Java/继承

维基教科书,自由的教学读本

作为面向对象的编程语言,Java也提供了类的继承机制。利用继承机制,新建的类可以建立在原有类的基础之上,使用或者重写原有类的成员方法,访问原有类的成员变量。我们称新类为原有类子类,而原有类为新类的父类(superclass)。如果类A是类B的父类,而类B是类C的父类,我们也称C是A的子类,类C是从类A继承而来的。在Java中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,一个父类可以有多个子类。所有Java的类均是由java.lang.Object类继承而来的,所以Object是所有类的祖先类,而除了Object外,所有类必须有一个父类。通过extends关键字可以申明一个类是继承另外一个类而来的,一般形式如下:

类的继承格式

class 父类 {
}
class 子类 extends 父类 {
}

重写

如果一个类从它的父类继承了一个方法,如果这个方法没有被标记为 final ,就可以对这个方法进行重写。

重写的好处是:能够定义特定于子类类型的行为,这意味着子类能够基于要求来实现父类的方法。

在面向对象编程中, overriding 意味着去重写父类已经存在的方法。

示例:

class Animal{
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal{
public void move(){
System.out.println("Dogs can walk and run");
}
}
public class Test{
public static void main(String args[]){
Animal a = new Animal(); 
Animal b = new Dog(); 
a.move();
b.move();
}
}

结果:

Animals can move
Dogs can walk and run

在上面的例子中,你可以看到尽管 b 是 Animal 类型,但它运行了 dog 类的方法。

原因是:在编译时会检查引用类型。然而,在运行时,JVM 会判定对象类型到底属于哪一个对象。因此,在上面的例子中,虽然 Animal 有 move 方法,程序会正常编译。在运行时,会运行特定对象的方法。

示例:

class Animal{
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal{
public void move(){
System.out.println("Dogs can walk and run");
}
public void bark(){
System.out.println("Dogs can bark");
}
}
public class Test{
public static void main(String args[]){
Animal a = new Animal(); 
Animal b = new Dog(); 
a.move();
b.move();
b.bark();
}
}

这将产生如下结果:

Test.java:30: cannot find symbol symbol : method bark() location: class Animal b.bark();^

这个程序在编译时将抛出一个错误,因为 b 的引用类型 Animal 没有一个名字叫 bark 的方法。


方法重写规则

  1. 重写方法的参数列表应该与原方法完全相同。
  2. 返回值类型应该和原方法的返回值类型一样或者是它在父类定义时的子类型。
  3. 重写函数访问级别限制不能比原函数高。举个例子:如果父类方法声明为公有的,那么子类中的重写方法不能是私有的或是保护的。
  4. 只有被子类继承时,方法才能被重写。
  5. 方法定义为 final,将导致不能被重写。
  6. 一个方法被定义为 static,将使其不能被重写,但是可以重新声明。
  7. 一个方法不能被继承,那么也不能被重写。
  8. 和父类在一个包中的子类能够重写任何没有被声明为 private 和 final 的父类方法。
  9. 和父类不在同一个包中的子类只能重写 non-final 方法或被声明为 public 或 protected 的方法
  10. 一个重写方法能够抛出任何运行时异常,不管被重写方法是否抛出异常。然而重写方法不应该抛出比被重写方法声明的更新更广泛的已检查异常。重写方法能够抛出比被重写方法更窄或更少的异常。
  11. 构造函数不能重写。

方法覆盖 (Overriding) 和方法重载 (Overloading)[编辑]

Java 中的方法重载发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。与此相对,方法覆盖是说子类重新定义了父类的方法。方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。

super 关键字[编辑]

super是用在子类中,目的是访问直接父类中被屏蔽的变量或方法。

子类构造方法中要调用父类的构造方法:

super(参数列表)

子类引用父类成员变量:

super.成员变量名

子类成员方法覆盖了父类成员方法时,也就是子类和父类有完全相同的方法定义(但方法体可以不同):

super.方法名(参数列表)

示例:

class Animal{
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal{
public void move(){
super.move();
System.out.println("Dogs can walk and run");
}
}
public class Test{
public static void main(String args[]){
Animal b = new Dog(); 
b.move(); 
}
}

结果:

Animals can move
Dogs can walk and run

this关键字[编辑]

在类的构造方法中,通过this调用另一个构造方法:

this(参数列表)

      

方法参数或者方法中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用

this.成员变量名

的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,可不用this。

在方法中,需要引用当前对象时候。

this

其实这些用法总结都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来。