5 java继承
继承是所有OOP语言和Java语言的组成部分。当你在创建一个类时,你总是在继承,因除非你已经明确的指出从那个类中继承,否则你就是在隐式的从java的标准根源类object进行继承。
利用继承,我们可以基于已存在的类构造一个新类。继承已存在的类就是复用(继承)这些类的方法和域。在此基础上,还可以在新类中添加一些新的方法和域,心满足新的设计需求。
子类(派生类、孩子类) extend 根类(基类、超类)
一个对象变量可以引用多种实际类型的现象被称做多态(polymorphism)。
在运行时能够自动地选择调用的适当方法的现象称为动态绑定。
在继承的层次中,从基个特定的类到其祖先的路径被称为该类的继承链。通常一个祖先可以拥有多个继承链。
5.1.1 多态
在java中,对象变量是多态的。子类的每个对象也是超类的对象,“is-a”规则表示是否应该将数据设计为继承关系,或者可以叫置换法则,即超类的对象都可以用子类对象置换。
5.1.2 动态绑定
既然对象变量是多态的,那怎么才能在运行中调用确定适合的对象中的方法呢?
首先,我们要弄清误用对象方法的执行过程。
①编译器查看对象的声明类型和方法名。如:调用a.chan(i),且a被声明为类A的对象,类A中包含多个名字为chan()参数不同的方法。然后,编译器将会一一列出所有可能被调用的候选方法。
②接下来,编译器执行重载解析过程,调用一个名字相同且参数类型相匹配的方法。
③当程序运行时,并且采用动态绑定调用方法时,虚拟机一定调用与a所引用对象的实际类型最合适的那个类的方法。假设a的实际类型是A,但是类A是类AA的子类,如果类A和类AA中都定义了chan()方法,那么就会调用类A中的方法,如果类A中没有定义chan(),那么将在类A的超类中寻找chan()方法。
④但是方法是final,static,private或者是构造器,那么编译器将可以准确的知道应该调用那个方法。这叫做静态绑定。
调用那个方法取决于隐式参数的实际类型,并且知运行时动态绑定。
5.1.3 阻止继承
不允许继承的类称为final类,final类中的方法无论有没有使用fianl都会自动成为fianl方法。
定义这个类的时候使用final修饰符声明。
final class A extends AA
{
…
}
类中的方法如果被声明为final,子类就不能覆盖这个final方法。换句话说,一个引用fianl类的对象变量,只能引用这个fianl类的对象,不能是其他类的对象。
5.1.4 内联
如果一个方法很短且没有被覆盖,编译器就能够对它进行优化,这个过程叫内联(inlining)。例如:
class A
{
int i;
int getI()
{
return i;
}
}
这个方法就会被优化为A.i,但是如果类A被继承且子类覆盖了这个方法,那么虚拟机就会取消内联。
5.1.5 强制类型转换
对象引用的转换仅需要用一对圆括号将目标类型类括起来,并放置到需要转换的对象引用前就可以了。
子类 var=(子类)根类; //会发生ClassCastException异常
进行对象的引用转换主要是为了暂时忽视对象的实际类型之后,使用对象的全部功能。注意以下两点:
①只能在继承层次内进行类型转换;
②在将超类转换为子类之前,应该使用instanceof进行检查。
a instanceof A //如果a是类A的对象返回true,否则返回false
建议少用类型转换和instanceof运算符。通过类型转换调整对象的类型并不总是一种好的做法,因为实现多态性的动态绑定机制能够自动调用相应的方法。
5.1.6 抽象类
从继承层次结构上看,位于最上层的根类更具有通用性――更抽象,从这种类继承出的子类也更加实用。
抽象类使用abstract关键字,可以包含具体的方法、数据或抽象方法。
使用sbatract 关键字定义的方法不需要具体实现。包含一个多个抽象方法的类本身必须被声明为抽象类。抽象方法充当点位的角色,它们的具体实现在子类中。子类实现有两种选择。
一、定义根类中的所有抽象方法,子类就不必被声明为abstract类;
二、定义部分抽象方法,子类必须被声明为abstract类。
抽象类不能被实例化,只能用于创建子类。但是可以定义一个抽象类的对象变量来引用它的非抽象子类。
5.1.7 受保护的访问
①仅对本类可见――private
②对所有类都可见――public
③对本类和子类都可见――protected
④本包可见――缺省
5.2 Object:java所有类的根类
类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。在定义类的时候没有明确指定超类默认是从Object继承。
object类型的变量引用任何类型的对象,但是object类型的变量只能对它们作一般的操作,要对它们进行特定的操作,还需要使用原始类型。
5.2.1 equals方法
Object类中的equals方法用于检测一个对象是否等于另外一个对象,即判断两个对象是否具有相同的引用。如果两个对象具有两个相同的引用,它们一定是相等的。其实对于大多数类来说,equals没有多大实际意义,如PrintStream类。但是可以用equals检测两个对象的状态是不是相同。
只有两个对象属于同一个类时,才胡可能相等。因此,在子类中定义queals方法时,首先要调用超类的equals方法(super.equsla(OtherObject))进行测试