Java基础语法(八)| 继承
1. 继承
- 继承概述
在面向对象里面,继承是对上一章的类,进一步抽象的过程。
当多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,这个类就是父类,那么多个子类无需再定义这些属性和行为,只要 继承那一个类(父类)即可。
其中,多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类。
- 继承概念
继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
- 继承的特点
子类自动拥有父类非私有的成员(成员变量、成员方法)
子类也可以拥有自己的成员
- 继承的好处
提高代码的复用性,降低重复代码;
由于有了继承,类与类之间产生了关系,是多态的基础。
- 继承的格式
class 父类 { ... }
class 子类 extends 父类 { ... }
- 代码示例:
//父类
public class Person {public void eat(){System.out.println("吃饭");}public void sleep(){System.out.println("睡觉");}
}//子类
public class Student extends Person { }
//子类
public class Teacher extends Person { }/** 定义测试类*/
public class PersonTest {public static void main(String[] args) { Student s = new Student();s.eat();s.sleep();Teacher t = new Teacher();t.eat();t.sleep();}
}
- 继承中成员访问的特点
子类访问父类非私有成员:
public class Father {//私有的成员变量private int num = 10;public int num2 = 20;//私有的成员方法private void mothod(){System.out.println(num);System.out.println(num2);}public void show(){System.out.println(num);System.out.println(num2);}
}public class Son extends Father {//子类也可以有自己的东西public void function(){//子类不能访问父类中私有的成员变量// System.out.println(num);System.out.println(num2);}
}public class SonTest {public static void main(String[] args) {Son s = new Son();// s.num =200; //子类不能访问父类中的私有的成员变量s.num2 = 100;// s.mothod(); //子类不能访问父类中的私有的成员方法s.function(); //也可以访问自己的方法s.show();}
}
2. 成员变量
2.1 成员变量不重名
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。
代码示例:
//父类
public class Father {int num = 10;
}//子类
public class Son extends Father {//子类成员变量int num2 = 20;//子类成员方法public void function(){// 访问父类中的num,System.out.println("Fu num="+num); //10 // 访问子类中的num2System.out.println("Zi num2="+num2); // 20}
}//测试类
public class SonTest {public static void main(String[] args) {Son s = new Son();s.function();}
}
2.2 成员变量重名
如果子类父类中出现重名的成员变量,这时的访问是有影响的。
代码示例:
//父类
public class Father {int num = 10;
}//子类
public class Son extends Father {int num = 20;//子类成员方法public void function(){//如果子类成员变量的名与父类成中变量名一样,就近原则System.out.println("num="+num); //20 }
}//测试
public class SonTest {public static void main(String[] args) {Son s = new Son();s.function();}
}
2.3 super关键字
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用super关键字,修饰父类成员变量。
- 使用格式
【super.父类成员变量名】
代码示例:
public class Son extends Father {int num = 20;//子类成员方法public void function(){//如果子类成员变量的名与父类成中变量名一样,就近原则// System.out.println("Fu num="+num); //20 //我就想访问父类中的成员变量,怎么办? 用superSystem.out.println(super.num);//此时访问的就是父类的成员变量 10}
}
注意:
Fu类中的成员变量是非私有的,子类中可以直接访问。若Fu类中的成员变量私有了,子类是不能直接访问的。
通常编码时,我们遵循封装的原则,
使用private修饰成员变量,那么如何访问父类的私有成员变量呢?----可以在父类中提供公共的getXxx方法和setXxx方法。
3. 成员方法
3.1 成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
代码示例:
//父类
public class Father {public void show(){System.out.println("我是父类Father");}
}//子类
public class Son extends Father {public void show2(){System.out.println("我是子类Father");}
}//测试
public class SonTest {public static void main(String[] args) {Son s = new Son();s.show();//调用父类方法s.show2();//调用子类方法}
}
3.2 方法重写
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做 方法重写(Override)。
- 什么是方法的重写
方法重写:子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
代码示例:
//父类
public class Father {public void show(){System.out.println("我是父类Father");}public void method(){System.out.println("我是父类method");}
}
//子类
public class Son extends Father {public void show2(){System.out.println("我是子类Father");}public void method(){System.out.println("我是子x`类method");}
}//测试
public class SonTest {public static void main(String[] args) {Son s = new Son();s.show();//调用父类方法s.show2();//调用子类方法System.out.println("===================");//方法重写:子类中出现了与父类中的一模一样的方法//子类重写了父类的方法s.method();}
}
- 方法重写的应用场景
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。
代码示例:
class Phone {public void sendMessage(){System.out.println("发短信");}public void call(){System.out.println("打电话");}public void showNum(){System.out.println("来电显示号码"); }
}//智能手机类
class NewPhone extends Phone {//重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能 public void showNum(){ //调用父类已经存在的功能使用supersuper.showNum();//增加自己特有显示姓名和图片功能System.out.println("显示来电姓名");System.out.println("显示头像");}
}public class ExtendsDemo06 {public static void main(String[] args) {// 创建子类对象NewPhone np = new NewPhone();// 调用父类继承而来的方法np.call();// 调用子类重写的方法np.showNum();}
}
- 方法重写的注意事项
1. 子类方法重写父类方法,必须要保证权限大于等于父类权限,最好修饰权限一样。
2. 子类方法重写父类方法,返回值类型、方法名和参数列表都要一模一样。
4. 构造方法
1.构造方法的名字是与类名一致的。所有子类是无法继承父类构造方法的。
2.构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个super() , 表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
代码示例:
//父类
public class Father {private int num;//父类的构造方法public Father(){System.out.println("父类的构造方法");}public Father(int num) {this.num = num;}public void show1(){System.out.println(num);}
}//子类
public class Son extends Father {//子类无参构造方法public Son(){// 子类构造方法中的第一行默认有 super() ,给父类进行初始化的// 作用:因为继承必须先调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。super();System.out.println("子类的构造方法");}//子类有参构造方法public Son(int num2) {super(34);this.num2 = num2;}public void show2(){System.out.println(num2);}
}//测试
public class Test {public static void main(String[] args) {//在每次创建子类对象时,都会先初始化父类构造方法,再创建其子类对象本身。Son s = new Son();Son s = new Son();//每一次实例子类对象,都会先访问父类的无参构造 (这里两次)//访问有参构造Son s = new Son(2000);s.show1();s.show2();}
}
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
- 访问构造方法的注意事项:
* 在子类构造方法中的第一行默认有 super() ,给父类进行初始化的
* 在子类构造方法中可以手动调用父类其他重载的构造方法
格式: super(参数列表);
* super 是写在子类的构造方法的第一行。
【注意】
【super.父类成员方法】,表示调用父类的成员方法
【super.父类成员变量名】,表示调用父类的成员变量
【super()】,表示访问父类中的无参构造
【super( 88 )】, 表示访问父类中的有参构造
5. super和this
- super和this的含义
==super:前提:继承关系 。 代表父类的存储空间标识(可以理解为父亲的引用)。
==this:代表当前对象的引用(谁调用就代表谁)
super和this的用法
- 访问成员
this.成员变量 ‐‐ 本类的
this.成员方法名() ‐‐ 本类的
super.成员变量 ‐‐ 父类的
super.成员方法名() ‐‐ 父类的
代码示例:
class Animal {public void eat() {System.out.println("animal : eat"); }
}class Cat extends Animal {public void eat() {System.out.println("cat : eat");}public void eatTest() {this.eat(); // this 调用本类的方法 super.eat(); // super 调用父类的方法 }}public class ExtendsDemo08 {public static void main(String[] args) { Animal a = new Animal();a.eat();Cat c = new Cat();c.eatTest();}}
- 访问构造
this(...) ‐‐ 本类的构造方法
super(...) ‐‐ 父类的构造方法
【注意】
子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。
super()和this()都必须是在构造方法的第一行,所以不能同时出现。
6. 继承的特点
/*
Java中继承的特点:
A:Java只支持单继承,不支持多继承。
B:Java支持多层继承(继承体系),间接继承
*/class Father(){}
class Mother(){}class son extends Father(){} // 正确
class son2 extends Father , Mother {} // 不正确
- Java只支持单继承,不支持多继承
//一个类只能有一个父类,不可以有多个父类。
class C extends A{} //ok
class C extends A,B... //error
- Java支持多层继承(继承体系)
class A{}
class B extends A{}
class C extends B{}
- 子类和父类是一种相对的概念,一个父类可以有很多个子类
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
class Pig extends Animal{}
代码示例:
//爷爷
public class GrandFather {public void show(){System.out.println("爷爷");}
}
//父亲
public class Father extends GrandFather {public void method(){System.out.println("父亲");}
}
//儿子
public class Son extends Father { }//测试
public class Test {public static void main(String[] args) {Son s = new Son();s.show();// 间接的继承爷爷的方法s.method();//继承了父亲的方法}
}