6.1
6.2 类的继承
在派生类中包含其基类的成员,以便它们在派生类中可以被访问的过程称为类的继承。
一个基类的继承成员可以在其派生类中被访问。如果一个基类的成员不能在其派生类中被访问,那么它就不是派生类的继承成员,但是基类的非继承成员仍然形成了派生类对象的一部分。
一个派生类的继承成员是该类的完全的成员,并且可以被该类的任何方法自由访问,
6.2.1 继承数据成员
类本身可以声明为public,这样该类就可以在任何地方被任何包访问。一个没有声明为public的类只能通过相同包中的类访问。
在与基类相同的包中定义的子类继除基类的private数据成员之外的所有东西。如果在包含基类的包外定义子类,不继承private成员,不继承没有指定访问属性的数据成员。
1.protected会阻止该包外的类的访问,但是不会限制继承。
2.没有访问说明符的类成员只能被相同包中的类访问,并且阻止另一个包中定义的子类的继承。
如果派生类的数据成员名称和基类数据成员的名称相同,则基类中的成员被会隐藏起来。为了引用继承的基类成员,必须用关键字super来限定它。
即:可以通过super限定成员名来访问基类的隐藏成员。
对基类的构造函数的调用必须是派生类的构造函数的第一条语句
6.2.2 继承方法(注意派生类和派生类对象)
继承是指在派生类中可以访问基类哪些成员,而不是指在派生类的对象中存在哪些基类的成员。子类对象将包含所有原始的基类的成员,
虽然基类的构造函数无法在派生类中被继承,但是仍然可以调用它们来初始化基类成员。
6.2.3覆盖基类的方法
派生类中该方法的访问属性可以与基类方法的相同,或者限制更少一些,但是不能有更多的限制。
当采用这种方法定义一个新版本的基类方法时,派生类的对象将调用该派生类的方法,而不是从基类继承的方法,这样派生类的方法将覆盖其基类中的方法。
但基类的方法仍然能以super指定基类方法来调用。
6.4 多态
一个特定类型的变量,可以引用不同类型的对象,并且自动调用该变量引用的特定类型对象的方法.(听起来应该是基类类型变量,引用派生类对象)
这样,就使得一个方法的调用根据该调用所作用到的不同对象类型而响应不同的操作.
基类指针调用子类对象的方法,且此方法同时定义在基类和子类中.
Dog[bark()] -- { Spaniel[bark()] | Chihuahua[bark()] | Collie[bark()] }
派生类方法的返回对象类型是基类类型的子集,即使用返回对象类型不相同,也可以获得多态行为
下面总结一个在使用多态时需要满足的条件:
1.派生类对象的方法调用必须通过一个基类类型的变量进行.
2.调用的方法必须在派生类中被定义.
3.调用的方法也必须被声明为基类的一个成员.
4.基类和派生类中对应方法签名必须相同。 (有时候基类定义的方法什么都不做,只定义一个空方法,如Animal,是抽象的概念,请看抽象类)
5.基类和派生类的方法的返回对象类型必须相同或者返回对象类型必须是协变的。
6.派生类的方法的访问说明符不能比基类有更多的限制。
当使用一个基类变量调用一个方法时,多态会根据存储的对象的类型而不是变量的类型来选择要调用的方法。
由于基类的变量可以存储任何派生类型的对象的引用,因此直接程序执行的时候才知道存储的对象的类型。
注意,多态只作用于方法,而不会作用于数据成员。当该变量引用一个Spaniel类型的对象时,也只能用它来访问Spaniel对象中属于Dog部分的数据成员。
多态的使用
Animal theAnimal = new Dog("Rover");
6.5 多级继承
6.6 抽象类 abstract
声明一个或多个方法,但是没有定义这些方法。
一切为了利用多态.
public abstract class Animal{
public abstract void sound();
... ...
}
我们不能把一个抽象类中的对象实例化,但是可以声明抽象类型的变量
Animal thePet = null; 我们可以用这个变量存储子类的对象。
6.7 通用超类
Object成员都是方法
toString() equals()同一个对象 getClass()返回一个Class类型的对象,以识别当前对象所属的类。 hashCode() notify() 该方法用于唤醒一个与当前对象关联的线程。 notifyAll()唤醒所有与当前对象关联的线程。 wait() 该方法将导致一个线程等待当前对象中发生的变化。
clone() finalize()该方法在销毁对象时被调用,用于清理工作。
6.7.2
假设pet是Animal类型的变量,它可能包含对Dog,Cat,Duck甚至Spaniel类型对象的引用。
Class objectType = pet.getClass();//Get the class type
System.out.println(objectType.getName);//output the class name
如果pet引用的是一个Duck对象,则会输出Duck
Class对象主要由Java虚拟机使用,而且没有公共的构造函数。如果添加.class作为任何类、接口或者基本类型的后缀,那么就拥有了该类的Class对象引用。
每个类或者接口类型都只有一个Class对象。
if(pet.getClass() == Duck.class){
System.out.println("it is a duck!");
}
注意:类Class不是一个普通类,它是泛型的一个例子。
6.7.3 对象的复制
从Object继承的方法clone()通过生成一个与当前对象类型相同的新的对象来实现对象的复制,并且把新的对象中每个成员域都设置成与当前对象的对应成员域相同的值。
当原始对象的数据成员引用一个类对象时,这个类对象在克隆的时候并不被复制,只是把引用从原始对象的成员域中复制到克隆到对象的成员域中。
这种情况下,现在的克隆对象和原始对象都可以通过它们对应的数据成员修改所引用的共享对象,同时却没意识到这种修改。
public Object clone() throws CloneNotSupportedException{
PetDog pet = (PetDog)super.clone();
pet.petFlea = (Flea)petFlea.clone(); 引用的对象也克隆一下。
return pet;
}
6.8 接收可变实参的方法
Object ...args
public static void printAll(Object ... args){
for(Object arg:args){
System.out.print(" ", arg);
}
}
限制可变实参表中的类型
public static double average(Double ... args){
}
6.9 对象的类型强制转换
6.13 接口
接口中定义的是抽象方法.
声明方法的接口定义了一组标准操作.
6.13.2 接口的应用 1.接口和多态
不能生成一个接口类型的对象,但能生成一个接口类型的变量,用于存储实现接口的任何任何类型对象的引用.
也就意味着,可以使用这个变量来多态调用在接口中声明的方法.
6.13.6 接口定义中的嵌套类
可以将类的定义放在接口的定义中。对于接口来讲,该类就是内部类。一个接口的内部类在默认情况下将是static和public类型
interface Port{
class Info{
}
}
Port.Info info = new Port.Info();
实现接口的类与该接口的内部类没有直接联系,即它只需要实现接口声明的方法,但是它很可能会使用内部类的对象。
6.14匿名类