一、动手实验:继承条件下的构造方法调用
继承的语法:
class 子类名 extends 父类名
{
......
}
父类(parent class)和超类(super class)两者通常指直接上级
基类 (base class)通常指包括直接上级在内的“上级的上级”
子类自动拥有父类声明为public和protected的成员,这就是继承特性的体现之一。
继承条件下的构造方法调用
package test; class Grandparent { public Grandparent() { System.out.println("GrandParent Created."); } public Grandparent(String string) { System.out.println("GrandParent Created.String:" + string); } } class Parent extends Grandparent { public Parent() { //super("Hello.Grandparent."); System.out.println("Parent Created"); // super("Hello.Grandparent."); } } class Child extends Parent { public Child() { System.out.println("Child Created"); } } public class TestInherits { public static void main(String args[]) { Child c = new Child(); } }
该程序运行结果为:
GrandParent Created.
Parent Created
Child Created
通过运行我们可以发现,在主函数里面,我们构建了一个新的child对象,然后就自动调用了child里面的构造函数,又因为child继承了parent类,所以要先调用parent的构造函数,接着parent继承了grandparent类,所以要先调用grantparent的构造函数,因此调用的顺序为grantparent->parent->child;
如果要在子类里面调用父类的函数,super要写在前面
结论:
通过 super 调用基类构造方法,必须是子类构造方法中的第一个语句。
二、思考:为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?
构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。主要作用为:为对象数据成员开辟内存空间;完成对象数据成员的初始化。
如果在子类的构造方法运行之前不调用父类的构造方法的话,那么父类的对象不能初始化,在运行时自然会报错。
三、不可变的类
final class{
}
以final声明的方法不允许覆盖。
以final声明的变量不允许更改。
利用final,可以设计出一种特殊的“只读” 的“不可变类”。
作用:
可以方便和安全地用于多线程环境中, 访问它们可以不用加锁,因而能提供较高的性能。
四、方法覆盖
动手动脑
运行结果显示,方法覆盖时用子类的方法
(1)覆盖方法的允许访问范围不能小于原方法。 (2)覆盖方法所抛出的异常不能比原方法更多。 (3)声明为final方法不允许覆盖。 例如,Object的getClass()方法不能覆盖。 (4)不能覆盖静态方法。
五、判断对象是否可以转换
public class TestInstanceof { public static void main(String[] args) { //声明hello时使用Object类,则hello的编译类型是Object,Object是所有类的父类 //但hello变量的实际类型是String Object hello = "Hello"; //String是Object类的子类,所以返回true。 System.out.println("字符串是否是Object类的实例:" + (hello instanceof Object)); //返回true。 System.out.println("字符串是否是String类的实例:" + (hello instanceof String)); //返回false。 System.out.println("字符串是否是Math类的实例:" + (hello instanceof Math)); //String实现了Comparable接口,所以返回true。 System.out.println("字符串是否是Comparable接口的实例:" + (hello instanceof Comparable)); String a = "Hello"; //String类既不是Math类,也不是Math类的父类,所以下面代码编译无法通过 //System.out.println("字符串是否是Math类的实例:" + (a instanceof Math)); } }
六、转换语句
通过测试可以得知 d=m,d=c 两个语句不能运行,不能进行这样的转换
七、变态类
通过该测试可以发现 当父类与子类有相同的方法时,在哪个对象下就调用哪个
即当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。 这个特性实际上就是面向对象“多态”特性的具体表现。
如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。
如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。
如果子类被当作父类使用,则通过子类访问的字段是父类的!
牢记:在实际开发中,要避免在子类中定义与父类同名 的字段。不要自找麻烦!——但考试除外,考试 中出这种题还是可以的。
八、多态
package test; import java.util.Vector; public class zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); Vector<Animal> ans = new Vector<Animal>(); //饲养员小李喂养一只狮子 ans.add(new Lion()); //饲养员小李喂养十只猴子 for (int i = 0; i < 10; i++) { ans.add(new Monkey()); } //饲养员小李喂养5只鸽子 for (int i = 0; i < 5; i++) { ans.add(new Pigeon()); } f.feedAnimals(ans); } } class Feeder { public String name; Feeder(String name) { this.name = name; } public void feedAnimals(Vector<Animal> ans) { for (Animal an : ans) { an.eat(); } } } abstract class Animal { public abstract void eat(); } class Lion extends Animal { public void eat() { System.out.println("我不吃肉谁敢吃肉!"); } } class Monkey extends Animal { public void eat() { System.out.println("我什么都吃,尤其喜欢香蕉。"); } } class Pigeon extends Animal { public void eat() { System.out.println("我要减肥,所以每天只吃一点大米。"); } }
在编程中应用多态,可以使我们的代码具有更强的适用性。当需求变化时,多态特性可以帮助我们将需要改动的地方减少到最低限度
标签:上课,String,10.7,子类,class,思考,println,父类,public From: https://www.cnblogs.com/jiacheng-712/p/16782612.html