Java基础-012-Java 继承

Java 继承


类、超类和子类


1、定义子类

由继承 Employee 类来定义 Manager 类的格式, 关键字 extends 表示继承。

public class Manager extends Employee {
    
    
    Manager(String name, int age, String position) {
    
    
        super(name, age, position);
    }
    //添加方法和域
}
    public static void main(String[] args) {
    
    
        Manager manager = new Manager("xhbruce", 18, "java person");
        System.out.println(manager.getName());
    }

在这里插入图片描述

关键字 extends 表明正在构造的新类派生于一个已存在的类。 已存在的类称为超类( superclass )、 基类( base class ) 或父类( parent class); 新类称为子类(subclass、) 派生类( derived class ) 或孩子类( child class )。 超类和子类是 Java 程序员最常用的两个术语,而了解其他语言的程序员可能更加偏爱使用父类和孩子类,这些都是继承时使用的术语。
尽管 Employee 类是一个超类, 但并不是因为它优于子类或者拥有比子类更多的功能。实际上恰恰相反,子类比超类拥有的功能更加丰富。 例如, 读过 Manager 类的源代码之后就会发现, Manager 类比超类 Employee 封装了更多的数据, 拥有更多的功能。

2、覆盖方法

然而, 超类中的有些方法对子类 Manager 并不一定适用。具体来说, Manager 类中的 getSalary 方法应该返回薪水和奖金的总和。 为此需要提供一个新的方法来覆盖(override) 超类中的这个方法:

    @Override
    public double getSalary() {
    
    
        return super.getSalary() + 500;
    }

这里需要指出: 我们希望调用超类 Employee 中的 getSalary 方法, 而不是当前类的这个方法。为此, 可以使用特定的关键字 super 解决这个问题:super.getSalary()

3、子类构造器

    public Manager(String name, int age, String position) {
    
    
        super(name, age, position);
        bonus = 0;
    }

由于 Manager 类的构造器不能访问 Employee 类的私有域, 所以必须利用 Employee 类的构造器对这部分私有域进行初始化,我们可以通过 super 实现对超类构造器的调用。使用 super 调用构造器的语句必须是子类构造器的第一条语句。

4、继承层次

  由一个公共超类派生出来的所有类的集合被称为继承层次( inheritance hierarchy )。在继承层次中, 从某个特定的类到其祖先的路径被称为该类的继承链 ( inheritance chain) 。
  通常, 一个祖先类可以拥有多个子孙继承链。 例如, 可以由 Employee 类派生出子类 Programmer 或 Secretary,它们与 Manager 类没有任何关系(有可能它们彼此之间也没有任何关系)。Java 不支持多继承。
在这里插入图片描述

5、多 态

  有一个用来判断是否应该设计为继承关系的简单规则,这就是“is-a” 规则,它表明子类的每个对象也是超类的对象。例如,每个经理都是雇员, 因此, 将 Manager 类设计为 Employee 类的子类是显而易见的,反之不然, 并不是每一名雇员都是经理。
  “is-a” 规则的另一种表述法是置换法则。它表明程序中出现超类对象的任何地方都可以用子类对象置换。
  在 Java 程序设计语言中, 对象变量是多态的。 一个 Employee 变量既可以引用一个 Employee 类对象, 也可以引用一个 Employee 类的任何一个子类的对象(例如, Manager、Executive、 Secretary 等)。

    public static void main(String[] args) {
    
    
        Manager boss = new Manager("xhbruce", 18, "java person");
        Employee[] staff = new Employee[3];
        staff[0] = boss;
        boss.setBonus(1000);
        //staff[0].setBonus(1000); Error
    }

这是因为 staff[0] 声明的类型是 Employee, 而 setBonus 不是 Employee 类的方法。然而,不能将一个超类的引用赋给子类变量。例如,下面的赋值是非法的Manager m = staff[i]; // Error。原因很清楚:不是所有的雇员都是经理。 如果赋值成功,m 有可能引用了一个不是经理的Employee 对象, 当在后面调用 m.setBonus(...)时就有可能发生运行时错误。

6、阻止继承:final 类和方法

  有时候,可能希望阻止人们利用某个类定义子类。不允许扩展的类被称为 final 类。如果在定义类的时候使用了 final 修饰符就表明这个类是 final 类。 例如, 假设希望阻止人们定义 Executive 类的子类,就可以在定义这个类的时候,使用 final 修饰符声明。声明格式如下所示:

public final class Executive extends Manager {
    
    
	// ... ...
}

类中的特定方法也可以被声明为 final。 如果这样做,子类就不能覆盖这个方法(final 类中的所有方法自动地成为 final 方法) 。
  将方法或类声明为 final 主要目的是:确保它们不会在子类中改变语义。例如, Calendar 类中的 getTime 和 setTime 方法都声明为 final。这表明 Calendar 类的设计者负责实现 Date 类与日历状态之间的转换, 而不允许子类处理这些问题。同样地,String 类也是 final 类,这意味着不允许任何人定义 String 的子类。换言之, 如果有一个 String 的引用, 它引用的一定是一个 String 对象, 而不可能是其他类的对象。

