目录
前言:
为了实现代码的复用,让代码看起来不在冗余,将两个类相同的部分提取出来,用子类去继承父类就可以达到这样的效果。
多态字面意思就是多种状态,这是一种思想,在Java中理解:一个引用调用同一个方法,产生的行为不一样。
继承:
😯被继承的类称为,父类、基类或者超类。继承的类称为子类或者派生类。
示例
class Person { private int age; private String name; public void eat() { System.out.println(name + "在吃饭"); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Student1 extends Person { boolean sleep; public void fun() { System.out.println("在睡觉"); } } class Student2 extends Person { public void fun() { System.out.println("在学习"); } } public class Test7 { public static void main(String[] args) { Student1 stu1 = new Student1(); stu1.setAge(21); stu1.setName("www"); System.out.println(stu1.getName() + stu1.getAge()); } }
🐵继承使用关键子extends,继承之后子类可以复用父类的成员,但必须要保证子类中有特有的属性或者行为,否则就没有必要去继承了。
子类中访问父类成员变量:
变量名字不同
🎈在子类中就正常访问父类中的成员。
变量名字相同
🎈就近原则,优先访问子类中的成员变量,如果想要访问父类中的成员变量,需使用super关键字(后续介绍)。
子类中访问父类成员方法:
方法名字不同
😯和访问变量原则一样,直接访问就行。
方法名字相同
😯就近原则,优先访问子类中的成员方法,如果想要访问父类中的成员方法,也需super关键字。与变量的访问规则对比着去理解。
super关键字
😊super的存在,解决了在子类中访问父类中相同的成员变量和方法。
class Person3 { int a; int b; public void fun() { System.out.println("aaaa"); } } class Student3 extends Person3{ int a; int b; int c; public void fun() { System.out.println("bbbb"); } public void func() { a = 0; super.a = 10; super.b = 20; super.fun(); fun(); System.out.println(super.a); System.out.println(a); } } public class Test8 { public static void main(String[] args) { Student3 stu = new Student3(); stu.func(); } }
🎉 可以清楚的看见通过super访问到了父类中的成员变量和方法。
注意:super只能在非静态方法中使用,因为静态方法是属于类的,它不属于某一个对象。
子类构造方法
🪖首先不同类的构造方法肯定在不同类中,虽然子类继承了父类,但在用子类实例化对象时需要调用父类的构造方法,完成父类中成员的构造,接下来调用子类的构造方法,完成子类成员的构造。父类构造方法需先调用,然后再调用子类的构造方法。这是用子类实例化对象的必要条件。
示例
class Person8{ int age; String name; public Person8(String name) { age = 21; System.out.println(name + this.age); } } class Student8 extends Person8{ boolean sleep; public Student8() { //必须在第一句 super("www"); sleep = false; System.out.println(sleep); } } public class Test9 { public static void main(String[] args) { Student8 stu = new Student8(); } }
💎可以清楚看见先调用父类构造方法然后调用子类构造方法。
注意:
🎄如果父类定义了无参构造方法,或者没有定义构造方法,则在子类中构造方法第一句默认super()调用了父类构造方法。
🎄子类调用父类构造方法必须在子类构造方法中第一句。
🎄super和this不能同时存在,因为this调用构造方法也得放在第一句。
super和this
相同点:
🧢都是关键字。
🧢只能在非静态方法中使用,访问非静态成员变量或者方法。
🧢构造方法调用时只能在第一句,且不能同时存在。
不同点:
🎉this是当前对象的引用,super可以理解为是子类中所继承父类对象的引用。
🎉在非静态方法中,this用来访问本类的成员和方法,super用来访问父类的成员和方法。
🎉在构造方法中,this()调用本类构造方法,super()调用父类构造方法。
🎉子类构造方法中一定存在super(),程序员没有写编译器也会增加,但是this()不写则没有。
再谈初始化
😆继承关系下,静态代码块,示实例代码块,构造方法的执行顺序?
class Person8{ int age; String name; static { System.out.println("Person8的静态代码块"); } { System.out.println("person8的实例代码块"); } public Person8() { System.out.println("Person8的构造方法"); } } class Student8 extends Person8{ boolean sleep; static { System.out.println("Student8的静态代码块"); } { System.out.println("Student8的实例代码块"); } public Student8() { super(); System.out.println("Student8的构造代码块"); } } public class Test9 { public static void main(String[] args) { Student8 stu = new Student8(); System.out.println("------------------"); Student8 stu2 = new Student8(); } }
🤨首先执行父类静态代码块,然后执行子类静态代码块,接下来执行父类实例代码块和构造方法,再然后执行子类实例代码块和构造方法。父类和子类静态代码块执行一次,它们在类的加载时就执行了。实例代码块和构造方法只要实例化对象就会执行。
继承方式:
单继承
B ----> A B类继承A类
多继承
B ----> A ----> C A类继承C类,B类继承A类
不同类继承同一类
B ----> A C ----> A B类继承A类,C类也继承A类。
🐵我们不希望继承层次太过于复杂,继承层次一般不能超过三层。
注意:Java中不支持多继承,一个类同时继承多个类。
final关键字:
🤨final可以用来修饰成员变量,成员方法以及类。。
final修饰成员变量
🤨该变量为常量,不可以被修改,存储在JVM中的方法区。
final修饰成员方法
🤨该方法不能被重写。(多态中详解)
final修饰类
🤨该类不能被继承。
继承与组合
🪖继承是一种联结类与类的层次模型,子类继承父类,可以增加自己的功能,是一种is - a的关系。
🪖组合是在新类中产生现有类的对象,因此新的类是由现有类的对象所组成,可以复用现有类中的属性和方法。是一种has - a的关系。
示例
lass Person9 { int age; String name; public void fun() { name = "www"; System.out.println(name + "在学习"); } } class Student9 { Person9 stu = new Person9(); Person9[] stu2 = new Person9[10]; public Student9(int age, String name) { stu.age = age; stu.name = name; } public void fun() { System.out.println(stu.name + stu.age); stu.fun(); } } public class Test10 { public static void main(String[] args) { Student9 stu = new Student9(21, "www"); stu.fun(); } }
多态
😉多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。(可能不是很容易理解,下面会体现这种思想)
多态的条件(缺一不可)
😊必须在继承关系下。
😊子类必须要对父类的方法进行重写。
😊通过父类的引用调用重写的方法。
重写
😆这个是建立在继承关系上的,子类对继承父类的一些方法不是很满意,自己再去写一遍这个方法,这个就是实现多态的首要条件。
😆重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。核心代码重写。
方法重写的规则
😯形参列表不能改变,形参的顺序,个数,类型都不能改变。
😯返回值需相同,或者具有父子关系。
😯方法权限只能大于或者等于被重写的方法。
😯父类被static、private或者构造方法都不能重写。
注意:
🎈方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
🎈父类被private修饰的方法或者属性虽然被继承了,但是子类中是无法访问的。
示例
class Person6 { int age; String name; public void eat() { name = "www"; System.out.println(name + "吃米饭"); } } class Student6 extends Person6{ boolean sleep; public void eat() { name = "w"; System.out.println(name + "吃鱼"); } } class Student7 extends Person6 { public void eat() { name = "ww"; System.out.println(name + "吃肉"); } } public class Test11 { public static void fun(Person6 stu) { stu.eat(); } public static void main(String[] args) { Student6 stu1 = new Student6(); Student7 stu2 = new Student7(); fun(stu1); fun(stu2); } }
😯多态的体现:同一个引用(对象不同),调用同一个方法,产生的行为却不同。
静态绑定
🐵也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表方法重载。
动态绑定
🐵也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。(编译看左边,运行看右边)
向上转型
😉概念:创建一个子类对象,被父类所引用。
class W2 { int a; public void fun() { a = 10; System.out.println(a); } } class W3 extends W2 { int b; public void fun() { System.out.println("aaaaa"); } } public class Test12 { public static void main(String[] args) { //向上转型 W2 stu = new W3(); stu.fun(); //向下转型 //确保stu引用了W3这个对象 if(stu instanceof W3) { W3 stu2 = (W3) stu; //访问子类中特有成员 System.out.println(stu2.b); } } }
注意:向上转型,最后运行时原理就是动态绑定,让代码更加灵活。
向下转型
代码(W2父类 W3子类)
W2 stu = new W3();
W3 stu2 = (W3) stu;(向下转型)
🤨向上转型,只能访问子类中父类被子类重写的方法、被继承父类中的属性和父类中没有被子类重写的方法。无法访问子类中特有的方法或者属性。
🤨向下转型,可以访问子类中特有的方法或者属性。
注意:向下转型不是很安全,需保证其可以正常还原。
小结:
🐵理解是学习首当其冲进行的,需大量练习才能提高我们的代码能力,坚持下去会有不一样的收获。