继承
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
修饰的方法不能被子类覆写 -
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.*;
这样表示把这个包里所有类都导入。
扫码关注: