🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## [继承语法](https://lingcoder.gitee.io/onjava8/#/book/08-Reuse?id=%e7%bb%a7%e6%89%bf%e8%af%ad%e6%b3%95) 继承是所有面向对象语言的一个组成部分。事实证明,在创建类时总是要继承,因为除非显式地继承其他类,否则就隐式地继承 Java 的标准根类对象(Object)。 组合的语法很明显,但是继承使用了一种特殊的语法。当你继承时,你说,“这个新类与那个旧类类似。你可以在类主体的左大括号前的代码中声明这一点,使用关键字**extends**后跟基类的名称。当你这样做时,你将自动获得基类中的所有字段和方法。这里有一个例子: ~~~ // reuse/Detergent.java // (c)2017 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. // Inheritance syntax & properties class Cleanser { private String s = "Cleanser"; public void append(String a) { s += a; } public void dilute() { append(" dilute()"); } public void apply() { append(" apply()"); } public void scrub() { append(" scrub()"); } @Override public String toString() { return s; } public static void main(String[] args) { Cleanser x = new Cleanser(); x.dilute(); x.apply(); x.scrub(); System.out.println(x); } } public class Detergent extends Cleanser { // Change a method: @Override public void scrub() { append(" Detergent.scrub()"); super.scrub(); // Call base-class version } // Add methods to the interface: public void foam() { append(" foam()"); } // Test the new class: public static void main(String[] args) { Detergent x = new Detergent(); x.dilute(); x.apply(); x.scrub(); x.foam(); System.out.println(x); System.out.println("Testing base class:"); Cleanser.main(args); } } /* Output: Cleanser dilute() apply() Detergent.scrub() scrub() foam() Testing base class: Cleanser dilute() apply() scrub() */ ~~~ 这演示了一些特性。首先,在**Cleanser**的`append()`方法中,使用`+=`操作符将字符串连接到**s**,这是 Java 设计人员“重载”来处理字符串的操作符之一 (还有 + )。 第二,**Cleanser**和**Detergent**都包含一个`main()`方法。你可以为每个类创建一个`main()`; 这允许对每个类进行简单的测试。当你完成测试时,不需要删除`main()`; 你可以将其留在以后的测试中。即使程序中有很多类都有`main()`方法,惟一运行的只有在命令行上调用的`main()`。这里,当你使用**java Detergent**时候,就调用了`Detergent.main()`。但是你也可以使用**java Cleanser**来调用`Cleanser.main()`,即使**Cleanser**不是一个公共类。即使类只具有包访问权,也可以访问`public main()`。 在这里,`Detergent.main()`显式地调用`Cleanser.main()`,从命令行传递相同的参数(当然,你可以传递任何字符串数组)。 **Cleanser**中的所有方法都是公开的。请记住,如果不使用任何访问修饰符,则成员默认为包访问权限,这只允许包内成员访问。因此,如果没有访问修饰符,那么包内的任何人都可以使用这些方法。例如,**Detergent**就没有问题。但是,如果其他包中的类继承**Cleanser**,则该类只能访问**Cleanser**的公共成员。因此,为了允许继承,一般规则是所有字段为私有,所有方法为公共。(受保护成员也允许派生类访问;你以后会知道的。)在特定的情况下,你必须进行调整,但这是一个有用的指南。 **Cleanser**的接口中有一组方法:`append()`、`dilute()`、`apply()`、`scrub()`和`toString()`。因为**Detergent**是从**Cleanser**派生的(通过**extends**关键字),所以它会在其接口中自动获取所有这些方法,即使你没有在**Detergent**中看到所有这些方法的显式定义。那么,可以把继承看作是复用类。如在`scrub()`中所见,可以使用基类中定义的方法并修改它。在这里,你可以在新类中调用基类的该方法。但是在`scrub()`内部,不能简单地调用`scrub()`,因为这会产生递归调用。为了解决这个问题,Java的**super**关键字引用了当前类继承的“超类”(基类)。因此表达式`super.scrub()`调用方法`scrub()`的基类版本。 继承时,你不受限于使用基类的方法。你还可以像向类添加任何方法一样向派生类添加新方法:只需定义它。方法`foam()`就是一个例子。`Detergent.main()`中可以看到,对于**Detergent**对象,你可以调用**Cleanser**和**Detergent**中可用的所有方法 (如`foam()`)。