10.7动手动脑
package ter; 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(); } }
通过 super 调用基类构造方法,必须是子类构造方法中的第一个语句。
为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?
由于构造函数主要用来在创建对象时完成对对象属性的一些初始化等操作, 当创建对象时, 对象会自动调用它的构造函数。构造函数有以下三个方面的作用:给创建的对象建立一个标识符;为对象数据成员开辟内存空间;完成对象数据成员的初始化。由于子类要继承父类中的数据,所以也应该先对父类进行初始化。
public class ExplorationJDKSource { /** * @param args */ public static void main(String[] args) { System.out.println(new A()); } } class A{}
A中没有任何成员,其继承来自于Object
main方法中实际上调用的是public void println(Object x) 这一方法内部调用了String类的valueOf方法
valueOf方法内部又调用了Object.toString方法:
public String toString() {
return getClass().getName()+"@"+Interger.toHexString(hashCode());
}
hashCode方法是本地方法,由JVM设计者实现。
public class Fruit { public String toString() { return "Fruit toString."; } public static void main(String args[]) { Fruit f=new Fruit(); System.out.println("f="+f); System.out.println("f="+f.toString()); } }
在“+”运算中,当任何一个对象与一个String对象,连接时,会隐式地调用其toString()方法,默认情况下,此方法返回“类名 @ + hashCode”。为了返回有意义的信息,子类可以重写toString()方法。
toString()覆盖了原来的toString()方法。
class Mammal{} class Dog extends Mammal {} class Cat extends Mammal{} public class TestInstanceof { public static void main(String args[]) { Mammal m; Dog d=new Dog(); Cat c=new Cat(); m=d; //d=m; d=(Dog)m; //d=c; //c=(Cat)m; } }
子类对象可以直接赋给基类变量。
基类对象要赋给子类对象变量,必须执行类型转换,
其语法是:
子类对象变量=(子类名)基类对象名;
也不能乱转换。如果类型转换失败Java会抛出以下这种异常:ClassCastException。
public class ParentChildTest { public static void main(String[] args) { Parent parent=new Parent(); parent.printValue(); Child child=new Child(); child.printValue(); parent=child; parent.printValue(); parent.myValue++; parent.printValue(); ((Child)parent).myValue++; parent.printValue(); } } class Parent{ public int myValue=100; public void printValue() { System.out.println("Parent.printValue(),myValue="+myValue); } } class Child extends Parent{ public int myValue=200; public void printValue() { System.out.println("Child.printValue(),myValue="+myValue); } }
首先开头的代码
Parent parent=new Parent();
parent.printValue();
Child child=new Child();
child.printValue();//输出父类和子类各自的方法。
parent=child;
parent.printValue();//子类对象赋值给父类对象,父类中的方法被覆盖。所以输出200;
parent.myValue++;
parent.printValue();//此处myValue++后,仍然输出的时200,那这个变化应该时父类的myValue;
修改代码
再子类的输出后加上super.myValue,后面的输出结果为:
Parent.printValue(),myValue=100
Child.printValue(),myValue=200,100
Child.printValue(),myValue=200,100
Child.printValue(),myValue=200,101
Child.printValue(),myValue=201,101
可以得出:子类的同名方法和变量会覆盖父类的方法和变量;可将子类对象赋值给父类对象,但此时调用的函数是子类的函数,变量时父类的变量;可以将父类强制转化为子类,从而使用子类的变量。
接口:
定义一个接口,采用关键字interface,实现一个接口,采用关键字implements
接口的成员函数自动成为public的,数据成员自动成为static和final的。
如果接口不声明为public的,则自动变为package。
一个类可以同时实现多个接口。
接口实现:
接口类型 接口类型的变量=new 实现了接口的具体类型();
多态的作用:多态可以降低程序的耦合度,提高程序的扩展力。