维导图:
1.继承的语法:
- 面向对象的思想中提出了继承的概念,专门用来进行共性提取,实现代码的复用。
- 继承作用就是实现代码复用,用来实现多态。
- 现有1个Dog类和1个Cat类都继承于Animal类,则这个Dog和Cat就称为子类或派生类;而Animal类称为父类、基类或超类。语法格式为:class Dog extends Animal;需要借助关键字extends。
- 子类会继承父类的成员变量和成员方法。
- 对于子类来说,成员变量和成员方法的访问必须遵循就近原则,自己有优先访问自己的,没有再去父类中找,如果父类也没有则就会编译出错。
- 子类中的成员变量如果和父类成员变量相同,但是还是想访问父类的成员变量需要用到关键字super。
- 子类中的成员方法如果和父类成员方法相同,但是还是想访问父类的成员变量也需要用到关键字super;另外如果父类和子类的方法构成了重载,根据调用的方法和传递的参数来选择合适的方法访问也可以访问到父类的成员方法,方法的重载不是必须在一个类中!
- final关键字修饰变量表示常量不能被修改,修饰类表示不能被继承。
2.super关键字:
- super代表着子类从父类继承过来的这一块空间的地址!
- super关键字的作用是在子类方法中访问父类的成员变量和方法,只能在非静态方法中使用。
- 在子类对象构造时,要先调用父类构造方法,然后才能执行子类构造方法。在子类构造前先帮助父类构建好,然后再构造子类自己的。
- 若父类显式定义无参或者默认的构造方法,则在子类构造方法中会默认调用父类构造方法:super();必须是子类构造方法的第一行。
- 若父类的构造方法中含有参数,则子类构造方法中需要用户使用合理的构造方法来调用父类的,看下面代码:
-
public class Animal {
-
public int age;
-
public String name;
-
public Animal(String name,int age){
-
this.name = name;
-
this.age = age;
-
}
-
}
-
class Cat extends Animal{
-
public int length;
-
public Cat(String name,int age,int length){
-
super(name,age);//显式的调用父类的构造方法
-
// 来初始化此时子类继承过来的父类的属性
-
this.length = length;
-
}
-
}
-
- super();只能在子类构造方法中出现一次,调用构造方法时不能和this();同时使用。super.属性:访问父类的成员变量,super.方法:访问父类的成员方法,super () :调用父类的构造方法。
- super 和 this 的异同:
相同点: 1.都是关键字。 2.都只能在非静态的方法中使用用来访问非静态的成员变量和成员方法。 3.在构造方法调用的时候必须是构造方法中的第一条语句。 不同点: 1.this是当前对象的引用,就是实例化的那个对象 而super是子类从父类继承下来的那部分成员的引用。 2.this用来访问当前类中的变量和方法 而super用来访问父类继承下来的变量和方法。 3.在构造方法中this();调用自己类的构造方法 而super();调用父类的构造方法二者的调用不能同时在构造方法中出现。 4.构造方法中一定会有super();的调用 而this()不写则没有。
3.涉及继承的初始化:
- 在没有设计继承的时候,代码块的执行顺序是:静态代码块>实例代码块>构造方法,并且静态代码块只能执行1次。
- 看段代码:
-
public class Animal {
-
public String name;
-
public int age;
-
public Animal(String name,int age){
-
this.name = name;
-
this.age = age;
-
System.out.println("父类的构造方法执行l");
-
}
-
static
-
{
-
System.out.println("父类的静态代码块执行了!");
-
}
-
{
-
System.out.println("父类的实例代码块执行了!");
-
}
-
}
-
class Dog extends Animal{
-
public Dog(String name,int age){
-
super(name, age);
-
System.out.println("子类的构造方法执行了!");
-
}
-
static
-
{
-
System.out.println("子类的静态代码块执行了!");
-
}
-
{
-
System.out.println("子类的实例代码块执行了!");
-
}
-
}
执行结果: 父类的静态代码块执行了! 子类的静态代码块执行了! 父类的实例代码块执行了! 父类的构造方法执行了! 子类的实例代码块执行了! 子类的构造方法执行了!
-
- 由上述代码,我们做出总结:最先执行的是父类的静态代码块,再到子类的静态代码块。静态的代码块总是最先被执行并且只会执行一次,不会因为再创建1个对象而再次执行静态代码块。
- 接着就执行父类的实例代码块,父类的构造方法,执行完父类才会去执行子类的实例代码块,子类的构造方法。
4.多态的实现:
- 多态是一种思想,同一件事情发生在不同对象身上就会产生不同的结果。在代码运行时传递不同类的对象时会调用对应类中的方法,这就是多态的体现。比如说对于吃饭而言,猫吃的就是猫粮,小狗吃的是狗粮......
- 多态必须要在继承的体系下才能实现,要实现多态就必须要满足3个条件:
1.完成向上转型 2.完成方法的重写 3.通过父类的引用调用重写的方法
- 满足方法的重写 (override) 也称覆盖,需要的6个条件;重点就是外表不变,核心内容重写!
1.方法名相同 2.方法的参数列表相同(参数个数、参数顺序、参数类型) 3.方法的返回值相同 4.static修饰的方法不能被重写 5.private修饰的方法也不能被重写 6.子类的访问修饰限定符要大于等于父类的访问修饰限定符
- 例如:Animal animal = new Dog( );就发生了向上转型,实际上就是创建了1个子类对象,将其当作父类对象来使用。向上转型的4个方法:
-
//Animal是父类,Dog继承了Animal
-
public class Main {
-
public static void func(Animal animal){
-
}
-
public static Animal func11(){
-
return new Dog("丫丫",3);
-
}
-
public static void main(String[] args) {
-
//向上转型:1
-
Dog dog = new Dog("狗子",6);
-
Animal animal1 = dog;
-
//向上转型:2
-
Animal animal2 = new Dog("狗子",7);
-
/*animal2.length;不能访问Dog中的成员*/
-
//向上转型:3
-
func(new Dog("花花",4));
-
//向上转型:4
-
func11();
-
}
-
}
-
- 例如:Animal animal = new Dog( );此时父类引用 引用了子类对象,animal不能访问到Dog中的成员。
- 动态绑定是父类引用引用了子类对象,通过父类的引用调用这个重写的方法,此时就发生了动态绑定。编译期间调用的还是父类自己的方法,但是运行时程序发生了动态绑定就调用了子类重写的方法。
多态思想的体现: Animal animal1 = new Animal(); animal1.eat();null在吃饭 //没有传name,所以name默认为null ============================== Animal animal2 = new Dog(); animal2.eat();小狗在吃骨头 //发生了动态绑定 ============================== Animal animal3 = new Cat(); animal3.eat();小猫在吃鱼 //发生了动态绑定