动手实验1:
运行 TestInherits.java 示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent的另一个构造函数,注意这句调用代码是否是第一句,影响重大!
1)输出结果:
2)结论:通过 super 调用基类构造方法,必须是子类构造方法中的第一个语句。
动手实验2:
参看ExplorationJDKSource.java示例
此示例中定义了一个类A,它没有任何成员:
class A { }
示例直接输出这个类所创建的对象
public static void main(String[] args) {
System.out.println(new A());
}
1)输出结果:
2)结论:前面示例中,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();
动手实验3:
我们来看一段代码(示例Fruit.java ):
注意最后一句,一个字串和一个对象“相加”,得到以下结果:
结论:在“+”运算中,当任何一个对象与一个String对象,连接时,会隐式地调用其toString()方法,默认情况下,此方法返回“类名 @ + hashCode”。为了返回有意义的信息,子类可以重写toString()方法。
动手实验4:面向对象语言为什么要引入“接口”?
先来看一个现实生活中的实例:
鸭子是一种鸟,会游泳,
同时又是一种食物。
如何使用面向对象的思想,为上述场景建立一个 系统模型(建模)?
什么叫“建立一个系统模型”?
简单地说,就是”你打算设计哪些类来“仿真” 鸭子这一现实事物?
因为“鸭子是一种(IS_A)鸟,又是一种(IS_A)食物”,所以我们可以创建三个类,Bird代表鸟,Food代表食物,Duck代表鸭子,让Duck派生自Bird和Food。
这个方案存在的问题:
(1)Java不支持多继承
(2)“会游泳”这个方法放在哪个类中?放到Bird中似乎并不合适,因为只有部分鸟类会游泳。放到Duck中也不好,因为会游泳的水鸟不止鸭子一种
能否把“会游泳”、“能被吃”这种特性独立出来作为一种“可选项”,可以被“附加”到具体对象上?
这样一来,水鸟可以拥有“会游泳”这个特性,其它种类的鸟就不具备这个特性,但它可能有其他的特性。
在面向对象世界中,可以使用“接口(interface)”来抽象对象的行为特性。
public interface IFood {
public void Cook();
}
public class Duck extends Bird implements IFood{
public void Cook() {
……
}
……
}
Java中“接口”的语法特性
定义一个接口,采用关键字interface,实现一个接口,采用关键字implements
接口的成员函数自动成为public的,数据成员自动成为
static和final的。
如果接口不声明为public的,则自动变为package。
一个类可以同时实现多个接口。
接口的使用:
IFood f = new Duck();
接口类型 接口类型的变量=new 实现了接口的具体类型()
可以通过继承接口来扩充已有接口,并形成一个新的接口。
接口的补充:
interface OneInterface {
void f1();
}
interface TwoInterface extends OneInterface {
void f2();
}
实现子接口的类,必须实现“父”“子”接口所定义的所有方法,才能被实例化(即new出一个对象)。
利用接口定义常量
public interface ArrayBound {
public static final int LOWBOUND=1;
public static final int UPBOUND=100;
}
只要一个类声明实现了这个接口,就可以直接使用这些常量名
在实际开发中,这种编程方式非常常见。
注意:定义在接口中的常量必须被初始化。
接口与抽象类的区别:
抽象类是一个不完全的类,而接口只是表明类应该具有哪些“外部”特征,不涉及任何实现细节。
接口基本上不具备继承的任何具体特点,它仅仅承诺了外界能够调用的方法。
一个类一次可以实现若干个接口,但一个类只能继承一个父类。