1、继承(inheritance)
一旦你已经创建了一个定义了对象一般属性的超类,该超类可以被继承以生成特殊用途的类。每一个子类只增添它自己独特的属性。这是继承的本质。Java 不支持多超类的继承。
超类变量可以引用子类对象(这个具体有什么作用,有待补充)
2、重载(overload)
a)、方法重载要求参数类型或个数必须不一致
b)、对返回类型无限制
c)、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
3、覆盖(override)
从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
a)、要求父类和子类的方法名称、参数相同
b)、子类中覆盖的方法的访问权限要>=父类中的方法的访问权限(defautl、protected、public)。
c)、子类中覆盖的方法的返回值必须和父类中的方法的返回一致;
d)、子类中覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
e)、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
f)、静态方法和最终方法(带关键字final的方法)不能被覆盖(“实例方法被覆盖,静态方法被隐藏”)
g)、抽象方法必须在具体类中被覆盖
4、多态(polymorphism)
多态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。
多态的通常含义是能够呈现出多种不同的形式或形态,即一个特定类型的变量可以用于引用不同类型的对象,并且自动调用该变量引用的特定类型对象的方法,这样就使得一个方法的调用根据该调用所作用到的不同对象类型而响应不同的操作。
下面就继承和接口实现两方面谈谈java运行时多态性的实现。
(1)、通过继承中超类对象引用变量引用子类对象来实现
//定义超类superA
class superA
{
void callfun()
{
System.out.println("call superA");
}
}
// 定义superA的子类subB
class subB extends superA
{
void callfun()
{
System.out.println(call subB");
}
}
// 定义superA的子类subC
class subC extends superA
{
void callfun()
{
System.out.println("call subC");
}
}
class mytest
{
public static void main(String[] args)
{
superA a;
subB b = new subB();
subC c = new subC();
a=b;
a.callfun(); (1)
a=c;
a.callfun(); (2)
}
}
运行结果:
call subB
call subC
上述代码中subB和subC是超类superA的子类,我们在类mytest中声明了3个引用变量a, b, c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。也许有人会问:“为什么(1)和(2)不输出:call superA”。java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
所以,不要被上例中(1)和(2)所迷惑,虽然写成a.callfun(),但是由于(1)中的a被b赋值,指向了子类subB的一个实例,因而(1)所调用的callfun()实际上是子类subB的成员方法callfun(),它覆盖了超类superA的成员方法callfun();同样(2)调用的是子类subC的成员方法callfun()。
另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性。具体的实现方法同上例。
不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,否则子类必须被abstract修饰符修饰,当然也就不能被实例化了。