### 论JAVA继承机制中父类与子类的关系
#### 摘要
本文深入探讨了Java语言中的继承机制,并重点分析了父类与子类之间的关系。文章围绕子类继承父类成员的过程、成员变量及方法的赋值、重写、覆盖等问题展开讨论,旨在帮助读者更好地理解Java继承中的重点与难点。
#### 关键词
- 继承机制
- 父类
- 子类
#### 一、超类的属性或方法在继承机制中的重难点问题
##### 1. 所有的成员都能被子类所继承吗?
并非如此。Java中的继承遵循一定的规则:
- **当超类和子类处于同一包内**:
- 超类中用`private`修饰的成员无法被子类继承。
- 超类中未明确指定访问修饰符(即默认)、`protected`、`public`修饰的成员均可被子类继承。
- **当超类和子类位于不同包内**:
- 超类中`private`和默认访问级别的成员不能被子类继承。
- 超类中`protected`和`public`修饰的成员能被子类所继承。
##### 2. 继承过来的属性和方法能否重写?
可以。在Java中,子类可以通过以下方式重写父类的属性和方法:
- **数据成员的重写**:当子类定义了一个与父类同名的数据成员时,子类成员将隐藏父类成员,即在子类中默认情况下无法直接访问父类成员。
- **方法的重写**:当子类中定义了一个与父类同名且具有相同参数列表的方法时,子类方法将覆盖父类方法。这意味着在子类中调用该方法时,会执行子类的方法体。
##### 3. 如何避免覆盖或重写?
如果在某些情况下,开发者不希望子类覆盖或重写父类的方法或成员变量,可以利用`super`关键字来显式地访问父类中的成员。例如,可以在子类中通过`super.变量名`或`super.方法()`的方式访问父类的成员。
#### 二、如何创建子类对象
##### 1. 创建子类和子类对象的方法
创建子类的基本语法如下:
```java
public class SubClass extends SuperClass {
// 子类的具体实现
}
```
创建子类对象的一般格式如下:
```java
SubClass subObj = new SubClass();
```
##### 2. 创建过程
- 当创建子类对象时,子类的构造器会隐式调用父类的无参构造器。如果父类没有无参构造器,则必须在子类构造器中显式调用父类构造器,通常使用`super(参数列表);`。
- 如果子类中定义了与父类同名的成员变量,父类的成员变量将被隐藏。同样地,如果子类定义了与父类同名且具有相同参数列表的方法,则父类的方法将被覆盖。
##### 3. 成员的隐藏与覆盖
- **成员变量的隐藏**:子类中定义的与父类同名的成员变量会隐藏父类中的同名成员变量。这意味着在子类内部,使用变量名时会优先引用子类的成员变量。
- **方法的覆盖**:子类中定义的与父类同名且具有相同参数列表的方法将覆盖父类中的方法。当在子类内部调用该方法时,会执行子类方法体。
#### 三、子类对象和父类对象的转换
子类对象可以赋值给父类类型的引用,但此时该对象实际上仍然是一个子类实例,只是从编译角度看作父类类型。这种特性称为“多态”。
示例代码如下:
```java
public class SuperClass {
protected String className = "父类属性";
public void print() {
System.out.println("父类方法");
}
}
public class SubClass extends SuperClass {
protected String className = "子类属性";
@Override
public void print() {
System.out.println("子类方法");
}
public static void main(String[] args) {
SuperClass sup = new SubClass(); // 子类对象赋值给父类类型的引用
System.out.println("此时的属性是: " + sup.className); // 输出“子类属性”
sup.print(); // 输出“子类方法”,因为子类覆盖了父类的print方法
}
}
```
在这个例子中,虽然`sup`是一个`SuperClass`类型的引用,但实际上指向的是一个`SubClass`对象。因此,当调用`sup.print()`时,执行的是`SubClass`中的`print`方法,而非`SuperClass`中的`print`方法。同时,由于`SubClass`中的`className`成员变量覆盖了`SuperClass`中的同名成员变量,所以`sup.className`将输出“子类属性”。