1.动手实验:继承条件下的构造方法调用。
运行 TestInherits.java 示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent的另一个构造函数,注意这句调用代码是否是第一句,影响重大!
结论:
通过 super 调用基类构造方法,必须是子类构造方法中的第一个语句。
在继承时候,构造方法先调用上面的,再进行下面的。
packageyanzheng;
classGrandparent {
publicGrandparent() {
System.out.println("GrandParent Created.");
}
publicGrandparent(Stringstring) {
System.out.println("GrandParent Created.String:"+string);
}
}
classParentextendsGrandparent {
publicParent() {
//super("Hello.Grandparent.");
System.out.println("Parent Created");
//super("Hello.Grandparent.");
}
}
classChildextendsParent {
publicChild() {
System.out.println("Child Created");
}
}
public classTestInherits {
public static voidmain(Stringargs[]) {
Childc=newChild();
}
}
packageyanzheng;
classGrandparent {
publicGrandparent() {
System.out.println("GrandParent Created.");
}
publicGrandparent(Stringstring) {
System.out.println("GrandParent Created.String:"+string);
}
}
classParentextendsGrandparent {
publicParent() {
super("Hello.Grandparent.");
System.out.println("Parent Created");
//super("Hello.Grandparent.");
}
}
classChildextendsParent {
publicChild() {
System.out.println("Child Created");
}
}
public classTestInherits {
public static voidmain(Stringargs[]) {
Childc=newChild();
}
}
2.不允许继承的类
final class 类名{
}
(1).以final声明的方法不允许覆盖。
(2).以final声明的变量不允许更改。
(3).利用final,我们可以设计出一种特殊的“只读” 的“不可变类”。
何为“不可变的类”?
创建“不可变的类”的对象后,此对象的属性不可改,而且也无法从此类派生出新子类。String就是一个典型的例子。
不可变的“类”有何用?
&可以方便和安全地用于多线程环境中,
&访问它们可以不用加锁,因而能提供较高的性能。
不可变类的实例:Address.java
JDK中的实例:String
packageyanzheng;
//不允许继承的类 2015.11.10
public final classAddress
{
private finalStringdetail;
private finalStringpostCode;
//在构造方法里初始化两个实例属性
publicAddress()
{
this.detail="";
this.postCode="";
}
publicAddress(Stringdetail, StringpostCode)
{
this.detail=detail;
this.postCode=postCode;
}
//仅为两个实例属性提供getter方法
publicString getDetail()
{
return this.detail;
}
publicString getPostCode()
{
return this.postCode;
}
//重写equals方法,判断两个对象是否相等。
public booleanequals(Objectobj)
{
if(obj instanceofAddress)
{
Addressad= (Address)obj;
if(this.getDetail().equals(ad.getDetail()) &&this.getPostCode().equals(ad.getPostCode()))
{
return true;
}
}
return false;
}
public inthashCode()
{
return detail.hashCode() +postCode.hashCode();
}
}
3.参看ExplorationJDKSource.java示例
此示例中定义了一个类A,它没有任何成员:
class A { }
示例直接输出这个类所创建的对象
public static void main(String[] args) {
System.out.println(new A());
}
我们得到了一个奇特的运行结果:
A@1c5f743
后面这一串奇怪的字符其实是hash值。
前面示例中,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();
4.神奇的“+”号。
我们来看一段代码(示例Fruit.java ):注意最后一句,一个字串和一个对象“相加”,前页的示例中,Fruit类覆盖了Object类的toString方法。
结论:
在“+”运算中,当任何一个对象与一个String对象,连接时,会隐式地调用其toString()方法,默认情况下,此方法返回“类名 @ + hashCode”。为了返回有意义的信息,子类可以重写toString()方法。
5.接口知识。
面向对象语言为什么要引入“接口”?
Java不支持多继承,还可以实现多种功能。
Java中“接口”的语法特性。
定义一个接口,采用关键字interface,实现一个接口,采用关键字implements
接口的成员函数自动成为public的,数据成员自动成为 static和final的。
如果接口不声明为public的,则自动变为package。
一个类可以同时实现多个接口。
可以通过继承接口来扩充已有接口,并形成一个新的接口。
interface OneInterface {
void f1();
}
interface TwoInterface extends OneInterface {
void f2();
}
实现子接口的类,必须实现“父”“子”接口所定义的所有方法,才能被实例化(即new出一个对象)。
接口与抽象类的区别?
抽象类是一个不完全的类,而接口只是表明类应该具有哪些“外部”特征,不涉及任何实现细节。
接口基本上不具备继承的任何具体特点,它仅仅承诺了外界能够调用的方法。
一个类一次可以实现若干个接口,但一个类只能继承一个父类。