继承是Java中面向对编程第二个重要特性,它主要解决的是共性抽取问题,同时继承还是多态的前提!那么什么是共性抽取问题呢?我们以生活中的例子感性的理解一下,学校里所有的职工都可以作为了一个Employee类,他们有工号(ID),姓名(name)……,对应的成员方法有工作(work)……。职工中又有老师、助教……,不同类型的职工都有工号、姓名和自己的工作,如果每类职工都编写一个类,代码如下:
class Teacher extends Employee{
int ID;
String name;
// 其他成员变量
public void work(){
System.out.println("teacher...");
}
//其他成员方法
}
class Assistant {
int ID;
String name;
// 其他成员变量
public void work(){
System.out.println("assistant...");
}
//其他成员方法
}
// 其他职工类
我们可以看到,不同的职工类的成员变量和成员方法有很多相似的东西,如果要写的类很多时,代码不免就显得有些冗余。因此,我们可以抽取出其中共性的东西构建一个父类,将所有的职工类看作子类,子类可以继承父类的一些成员变量和成员方法,同时它们又有自己独特的内容。
class Employee {
String name;
int ID;
public void showInfo(){
System.out.println("ID is: " + this.ID + " and name is: " + this.name);
}
public void work(){
System.out.println("employee...");
}
}
class Teacher extends Employee{
@Override
public void work() {
System.out.println("teacher...");
}
}
class Assistant extends Employee{
@Override
public void work() {
System.out.println("assistant...");
}
}
public class ExtendsTest {
public static void main(String[] args) {
Teacher t = new Teacher();
t.ID = 001;
t.name = "Forlogen";
t.work(); // teacher...
t.showInfo(); // ID is: 1 and name is: Forlogen
Assistant assistant = new Assistant();
assistant.ID = 110;
assistant.name = "kobe";
assistant.work(); // assistant...
assistant.showInfo(); // ID is: 110 and name is: kobe
}
}
其中继承中包含有几个重要概念:
public class 子类名称 extends 父类名称{
}
同时继承关系中还有如下特点:
在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式
直接通过子类对象访问成员变量:等号左边是谁就优先用谁,没有则向上找
如何理解上面的两句话呢?我们同样通过例子来看一下,假设现在Employee类如下,其中多加了一个成员变量school表示是哪一所院校:
class Employee {
String name;
int ID = 111;
String school = "STU";
public void showInfo(){
System.out.println("ID is: " + this.ID + " and name is: " + this.name);
}
public void work(){
System.out.println("employee...");
}
}
Teacher类如下,它只有自己的ID,并没有school:
class Teacher extends Employee{
int ID = 100;
@Override
public void work() {
System.out.println("teacher...");
}
}
那么,我们实例化一个Teacher类的对象,并访问其中的成员变量:
public class ExtendsTest1 {
public static void main(String[] args) {
Teacher t = new Teacher();
System.out.println(t.ID); // 100
System.out.println(t.school); // STU
}
}
现在等号左边的时Teacher,所以优先使用Teacher中的成员变量,因此ID为100;而school在Teacher中没有,因此要继续向它的父类中寻找,最后输出为STU。
间接通过成员方法访问成员变量:该方法属于谁就优先用谁,没有则向上找
class Employee {
String name;
int ID = 111;
String school = "STU";
// 获取ID
public void getID(){
System.out.println(ID);
}
}
class Teacher extends Employee{
int ID = 100;
public void getTeacherID(){
System.out.println(ID);
}
}
public class ExtendsTest1 {
public static void main(String[] args) {
Teacher t = new Teacher();
t.getTeacherID(); // 100
t.getID(); // 111
}
}
如上所示,Employee类中有成员方法getID来访问成员变量ID,Teacher中同样有getTeacherID来访问ID。当我们使用Teacher的对象访问ID时,使用的方法属于谁就优先用谁。getTeacherID属于Teacher,因此优先用它,相应的输出为100,而getID在Teacher中并没有,而是在它的父类中存在,因此这里访问的ID就是Employee的ID,输出111。
在子类的实现中,可能会出现继承的父类的成员变量、自己的成员变量以及自己成员方法中的局部变量有重名的情况发生,那么在使用重名变量时如何区分呢?针对不同的变量,可以做如下区分:
在父子类的继承关系中,创建子类对象,访问成员方法的规则:创建的对象是谁就优先用谁,如果没有则向上找
class Employee {
int ID = 111;
}
class Teacher extends Employee{
int ID = 100;
public void showID(){
int ID = 222;
System.out.println(ID);
System.out.println(this.ID);
System.out.println(super.ID);
}
}
public class ExtendsTest1 {
public static void main(String[] args) {
Teacher t = new Teacher();
t.showID(); // 222 100 111
}
}
在继承关系中,成员方法的使用和成员变量的使用类似:创建的对象是谁就优先用谁,如果没有则向上找。
class Employee {
String name;
int ID = 111;
public void showInfo(){
System.out.println("ID is: " + this.ID + " and name is: " + this.name);
}
}
class Teacher extends Employee{
int ID = 100;
}
public class ExtendsTest2 {
public static void main(String[] args) {
Teacher t = new Teacher();
t.showInfo(); // ID is: 111 and name is: null
}
}
如上所示,在使用Teacher对象的showInfo()时,如果它有则直接调用,由于它没有就向上找他父类中的方法。
重写是指在继承关系中方法的名称一样,参数的列表也一样。
重写(Override)和重载(Overload)的区别:
- Override:方法的名称一样,参数列表也一样,也称覆盖、覆写
- Overload:方法的名称一样,参数列表不一样
方法覆盖重写的注意事项:
@Override只写在方法前面,用来检测是不是有效的方法覆盖
class Employee {
String name;
int ID = 111;
public void showInfo(){
System.out.println("ID is: " + ID);
System.out.println("name is: " + name);
}
}
class Teacher extends Employee{
int ID = 100;
String classroom = "CS";
int salary = 10000;
@Override
public void showInfo() {
System.out.println("ID is: " + ID);
System.out.println("name is: " + name);
System.out.println("classroom is: " + classroom);
System.out.println("salary is: " + salary);
}
}
public class OverrideTest {
public static void main(String[] args) {
Teacher t = new Teacher();
t.showInfo();
/*
ID is: 100
name is: null
classroom is: CS
salary is: 10000
*/
}
}
继承关系中,父子类构造方法的访问特点:
public class Employee {
String name;
int ID = 111;
String school = "STU";
public Employee(){
System.out.println("Employee constructor...");
}
}
class Teacher extends Employee{
public Teacher(){
super();
System.out.println("Teacher constructor...");
}
}
public class ExtendsTest3 {
public static void main(String[] args) {
Teacher t = new Teacher();
// Employee constructor...
//Teacher constructor...
}
class Employee {
String name;
int ID = 111;
String school = "STU";
public void showInfo(){
System.out.println("ID is: " + ID);
System.out.println("name is: " + name);
}
}
class Teacher extends Employee{
public Teacher(){
super();
System.out.println("Teacher constructor...");
}
public void getFatherInfo(){
System.out.println(super.school);
super.showInfo();
}
}
public class ExtendsTest3 {
public static void main(String[] args) {
Teacher t = new Teacher();
t.getFatherInfo();
/*
STU
ID is: 111
name is: null
*/
}
}
Java中的this关键字
Java是单继承的,一个类的直接父类只能有一个
class A{
}
class B extends A{
} // 正确
class C{
}
class D extends A, C{
} //错误
Java语言可以多级继承
class A{
}
class B extends A{
} //正确
class C extends B{
} //正确
一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类
class A{
}
class B extends A{
} //正确
class C extends A{
} // 正确