一:继承
1:什么是继承
继承就是将共性进行提取,实现代码的复用。
class Dog{ public String name; public int age; public void eat(){ System.out.println(name+"正在吃饭"); } public void fun(){ System.out.println(name+"汪汪叫"); } } class Cat{ public String name; public int age; public void eat(){ System.out.println(name+"正在吃饭"); } public void catchMouse(){ System.out.println(name+"捉老鼠"); } } public class Test { public static void main(String[] args) { } }
在上面的例子中,Dog类和Cat类都有这些成员变量和成员方法
private String name; private int age; public void eat(){ System.out.println(name+"正在吃饭"); }
那么我们就把这些成员变量和成员方法提取出来,构成一个父类,然后让Dog类和Cat类继承这个父类,而且Dog类和Cat类称为子类。
class Animal{ public String name; public int age; public void eat(){ System.out.println(name+"正在吃饭"); } } class Dog extends Animal{ public void fun(){ System.out.println(name+"汪汪叫"); } } class Cat extends Animal{ public void catchMouse(){ System.out.println(name+"捉老鼠"); } } public class Test { public static void main(String[] args) { } }
通过继承,子类将父类的成员变量和成员方法继承下来了
这样就提高了代码的复用性。
二:访问成员变量
在子类方法中或者通过子类对象访问成员变量时:
1:如果访问的成员变量子类中有,父类中没有,访问子类自己的成员变量。
class A{ public int a=10; public int b=20; public int c=30; // public int d=11; } class B extends A{ public int d=40; } public class Test { public static void main(String[] args) { B b=new B(); System.out.println(b.d);//子类中有,父类没有,访问子类自己的成员变量 } }
2:如果访问的成员变量子类中没有,则访问父类继承下来的,如果父类中也没有则编译错。
3:如果访问的成员变量与父类的成员变量同名,则优先访问自己的。
class A{ public int a=10; public int b=20; public int c=30; public int d=11; } class B extends A{ public int d=40; } public class Test { public static void main(String[] args) { B b=new B(); System.out.println("d="+b.d);//子类中有,父类中也有,优先访问自己的 } }
三:访问成员方法
在子类方法中或者通过子类对象访问成员方法时:
1:如果访问的成员放方法子类中有,父类中没有,访问子类自己的成员变量。
class A{ public int a=10; public int b=20; public int c=30; /* public void fun(){ System.out.println("哈哈"); }*/ public int d=11; } class B extends A{ public int d=40; public void fun(){ System.out.println("haha"); } } public class Test { public static void main(String[] args) { B b=new B(); b.fun();//子类中有,父类中没有,访问子类自己的成员方法 } }
2:如果访问的成员方法子类中没有,则访问父类继承下来的,如果父类中也没有则编译错。
class A{ public int a=10; public int b=20; public int c=30; public void fun(){ System.out.println("哈哈"); } public int d=11; } class B extends A{ public int d=40; /* public void fun(){ System.out.println("haha"); }*/ } public class Test { public static void main(String[] args) { B b=new B(); //b.fun();//子类中没有,父类中有,访问父类的成员方法 } }
访问的成员方法与父类的成员方法同名,则优先访问自己的。
class A{ public int a=10; public int b=20; public int c=30; public void fun(){ System.out.println("哈哈"); } public int d=11; } class B extends A{ public int d=40; public void fun(){ System.out.println("haha"); } } public class Test { public static void main(String[] args) { B b=new B(); b.fun();//子类中有,父类中有,优先访问子类的成员方法 } }
四:访问父类的成员变量和成员方法
1:当子类中没有要访问的成员变量或成员方法,而父类中有时,则访问父类的成员变量或成员方法。
2:当子类中有要访问的成员变量和成员方法时,我们通过super关键字来访问父类中的成员变量或成员方法。
super关键字
super关键字的作用:在子类方法中访问父类的成员
1:访问父类的成员变量
class A{ public int a=10; public int b=20; public int c=30; public void fun(){ System.out.println("哈哈"); } public int d=11; } class B extends A{ public int d=40; public void fun(){ System.out.println("haha"); } public void func(){ System.out.println(super.d);//访问父类的成员变量 } } public class Test { public static void main(String[] args) { B b=new B(); b.func();//11 } }
2:访问父类的成员方法
class A{ public int a=10; public int b=20; public int c=30; public void fun(){ System.out.println("哈哈"); } public int d=11; } class B extends A{ public int d=40; public void fun(){ System.out.println("haha"); } public void func(){ super.fun();//访问父类的成员方法 } } public class Test { public static void main(String[] args) { B b=new B(); b.func();//11 } }
注意:
1:super关键字只能在非静态成员方法中使用
2:在子类方法中,访问父类的成员变量和成员方法。
super和this关键字的区别
相同点:
1:super关键字和this关键字都只能在非静态的成员方法中使用,访问非静态的成员变量和成员方法
2:在构造方法中调用时,必须放在构造方法的
第一行,不能同时存在。
不同点:
1:this是当前对象的引用,访问当前对象的成员变量或成员方法,super访问父类的成员变量或成员方法;
2:在构造方法中,this()用来调用本类构造方法,super()用来调用父类的构造方法
3:构造方法中一定有super()的调用,而this()用户不写则没有
super.父类成员//访问父类的成员变量 super.父类成员方法//访问父类的成员方法 super() //访调用父类不带参数的构造方法 this.成员变量//访问当前对象的成员变量,优先访问子类的 this.成员方法//访问当前对象的成员方法,优先访问子类的 this() //调用不带参数的构造方法
五:子类的构造方法
在子类的构造方法中,没有写任何关于父类的构造方法,但在构造子类对象时,先执行父类的构造方法。
class A{ public int a=10; public int b=20; public int c=30; public int d=11; public A() { System.out.println("父类的构造方法"); } } class B extends A{ public int d=40; public B() { System.out.println("子类的构造方法"); } } public class Test { public static void main(String[] args) { B b=new B(); } }
这是因为子类对象中的成员是由两部分组成的,从父类继承下来的和子类新增加的部分。简单理解就是:父子父子,肯定是先有父,在有子,所以在创建子类对象的时候,先要调用父类的构造方法,将从父类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员变量初始化完整
注意:
1:当父类的构造方法不带参数,那么子类的构造方法中默认有super(),我们可以不写;但如果父类只有带参数的构造方法,那么在子类的构造方法中,必须写上super(参数1,参数2…)
2:子类构造方法中调用父类的构造方法,super()语句必须放在子类构造方法的第一行
3:因为super(),this()在构造方法中都只能出现在第一行,所有不能同时出现
六:代码块
class A{ public int a=10; public int b=20; public int c=30; public int d=11; static{ System.out.println("父类的静态代码块被执行了---"); } { System.out.println("父类的实例代码块被执行了---"); } public A() { System.out.println("父类的构造方法被执行了---"); } } class B extends A{ static{ System.out.println("子类的静态代码块被执行了---"); } { System.out.println("子类的实例代码块被执行了---"); } public int d=40; public B() { System.out.println("子类的构造方法被执行了---"); } } public class Test { public static void main(String[] args) { B b=new B(); System.out.println("--------------------"); B b1=new B(); } }
1:静态代码块先执行,并且只会执行一次,在类加载阶段完成。
2:当有对象创建的时候,才会执行实例代码块,然后再执行构造方法。
七:final关键字
1:final修饰普通变量或成员变量,表示该变量不能被修改;
2:final修饰类,表示该类不能被继承;
3:final修饰方法,表示该方法不能被重写
八:继承和组合
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。组合并没有涉及到特殊的语法
(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物
组合表示对象之间是has-a的关系,比如:汽车和其轮胎、发动机、方向盘、车载系统等的关系就应该是组合,因为汽车是有这些部件组成的。
// 轮胎类 class Tire{ // ... } // 发动机类 class Engine{ // ... } // 车载系统类 class VehicleSystem{ // ... } class Car{ private Tire tire; // 可以复用轮胎中的属性和方法 private Engine engine; // 可以复用发动机中的属性和方法 private VehicleSystem vs; // 可以复用车载系统中的属性和方法 // ... } // 奔驰是汽车 class Benz extend Car{ // 将汽车中包含的:轮胎、发送机、车载系统全部继承下来 }
组合和继承都可以实现代码复用,应该使用继承还是组合,需要根据应用场景来选择,一般建议:能用组合尽量用组合。