Java使用 extends
关键字来实现继承:
class Person { private String name; private int age; public String getName() {...} public void setName(String name) {...} public int getAge() {...} public void setAge(int age) {...} } class Student extends Person { // 不要重复name和age字段/方法, // 只需要定义新增score字段/方法: private int score; public int getScore() {...} public void setScore(int score) {...} }
通过继承,子类 Student
获得了父类 Person
已有的字段与方法,节省了重复编写代码的时间。
Java中所有的类都继承自 Object
这个类,除了它自身。
private
关键字修饰的字段,只能在类中被访问,子类也无法访问,为了让子类也能使用父类的字段,要把修饰符改成 protected
。
在上一篇中讲到构造方法时有提到过 方法签名 的概念,当一个子类与其父类有着相同的方法签名的方法(修饰符、参数、返回值都相同)时,称之为 覆写 。
注意上篇中讲的重载,并不要求方法签名完全相同,编译器也是根据这个将重载的方法区分开来。覆写则在运行期间动态决定调用的方法,以实现多态。
class Animal { public void sound {...} } class Cat { @Override public void sound { System.out.println("meow") } }
使用 @Override
可以让编译器帮我们检查覆写是否正确。
final final final
有时候,如果父类的方法没有实际意义,能不能不写呢?
class Person { public void run(); // Compile Error! }
上述代码会报错。
如果一个方法只定义方法签名,没有实质内容,可以用 abstract
修饰符把它定义成抽象方法,包含抽象方法的类也必须被声明为 抽象类 (abstract class)。
abstract class Person { public abstract void run(); }
抽象类不能被实例化,方法也是空的,这个类用来干什么的呢?抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
对于抽象类的子类,我们可以用抽象类型去引用它的子类型:
Person s = new Student(); Person t = new Teacher(); s.run(); t.run();
我们可以直接调用它的方法而不必关心具体类型,可以确信抽象类的子类是一定实现了这些方法的。
有一种极端的“抽象类”,它 只包含 抽象方法,这种东西可以写成 接口 。
interface Person { void run(); String getName(); }
由于接口肯定都是抽象方法了,所以没必要用 abstract
修饰符。事实上它的方法都默认是 public abstract
。声明接口用 interface
。
某个类要去实现接口,要用 implements
关键字。
class Dog implements Animal { ... }
Java中一个类只能继承自一个父类,通过接口则可以实现多重继承,一个类可以实现多个接口。(Python支持多重继承)
接口中还可以有一种 default
修饰符修饰的默认方法,这种方法可以有一个默认实现,具体实现的类可以 不必 覆写它。
有时候可能两个人都实现了一个名为 Person
的类,同时还想引用对方的类来使用。对于这种命名冲突的情况应该怎么办呢?
Java使用包 package
来解决命名冲突。在定义一个类时,把它的包名写在第一行。
下面是用IDE编写程序时自动创建的代码部分:
package com.company; public class Main { public static void main(String[] args) { } }
与下面某人编写的同名 Main
类:
package harry; public class Main { public static void main(String[] args) { } }
虽然这两个类同名了,但在运行时,这两个类会使用完整类名,它们的完整名分别是 com.company.Main
和 harry.Main
。
有时候要使用一个包中的类,一种写法是直接写完整类名,但那样就有点麻烦,我们可以和 Python
中一样使用 import
语句。
例如要使用 java.util
包中的 ArrayList
:
import java.util.ArrayList; public class SingleImport { public static void main(String[] args) { ArrayList list = new ArrayList(); } }
这个包里还含有很多类,可以使用星号 *
:
import java.util.*;
这样表示把这个包里所有类都导入。
扫码关注: