Java

Java 知识量:11 - 45 - 220

3.3 子类与继承><

扩展类- 3.3.1 -

可以通过继承来扩展一个类。继承是一种方式,通过它,可以创建一个新类(子类),并继承另一个已存在的类(父类)的属性和方法。这是代码重用的一种方式,也是类之间的一种关系。

下面是一个简单的例子,展示了如何创建一个扩展了父类的子类:

// 父类  
public class Animal {  
    private String name;  
  
    public Animal(String name) {  
        this.name = name;  
    }  
  
    public void eat() {  
        System.out.println(name + " is eating.");  
    }  
}  
  
// 子类(扩展了父类)  
public class Dog extends Animal {  
    private String breed;  
  
    public Dog(String name, String breed) {  
        super(name);  // 调用父类的构造函数  
        this.breed = breed;  
    }  
  
    public void bark() {  
        System.out.println("The dog barks.");  
    }  
}

在这个例子中,Dog类扩展了Animal类。这意味着Dog类继承了Animal类的所有公共方法和属性,包括eat方法和name属性。并且,Dog类还定义了它自己特有的方法和属性,比如bark方法和breed属性。

可以这样使用它:

public class Main {  
    public static void main(String[] args) {  
        Dog myDog = new Dog("Rex", "German Shepherd");  
        myDog.eat();  // 继承自Animal类的方法  
        myDog.bark();  // Dog类特有的方法  
    }  
}

这段代码会输出:

Rex is eating.  
The dog barks.

超类和类层次结构- 3.3.2 -

在Java中,一个类可以继承另一个类的属性和方法。这种继承关系可以通过关键字 "extends" 来实现。子类可以继承父类的非私有属性和方法,同时也可以添加自己的属性和方法。这种层次结构称为类层次结构。

超类是指一个类在类层次结构中的父类。在Java中,所有的类都是java.lang.Object类的子类,因此Object类是所有类的超类。

下面是一个简单的Java类层次结构示例:

class Animal {  
    public void eat() {  
        System.out.println("Animal is eating");  
    }  
}  
  
class Dog extends Animal {  
    public void bark() {  
        System.out.println("Dog is barking");  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        Dog myDog = new Dog();  
        myDog.eat(); // 继承自Animal类的方法  
        myDog.bark(); // Dog类特有的方法  
    }  
}

在这个例子中,Dog类继承了Animal类,并添加了自己的方法bark()。在main()方法中,创建了一个Dog类的对象myDog,并调用了它的eat()和bark()方法。因为Dog类是Animal类的子类,所以它继承了Animal类的eat()方法。

默认构造方法- 3.3.3 -

默认构造方法是一个没有参数的构造方法。如果在一个类中没有定义任何构造方法,Java编译器会自动为这个类生成一个默认构造方法。默认构造方法会初始化类的所有实例变量,并将它们设置为默认值(例如,整数为0,对象为null等)。但是,如果类中定义了至少一个构造方法,Java编译器就不会自动提供默认构造方法。这意味着如果想使用默认构造方法来创建对象,必须自己显式地定义它。

例如:

public class Person {  
    private String name;  
    private int age;  
      
    public Person() { // 默认构造方法  
        this.name = "Unknown";  
        this.age = 0;  
    }  
}

在这个例子中,定义了一个默认构造方法,它将name设置为"Unknown",将age设置为0。

子类的构造方法- 3.3.4 -

子类的构造方法可以通过使用 super 关键字调用父类的构造方法。super 关键字是一个特殊的关键字,用于从子类中引用父类。

以下是一个简单的例子:

// 父类  
public class ParentClass {  
    private String name;  
  
    public ParentClass(String name) {  
        this.name = name;  
    }  
}  
  
// 子类  
public class ChildClass extends ParentClass {  
    private int age;  
  
    public ChildClass(String name, int age) {  
        super(name); // 调用父类的构造方法  
        this.age = age;  
    }  
}

