动手动脑四
一、运行 TestInherits.java 示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent的另一个构造函数,注意这句调用代码是否是第一句,影响重大!
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(); } }
运行结果:
二、为什么子类的构造方法在运行之前,必须调用父类的构造方法?能不能反过来?为什么不能反过来?
构造函数是一种特殊的方法 。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。构造函数的功能主要用于在类的对象创建时定义初始化的状态。
所以说构造函数的作用,简单来说就是初始化,初始化一个新建的对象。而父类不拥有子类成员,故子类和父类不可以反过来调用。
三、参看ExplorationJDKSource.java示例,此示例中定义了一个类A,它没有任何成员:
class A { }
示例直接输出这个类所创建的对象
public static void main(String[] args) {
System.out.println(new A());
}
public class ExplorationJDKSource { /** * @param args */ public static void main(String[] args) { System.out.println(new A()); } } class A{}
public void println(Object x),这一方法内部调用了String类的valueOf方法。
valueOf方法内部又调用Object.toString方法:
public String toString() {
return getClass().getName() +"@" +
Integer.toHexString(hashCode());
}
hashCode方法是本地方法,由JVM设计者实现:
public native int hashCode();
四、 来看一段代码(示例Fruit.java ):
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()方法。
五、在子类中,若要调用父类中被覆盖的方法,可以使用super关键字。
class Parent { public Parent() { System.out.println("父类 1"); } public void show() { System.out.println("子类 2"); } } class Child extends Parent { int y; public Child() { System.out.println("父类 1"); } public void show() { super.show(); System.out.println("父类 3"); } } public class text { public static void main(String args[]) { Child c = new Child(); c.show(); } }
六、
1. 左边的程序运行结果是什么?
2. 你如何解释会得到这样的输出?
3. 计算机是不会出错的,之所以得到这样的运行结果也是有原因的,那么从这些运行结果中,你能总结出Java的哪些语法特性?
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); } }
输出结果:
当子类与父类拥有一样的方法时,并且让一个父类变量引用一个子类对象时,看自己的类型,对象时子类型则调用子类型方法,若对象是父类型则调用父类型方法。
如果子类与父类有相同的字段,则子类中的字段回代替或隐藏父类的字段,子类方法中访问的是子类中的字段,如果子类方法想访问父类中隐藏的同名字段,可以用super来访问
如果子类被当作父类使用,则通过子类访问的字段是父类的
七、为什么要用多态?它有什么好处?
使用多态最大的好处是:
当你要修改程序并扩充系统时,你需要修改的地方较少,对其它部分代码的影响较小!千万不要小看这两个“较”字!程序规模越大,其优势就越突出。