继承

共性抽取

类的继承格式

class 父类 {
}

class 子类 extends 父类 {
}


继承的关系:is-a,父类更通用,子类更具体。

java单继承,java不支持多继承,支持多级继承

继承的特性

  • 子类拥有父类非 private 的属性、方法。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

继承关键字

继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。

extends关键字

在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。

public class Animal { 
private String name;
private int id;
public Animal(String myName, String myid) {
//初始化属性值
}
public void eat() { //吃东西方法的具体实现 }
public void sleep() { //睡觉方法的具体实现 }
}

public class Penguin extends Animal{
}


implements关键字

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

public interface A {
public void eat();
public void sleep();
}

public interface B {
public void show();
}

public class C implements A,B {
}


继承中成员变量的访问特点

在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:

  1. 直接通过子类对象访问成员变量:等号左边时谁,就优先用谁,没有则向上找
  2. 间接通过成员方法访问成员变量:该方法属于谁,就优先用谁,没有则向上找

示例代码

父类子类都有一个变量num

package extendsDemo;

//父类
public class Fu {
int num = 10;
int numFu = 20;

public void methodFu() {
System.out.println(num);
}
}

//子类
package extendsDemo;

public class Zi extends Fu{
int numZi = 100;
int num = 200;

public void methodZi() {
System.out.println(num);
}
}

//demo
package extendsDemo;

public class demoFuZi {
public static void main(String[] args) {
Fu fu = new Fu();
Zi zi = new Zi();

System.out.println(zi.num); //200
System.out.println("------------------");
zi.methodZi(); //200
zi.methodFu(); //10
}
}


区分子类方法中重名的三种

父类成员变量:直接写成员变量名

子类成员变量:this.成员变量名

子类方法的局部变量:super.成员变量名

Fu.java

package extendsDemo;

public class Fu {
int num = 10;
}


Zi.java

package extendsDemo;

public class Zi extends Fu{
int num = 20;

public void methodZi() {
int num = 30;
System.out.println(num); //30 局部变量
System.out.println(this.num); //20 本类的成员变量
System.out.println(super.num); //10 父类的成员变量
}
}


demoFuZi.java

package extendsDemo;

public class demoFuZi {
public static void main(String[] args) {
Zi zi = new Zi();
zi.methodZi();
}
}


继承中成员方法的访问特点

在父子类的继承关系中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先用谁,如果没有则向上找。

注意事项:无论时成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。

示例代码

Fu.java

public class Fu {
public void method() {
System.out.println("执行父类的方法");
}
}


Zi.java

public class Zi extends Fu{
public void method() {
System.out.println("执行子类的方法");
}
}


demoFuZi.java

public class demoFuZi {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}


java方法中的覆盖重写

重写:Override 在继承关系中,方法的名称一样,参数列表也一样

重载:OverLoad 在继承关系中,方法的名称一样,参数列表不一样

​@Override​​ 写在方法前面,用来检测是不是有效的正确覆盖重写。只是检测,方法是重写的话,不写@Override也是重写的。

子类方法的返回值必须小于等于父类方法的返回值范围

java.lang.object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类

子类方法的权限必须大于等于父类方法的权限修饰符

public > protected > (default) > private


default不是关键字default,而是什么都不写,留空。

覆盖重写应用

设计原则:对于已经投入使用的类,尽量不要进行修改。推荐定义一个新的类,来重复利用其中共性内容,并且添加改动新内容。

示例代码

Fu.java

public class Fu {
public void call() {
System.out.println("打电话");
}
public void send() {
System.out.println("发短信");
}
public void show() {
System.out.println("显示号码");
}
}


Zi.java

public class Zi extends Fu{
public void show() {
super.show(); //把父类的show方法拿过来重复利用
System.out.println("显示姓名");
System.out.println("显示头像");
}

}


demoFuZi.java

public class demoFuZi {
public static void main(String[] args) {
Fu fu = new Fu();
fu.call();
fu.send();
fu.show();
System.out.println("---------------");
Zi zi = new Zi();
zi.call();
zi.send();
zi.show();
}
}


继承中构造方法的访问特点

  1. 在子类构造方法中有一个默认隐含的“super()”调用父类无参构造方法(不写编译器也会加上),所以一定是先调用父类构造,后执行子类构造。
  2. 可以通过super关键字在子类构造方法中调用父类重载构造。
  3. super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。

总结:子类必须调用父类构造方法,不写则编译器自动加super(),写了则用写的指定的super调用,super只能有一个,还必须是第一个。

示例代码

Fu.java

public class Fu {

public Fu(){
System.out.println("父类无参构造");
}
public Fu(int num){
System.out.println("父类有参构造");
}
}


Zi.java

public class Zi extends Fu{

public Zi(){
super(); //在调用父类无参构造方法,编译器会自动加上super()
// super(10); //通过super关键字在子类构造方法中调用父类重载构造
System.out.println("子类构造方法");
}
}


demoFuZi.java

public class demoFuZi {
public static void main(String[] args) {
Zi zi = new Zi();
}
}


super关键字的三种用法

  1. 在子类的成员方法中,访问父类的成员变量
  2. 在子类的成员方法中,访问父类的成员方法
  3. 在子类的构造方法中,访问父类的构造方法

示例代码

Fu.java

public class Fu {

int num = 10;
public void method(){
System.out.println("父类方法");
}
}


Zi.java

public class Zi extends Fu{

int num = 20;
public void methodZi(){
System.out.println(super.num); //子类访问父类成员变量
}
public void method(){
super.method();
System.out.println("子类调用父类成员方法");
}
public Zi(){
super(); // 3
System.out.println("子类构造方法调用父类构造方法");
}
}


demoFuZi.java

public class Zi extends Fu{

int num = 20;
public void methodZi(){
System.out.println(super.num); //子类访问父类成员变量
}
public void method(){
super.method();
System.out.println("子类调用父类成员方法");
}
public Zi(){
super(); // 3
System.out.println("子类构造方法调用父类构造方法");
}
}


this关键字的三种用法

super关键字用来访问父类内容,而this关键字用来访问本类内容。用法三种:

  1. 在本类的成员方法中,访问本类的成员变量
  2. 在本类的成员方法中,访问本类的另一个成员方法
  3. 在本类的构造方法中,访问本类的另一个构造方法

在第三种用法中要注意:

a. this(...)调用必须是构造方法的第一个语句,唯一一个。

b. super和this两种构造调用,不能同时使用。

示例代码

Fu.java

public class Fu {

int num = 10;
public void method(){
System.out.println("父类方法");
}
}


Zi.java

public class Zi extends Fu{

int num = 20;
//在本类的成员方法中,访问本类的成员变量
public void showNum(){
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
System.out.println("-----------------");

}
//在本类的成员方法中,访问本类的另一个成员方法
public void methodA(){
System.out.println("AAA");
}
public void methodB(){
this.methodA();
System.out.println("BBB");
}
//在本类的构造方法中,访问本类的另一个构造方法
public Zi(){
this(123); //本类的无参构造调用本类的有参构造
}
public Zi(int n){
this(1,2);
}
public Zi(int n, int m){
// this(); //错误写法
}
}


super与this关键字图解

java 19.继承_java