7、抽象类

  如果自下而上在类的继承层次结构中上移,位于上层的类更具有通用性,甚至可能更加抽象。从某种角度看, 祖先类更加通用, 人们只将它作为派生其他类的基类,而不作为想使用的特定的实例类。例如, 考虑一下对 Employee 类层次的扩展。一名雇员是一个人, 一名学生也是一个人。下面将类 Person 和类 Student 添加到类的层次结构中。
在这里插入图片描述
为什么要花费精力进行这样高层次的抽象呢? 每个人都有一些诸如姓名这样的属性。学生与雇员都有姓名属性, 因此可以将 getName 方法放置在位于继承关系较高层次的通用超类中。

现在, 再增加一个 getDescription 方法,它可以返回对一个人的简短描述。在 Employee 类和 Student 类中实现这个方法很容易。 但是在 Person类中应该提供什么内容呢? 除了姓名之外,Person类一无所知。当然, 可以让 Person。getDescription 返回一个空字符串。然而,还有一个更好的方法, 就是使用 abstract 关键字,这样就完全不需要实现这个方法了。
  为了提高程序的清晰度, 包含一个或多个抽象方法的类本身必须被声明为抽象的。

public abstract class Person {
     
     
	... ...
	public abstract String getDescription()}

除了抽象方法之外,抽象类还可以包含具体数据和具体方法。
  抽象方法充当着占位的角色, 它们的具体实现在子类中。扩展抽象类可以有两种选择。一种是在抽象类中定义部分抽象类方法或不定义抽象类方法,这样就必须将子类也标记为抽象类另一种是定义全部的抽象方法,这样一来,子类就不是抽象的了。


  在 Java 程序设计语言中, 抽象方法是一个重要的概念。在接口(interface) 中将会看到更多的抽象方法。

Object: 所有类的超类


Object 类是 Java 中所有类的始祖, 在 Java 中每个类都是由它扩展而来的。但是并不需要这样写:public class Employee extends Object
如果没有明确地指出超类,Object 就被认为是这个类的超类。由于在 Java 中,每个类都是由 Object 类扩展而来的, 所以, 熟悉这个类提供的所有服务十分重要。
可以使用 Object 类型的变量引用任何类型的对象:Object obj = new Employee("xhbruce", 18, "java person");
当然, Object 类型的变量只能用于作为各种值的通用持有者。要想对其中的内容进行具体的操作, 还需要清楚对象的原始类型, 并进行相应的类型转换:Employee e = (Employee) obj;
在 Java 中, 只有基本类型 ( primitive types) 不是对象, 例如,数值、 字符和布尔类型的值都不是对象。所有的数组类型,不管是对象数组还是基本类型的数组都扩展了 Object 类。

1、equals 方法

  Object 类中的 equals 方法用于检测一个对象是否等于另外一个对象。在 Object 类中,这个方法将判断两个对象是否具有相同的引用。 如果两个对象具有相同的引用, 它们一定是相等的。从这点上看,将其作为默认操作也是合乎情理的。然而,对于多数类来说,这种判断并没有什么意义。

2、相等测试与继承

  如果隐式和显式的参数不属于同一个类, equals 方法将如何处理呢? 这是一个很有争议的问题。 如果发现类不匹配, equals 方法就返冋 false: 但是, 许多程序员却喜欢使用 instanceof 进行检测:if ( !(otherObject instanceof Employee)) return false;
这样做不但没有解决 otherObject 是子类的情况,并且还有可能会招致一些麻烦。这就是建议
不要使用这种处理方式的原因所在。Java 语言规范要求 equals 方法具有下面的特性:

  • 1 ) 自反性: 对于任何非空引用 x, x.equals(0) 应该返回 true。
  • 2 ) 对称性: 对于任何引用 x 和 y, 当且仅当 y.equals(x) 返回 true, x.equals(y) 也应该返回 true。
  • 3 ) 传递性: 对于任何引用 x、 y 和 z, 如果 x.equals(y) 返回 true, y.equals(z) 返回 true,x.equals(z) 也应该返回 true。
  • 4 ) 一致性: 如果 x 和 y 引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果。
  • 5 ) 对于任意非空引用 x, x.equals(null) 应该返回 false,
    这些规则十分合乎情理,从而避免了类库实现者在数据结构中定位一个元素时还要考虑
    调用 x.equals(y), 还是调用 y.equals(x) 的问题

3、hashCode 方法

  散列码( hash code ) 是由对象导出的一个整型值。 散列码是没有规律的。如果 x 和 y 是两个不同的对象, x.hashCode( ) 与 y.hashCode( ) 基本上不会相同。
  由于 hashCode 方法定义在 Object 类中, 因此每个对象都有一个默认的散列码,其值为对象的存储地址。

4、toString 方法

在 Object 中还有一个重要的方法, 就是 toString 方法, 它用于返回表示对象值的字符串。
绝大多数(但不是全部)的 toString方法都遵循这样的格式:类的名字,随后是一对方括号括起来的域值。 下面是 Employee 类中的 toString 方法的实现:

    @Override
    public String toString() {
    
    
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", position='" + position + '\'' +
                '}';
    }

实际上,还可以设计得更好一些。最好通过调用 getClaSS( ).getName( )获得类名的字符串,而不要将类名Employee硬加到 toString方法中。

总结一下


Java 不支持多继承,但支持多重继承。
在这里插入图片描述
继承的特性:

  • 子类拥有父类非 private 的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

猜你喜欢

转载自blog.csdn.net/qq_23452385/article/details/111060655