一、继承条件下的构造方法调用
package example; 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 调用基类构造方法,必须是子类构造方法中的第一个语句。
二、
package example; public class ExplorationJDKSource { /** * @param args */ public static void main(String[] args) { System.out.println(new A()); } } class A{}
前面示例中,main方法实际上调用的是: 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();
三、神奇的“+”号
package example; 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关键字。
public class We { public static void main(String[] args) { // TODO Auto-generated method stub Son s=new Son(); s.Cs(); } } class Parent{ void Cs(){ System.out.println("父类方法"); } } class Son extends Parent{ void Cs(){ super.Cs(); System.out.println("子类方法"); } }
Java“方法覆盖”的语法规则:
(1)覆盖方法的允许访问范围不能小于原方法。
(2)覆盖方法所抛出的异常不能比原方法更多。
(3)声明为final方法不允许覆盖。 例如,Object的getClass()方法不能覆盖。
(4)不能覆盖静态方法。
五、
package example; 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关键字来访问它。
如果子类被当作父类使用,则通过子类访问的字段是父类的!
牢记:在实际开发中,要避免在子类中定义与父类同名 的字段。不要自找麻烦!——但考试除外,考试中出这种题还是可以的。
六、动物园
package zoo1; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); // 饲养员小李喂养一只狮子 f.feedLion(new Lion()); // 饲养员小李喂养十只猴子 for (int i = 0; i < 10; i++) { f.feedMonkey(new Monkey()); } // 饲养员小李喂养5只鸽子 for (int i = 0; i < 5; i++) { f.feedPigeon(new Pigeon()); } } }
简化Feeder类:Feeder类的三个喂养方法现在可以合并为一个feedAnimal()方法,注意它接收一个类型为Animal参数,而不是三个具体的动物类型。 依据多态特性,此方法将可以接收任何一个派生自Animal类的子类对象
package zoo2; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); //饲养员小李喂养一只狮子 f.feedAnimal(new Lion()); //饲养员小李喂养十只猴子 for (int i = 0; i < 10; i++) { f.feedAnimal(new Monkey()); } //饲养员小李喂养5只鸽子 for (int i = 0; i < 5; i++) { f.feedAnimal(new Pigeon()); } } }
修改feedAnimals方法,让它接收一个Animal数组。
现在只需要一句代码,就 可以模拟出喂养一批各种 各样的动物的过程。
package zoo3; public class Zoo { public static void main(String args[]) { Feeder f = new Feeder("小李"); Animal[] ans = new Animal[16]; //饲养员小李喂养一只狮子 ans[0] = new Lion(); //饲养员小李喂养十只猴子 for (int i = 0; i < 10; i++) { ans[1 + i] = new Monkey(); } //饲养员小李喂养5只鸽子 for (int i = 0; i < 5; i++) { ans[11 + i] = new Pigeon(); } f.feedAnimals(ans); } } class Feeder { public String name; Feeder(String name) { this.name = name; } public void feedAnimals(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("我要减肥,所以每天只吃一点大米。"); } }
Feeder类的feedAnimals()方法接收的是一个Animal数组,这有一个限制,就是只能创建固定个数的数组,无法动态地增减动物个数。
修改feedAnimals方法,让其接收一个元素数目可变的对象容器。
package zoo4; 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("我要减肥,所以每天只吃一点大米。"); } }
从这个示例中可以看到,通过在编程中应用多态,可以使我们的代码具有更强的适用性。当需求变化时,多态特性可以帮助我们将需要改动的地方减少到最低限度。
多态编程有两种主要形式: (1)继承多态:示例程序使用的方法 (2)接口多态:使用接口代替抽象基类,这个任务留为作业。