在这个例子中,ChildClass 是 ParentClass 的子类。在 ChildClass 的构造方法中,使用 super(name); 来调用 ParentClass 的构造方法。然后,为 ChildClass 增加了新的字段 age。

需要注意的是,super 关键字必须在子类构造方法的第一行中使用,因为父类的构造需要在子类的构造之前完成。同时,如果子类没有显式地调用父类的构造方法(无论是无参构造还是有参构造),Java编译器会自动地插入一个无参的 super() 调用,但如果父类没有无参构造,编译器将会报错。

构造方法链- 3.3.5 -

构造方法链是指当在一个类中定义多个构造方法时,这些构造方法之间可能会共享一些通用的初始化代码。为了避免代码重复,可以让一个构造方法调用另一个构造方法来完成部分初始化工作。

在Java中,可以通过在构造方法内部调用其他构造方法来实现这一目标。这种在一个构造方法中调用另一个构造方法的方式被称为构造方法链。例如:

public class Person {  
    private String name;  
    private int age;  
      
    public Person(String name) {  
        this(name, 0); // 调用第二个构造方法  
    }  
      
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
}

在这个例子中,第一个构造方法通过调用第二个构造方法来初始化name和age。

遮盖超类的字段- 3.3.6 -

在Java中,子类可以访问和使用其超类的字段和方法。但是,如果希望在子类中修改或遮盖超类的字段,可以使用关键字super来引用超类的字段。

例如,假设有一个超类Animal和一个子类Dog,Animal类有一个字段name,如果希望在Dog类中访问并修改这个字段,可以这样做:

public class Animal {  
    protected String name;  
  
    public Animal(String name) {  
        this.name = name;  
    }  
}  
  
public class Dog extends Animal {  
    public Dog(String name) {  
        super(name); // 调用超类的构造函数来初始化name字段  
    }  
  
    public void setName(String name) {  
        this.name = name; // 在子类中修改超类的字段  
    }  
  
    public String getName() {  
        return this.name; // 在子类中访问超类的字段  
    }  
}

在上面的代码中,Dog类是Animal类的子类,它有一个name字段,这个字段是从Animal类继承的。在Dog类中,可以使用super关键字来引用和修改超类的字段。

注意:为了保护数据的安全性和完整性,通常将字段设置为私有(private),并通过公共的getter和setter方法来访问和修改这些字段。这样做可以防止外部代码直接访问和修改字段。在上述代码中,如果Animal类的name字段是私有的,那么Dog类就不能直接访问和修改它,而需要通过在Animal类中定义的getter和setter方法来进行操作。

覆盖超类的方法- 3.3.7 -

覆盖超类的方法被称为方法重写(Method Overriding)。方法重写是面向对象编程中的一个重要特性,它允许子类改变其父类的特定方法行为。

以下是一些规则:

  • 方法声明必须与超类方法声明完全相同,包括方法名、参数类型和数量。

  • 方法的访问权限不能比超类中的方法更严格。例如,如果超类中的方法是public的,那么子类中的方法也必须是public的。

  • 子类方法的返回类型可以是超类方法返回类型的子类型。这被称为协变返回类型(Covariant Return Types)。

  • 子类方法不能抛出比超类方法更广泛的异常,但可以抛出相同的异常或者不抛出异常。

以下是一个例子,展示了如何在子类中覆盖超类的方法:

class Animal {  
    void eat() {  
        System.out.println("Animal is eating...");  
    }  
}  
  
class Dog extends Animal {  
    // 重写超类的eat方法  
    @Override  
    void eat() {  
        System.out.println("Dog is eating...");  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        Animal animal = new Animal();  
        animal.eat();  // 输出: Animal is eating...  
  
        Dog dog = new Dog();  
        dog.eat();  // 输出: Dog is eating...  
    }  
}

在这个例子中,Dog类覆盖了Animal类的eat方法。当创建Dog对象并调用其eat方法时,会输出"Dog is eating...",而不是"Animal is eating..."。这就是方法重写的效果。