day21
思考:构造方法能否实现重写
引申出来三个问题:
一个类是否可以继承它自身
一个类是否可以继承它的同名类
构造方法能否实现重写
结论:
一个类如果继承了自己,会出现递归构造调用
一个类可以继承它的同名类,必须要写其完整的全路径,而且注意不能导入该父类
由于构造方法无法实现继承,则构造方法无法实现重写
package com.saas.oo; public class MyClass { }package com.saas.oo2; //import com.saas.oo.MyClass; /** * 一个类不能继承它自身,否则会出现递归构造调用 * 一个类可以继承它的同名类,继承它的同名类时必须要指定其同名类的完整路径,不能导入同名类 * 构造方法不能实现继承,所以构造方法无法实现重写 */ public class MyClass extends com.saas.oo.MyClass{ }
思考:构造子类对象时一定会调用父类构造器吗?
package com.saas.oo2; public class Father { public Father(){ System.out.println("this is Father Constructor"); } }package com.saas.oo2; public class Son extends Father{ String name; int age; /** * 在一个类的构造方法中,如果没有显式地调用其他构造器,则Java虚拟机会默认调用super()来调用父类的无参构造器 * 如果显式地调用了某个构造器,则Java虚拟机不再调用父类的无参构造 * 在构造方法内部,如果要调用其他构造方法,则该调用必须写在方法的第一行 */ public Son(){ this(18); System.out.println("this is son Constructor without params"); } public Son(int age){ this(18, "wumingshi"); System.out.println("this is son Constructor with age"); } public Son(int age, String name){ super(); System.out.println("this is son Constructor with age and name"); } }package com.saas.oo2; public class Son extends Father{ String name; int age; /** * 在一个类的构造方法中,如果没有显式地调用其他构造器,则Java虚拟机会默认调用super()来调用父类的无参构造器 * 如果显式地调用了某个构造器,则Java虚拟机不再调用父类的无参构造 * 在构造方法内部,如果要调用其他构造方法,则该调用必须写在方法的第一行 */ public Son(){ this(18); System.out.println("this is son Constructor without params"); } public Son(int age){ this(18, "wumingshi"); System.out.println("this is son Constructor with age"); } public Son(int age, String name){ super(); System.out.println("this is son Constructor with age and name"); } }通过Son类中构造器的调用我们发现:
即使在子类的内部构造方法中调用了当前类的其他构造器,但是总有一个方法会调用其父类的构造器
所以在创建任何子类对象时,都会直接或者间接调用父类的构造器
继承中的对象创建
package com.saas.oo3; public class Father { int a; int b; public void m1(){ System.out.println("this is m1 in Father"); } }package com.saas.oo3; import com.saas.oo2.Father; /** * 在具有继承关系的对象创建中,构建子类对象会先执行父类的构造器,但是不一定会创建父类对象 * 由父类的共性内容,叠加子类的独有内容,组合成完整的子类对象 * 所以Son所持有的成员属性和方法有: * int a * int b * int c * m1() * m2() */ public class Son extends Father { int c; public void m2(){ System.out.println("this is m2 in Son"); } }package com.saas.oo3; public class Test { public static void main(String[] args) { new Son(); } }通过new关键字创建的Son对象,只会创建一个Son类型的对象,并不会创建Father的对象本身,只是借助Father构造器来初始化该Son对象本身
继承后的对象创建
package com.saas.oo4; /** *如果直接new C()的构造器,则分别会执行A的构造器,B的构造器,以及C自己的构造器 * super()表示调用父类无参构造方法 * 如果没有显式的书写,隐式的存在于子类构造器的第一行 * 所以最终的运行结果时 * A() * B() * C() * 但是注意,虽然分别走了A和B的构造器,但是并不会真正创建A和B对象,走A和B的构造器的目的时为了初始化C对象 */ public class Test { public static void main(String[] args) { new C(); } }
继承小结
super关键字的第一种用法:
在子类中使用“super.”的形式访问父类的属性和方法
例如: super.money, super.test(),分别调用父类中的money属性和test()方法
super的第二种用法:
在子类的构造器第一行,使用super()或者super(实参),调用父类的构造方法
注意:
如果子类构造方法中,没有显式的定义super()或者super(形参),则默认提供super();
在构造方法内部,调用其他的构造方法,该调用代码必须写在第一行
同一个子类构造方法中,super()、this()不可能同时存在
多态
概念
一个事物的多种形态
生活中:不同人物角色看待同一个对象的视角不同,关注点也不相同
生活中的多态是指“客观事物在人脑中的主观反应”
主观意识上的类别与客观存在的对象之间具有“is a”的关系时,即形成多态
程序中的多态:
概念:父类引用指向子类对象,从而产生多种形态
package com.saas.oo5; public class Animal { String breed; int age; public void eat(){ System.out.println("eatting..."); } public void sleep(){ System.out.println("sleeping..."); System.out.println("zzzzzZZZZZZZ"); } }package com.saas.oo5; public class Sheep extends Animal{ public void miemie(){ } }package com.saas.oo5; public class Wolf extends Animal{ }package com.saas.oo5; public class Test { public static void main(String[] args) { Animal s = new Sheep(); Animal w = new Wolf(); s.age = 4; s.breed = "mianyang"; System.out.println(s.age); System.out.println(s.breed); s.eat(); s.sleep(); //s.miemie(); // miemie()是Sheep这个类所特有的方法,不能通过Animal类型的s来调用 System.out.println("================"); } }二者具有直接或者间接的继承关系时,父类引用指向子类对象,即形成多态
父类引用仅可调用父类所声明的属性和方法,不可调用子类独有的属性和方法
多态中的方法重写
思考:如果子类中重写了父类的方法,以父类类型的引用调用此方法时,优先执行的是父类的方法还是子类中的方法
实际运行过程中,依照重写的原则,如果子类重写了父类中的方法,执行子类中重写后的方法,否则如果没有重写,完全继承的话,则执行的是父类中的方法