Java基础之:OOP——继承

Java基础之:OOP——继承

面向对象编程OOP(Object Oriented Programming)的三大特征之二:继承

首先看一个案例,分别创建小学生与研究生类,输出他们的信息:

小学生类:

public class Pupil { //小学生类
​
    String name;
    double score;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    public void testing() {
        System.out.println("小学生考语文...");
    }
    public void showScore() {
        System.out.println("学生名" + name + " 成绩=" + score);
    }
}
研究生类:
public class Graduate { //研究生
​
    String name;
    double score;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    public void testing() {
        System.out.println("研究生考的是微积分...");
    }
    public void showScore() {
        System.out.println("学生名 " + name + " 成绩=" + score);
    }
}

可以看到 在小学生类与研究生类中 ,有大量的内容是重复的,只有 testing() 方法不同。所以我们可以将它们两个类中共同的属性或方法抽象出来创建一个Student类,再继承Student。

继承介绍

继承可以解决代码的复用性问题,让编程更解决我们人类的思维逻辑,多个类出现相同的属性/方法时,可以将这些属性/方法抽象出来,放在一个父类中来定义,所有的子类都不需要再定义这些属性/方法,只需要继承(extends)父类即可。

继承语法

class 子类名 extends 父类名 {}

说明:

1) 子类就会自动拥有父类定义的属性和方法

2) 父类又叫 超类,基类。

3) 子类又叫派生类。

简单案例

对上面的小学生类和研究生类进行改进。

Student类:

public class Student { //父类
​
    String name;
    double score;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getScore() {
        return score;
    }
    public void setScore(double score) {
        this.score = score;
    }
    public void showScore() {
        System.out.println("学生名 " + name + " 成绩=" + score);
    }
}

Pupil类:

public class Pupil extends Student { //小学生类, 子类
​
    public void testing() {
        System.out.println("小学生考语文...");
    }

}
​ 

Graduate类:

public class Graduate extends Student{ //研究生 子类
​
    public void testing() {
        System.out.println("研究生考的是微积分...");
    }

}

继承优点

  1. 代码复用性提高了。

  2. 代码的扩展性和维护性提高了。

继承使用细节与注意事项

  1. 子类继承了所有的属性和方法,只是私有的属性不能直接访问,需要通过公共方法进行访问。(封装的体现)

  2. 子类没有继承父类的构造器,但在子类的构造器中必须调用父类的构造器,完成父类的初始化。(例:肯定是先有爷爷再有爸爸最后有儿子)

  3. 当创建子类时,不管你使用子类的哪个构造方法,默认情况下总会去调用父类的无参构造函数,如果父类没有提供无参构造函数,则必须在子类的构造函数中用 super 去指定使用父类的哪个构造函数完成对父类的初始化工作,否则,编译不会通过。

  4. 如果希望指定调用父类的某个构造方法,需要使用super关键字显式调用。

    1. 无参构造器:super();

    2. 有一个参数:super(参数);

    3. 要注意super在使用时,需要放在方法体的第一句位置。

  5. super() 和 this() 都只能放在构造方法句首,因此这两个方法不能共存在一个方法中

  6. java中所有的类都是Object类的子类

  7. 子类最多只能有一个直接父类,也就是只能继承一个父类。(若需要A类继承B类和C类,则A继承B,B继承C)。

  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到Object类。同样的,若子类调用父类提供的方法,也不限于直接父类。

简单案例

import java.util.ArrayList;
​
public class ExtendsDetail {
​
    public static void main(String[] args) {
        BB bb = new BB();
        bb.m1();
    }
}
​
class DD {
    public DD() {
        System.out.println("DD() 被调用");
    }
}
​
// 子类继承了所有的属性和方法,只是私有的属性不能直接访问,需要通过公共的方法去访问
class AA extends DD {
    // 属性
    public int n1 = 10;
    protected int n2 = 20;
    int n3 = 30;
    private int n4 = 40;

    public int getN4() {
        return n4;
    }

//  public AA() {
//      System.out.println("AA() 构造器..");
//  }
     public AA(String name) {
     }

     public AA() {

     }

     public AA(int num) {
         //super();
     }
}
​
//类的BB继承 ctrl+t
class BB extends AA { //子类BB 继承 AA
    public void m1() {
        System.out.println(n1 + " " + n2 + " " + n3 + " " /*+ n4 */);
        System.out.println(getN4());
    }

    //子类没有继承父类的构造器,但必须调用父类的构造器, 完成父类的初始化.
    //至于调用父类的哪个构造器,无所谓,但是一定要调用一个
    public BB() {
        //默认有一句话 super(), 父类的无参构造器

        //如果希望指定去调用父类的某个构造方法,则显示的调用一下
        //super在使用时,需要放在方法体的第一句位置
        //super() 和 this() 都只能放在构造方法句首,因此这两个方法不能共存在一个方法中
        super(10);
        System.out.println("BB() 构造器..");
    }
}

  

内存分析案例

public class ClassTest {
    public static void main(String[] args) {
        son son = new son();
    }
}
​
class Guandpa {
    private String name;

    public Guandpa(String name) {
        super();    //指向 Object();
        this.name = name;
    }
​
    public Guandpa() {
        //默认存在super();  即使不显式的写出
        this.name = "爷爷";
    }

    public  void show() {
        System.out.println("Guandpa:" + name);
    }
}
​
class father extends Guandpa{
    private String name;
​
    public father(String name) {
        super();
        this.name = name;
    }
​
    public father() {
        super();// 指向 Guandpa();
        this.name = "父亲";
    }

    public void show(){
        System.out.println("father"+name);
    }

}
​
class son extends father{
    private String name;

    public son(String name) {
        super();
        //默认存在super();即使不显式的写出。
        //当我们在father类中 无参构造方法被覆盖时, son子类的构造方法就会报错。
        //因为son子类在构造时 ,会首先调用super();
        this.name = name;
    }
​
    public son() {
        super();    //指向 father();
        this.name = "儿子";
    }

    public void f1() {
        show();
    }
}

  

super关键字

super代表父类的引用,用于访问父类的属性、方法、构造器

基本语法

  1. 访问父类的属性 , 不能访问父类的private属性 [案例] super.属性名;

  2. 访问父类的方法,不能访问父类的private方法

    super.方法名(参数列表);

  3. 访问父类的构造器(只能访问非私有的父类构造器):

    super(参数列表); 构造器的调用只能放在构造器中,且一定在第一行。

细节说明

  1. 调用父类的构造器 (分工明确, 父类属性由父类初始化,子类的属性由子类初始化)

  2. 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果!

  3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。A->B->C

简单案例

public class SuperTest {

public static void main(String[] args) {
BB bb = new BB();
bb.m1();
}

}

class AA {
public int n1 = 10;
protected int n2 = 20;
int n3 = 30;
private int n4 = 40;

public void run() {

}
protected void eat() {

}
void sleep() {

}
private void cry() {

}

public  AA() {

}
public AA(String name) {

}
}

class BB extends AA{
public void m1() {
//访问父类的属性 , 不能访问父类的private属性 [案例]    super.属性名
//如果子类,和父类不在同一个包 ,默认的属性是否可以访问? 答不能
System.out.println(super.n1 + " " + super.n2 + " " + super.n3 /*+ super.n4*/);
}

//访问父类的方法,不能访问父类的private方法    super.方法名(参数列表);
//如果子类,和父类不在同一个包 ,默认的方法是否可以访问? 答不能

public void m2() {

super.eat();
super.run();
super.sleep();
//super.cry();

}

//访问父类的构造器(这点前面用过):    super(参数列表);只能放在构造器的第一句,而且只能出现一句
//也只能访问 非私有的构造器,如果子类和父类不在同一个包,默认的构造器,也不能使用

public BB() {
//super();
super("hello");
}
}

  特别注意:如果子类,和父类不在同一个包 ,默认的属性不可以访问。在上面的案例中可以可以通过super访问AA类中的属性与方法,是因为AA与BB在同一个包下!

super与this

对于继承的总结:

继承的本质是建立一种查找关系,就像this关键字中的访问属性和调用方法时一样。

继承应用案例1

为了代码方便阅读这里将各个类写在了一起,但在实际开发中应该保证一个类一个文件,所有类在同一个包下。

/**
 *
 * 编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
 * 编写PC子类,继承Computer类,添加特有属性【品牌brand】 编写NotePad子类,继承Computer类,添加特有属性【演示color】
 * 编写Test类,在main方法中创建PC和NotePad对象,分别给对象中特有的属性赋值,
 * 以及从Computer类继承的属性赋值,并使用方法并打印输出信息
 *
 */
public class Test {
    public static void main(String[] args) {
        PC pc = new PC("intel_i9", "16GB", "1TB", "PCbrand");
        NotePad notePad = new NotePad("cpu", "8GB", "128GB", "NotePadcolor");

        System.out.println(pc.getDetails());
        System.out.println(notePad.getDetails());
    }
}
​
//编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
class Computer {
    //private + set & get 方法,体现封装
    private String CPU;
    private String memory;
    private String disk;

    public String getCPU() {
        return CPU;
    }
​
    public void setCPU(String cPU) {
        CPU = cPU;
    }
​
    public String getMemory() {
        return memory;
    }
​
    public void setMemory(String memory) {
        this.memory = memory;
    }
​
    public String getDisk() {
        return disk;
    }
​
    public void setDisk(String disk) {
        this.disk = disk;
    }
​

    public String getDetails() {
        return "Computer [CPU=" + CPU + ", memory=" + memory + ", disk=" + disk + "]";
    }
​
    public Computer(String cPU, String memory, String disk) {
        super();
        CPU = cPU;
        this.memory = memory;
        this.disk = disk;
    }
​
    public Computer() {
        super();
    }

}
​
//编写PC子类,继承Computer类,添加特有属性【品牌brand】
class PC extends Computer {
    private String brand;   //private + set & get 方法,体现封装

    public String getBrand() {
        return brand;
    }
​
    public void setBrand(String brand) {
        this.brand = brand;
    }
​
    @Override
    public String getDetails() {
        return super.getDetails() + "\nPC [brand=" + brand + "]";
    }
​
    public PC(String cPU, String memory, String disk, String brand) {
        super(cPU, memory, disk);
        this.brand = brand;
    }

}
​
//编写NotePad子类,继承Computer类,添加特有属性【演示color】
class NotePad extends Computer {
    private String color;   //private + set & get 方法,体现封装

    public String getColor() {
        return color;
    }
​
    public void setColor(String color) {
        this.color = color;
    }
​
    @Override
    public String getDetails() {
        return super.getDetails() + "\nNotePad [color=" + color + "]";
    }
​
    public NotePad(String cPU, String memory, String disk, String color) {
        super(cPU, memory, disk);
        this.color = color;
    }

}

继承应用案例2

为了代码方便阅读这里将各个类写在了一起,但在实际开发中应该保证一个类一个文件,所有类在同一个包下。

/**
 * 定义一个ManKind类: 成员变量int sex和int salary; 要求加上两个参数有参构造
 * 方法void manOrWomen():根据sex的值显示“man”(sex==1)或者“women”(sex==0);
 * 方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
 * 定义类Kids继承ManKind,并包括成员变量int yearsOld; 方法printAge()打印yearsOld的值。
 * 在Kids类的main方法中实例化Kids的对象someKid,用该对象访问其父类的成员变量及方法。
 */
public class HomeWork {
​
    public static void main(String[] args) {
        Kids kids = new Kids(2,-100,18);

        kids.manOrWomen();
        kids.employeed();
        kids.printAge();
​
    }
​
}
​
class ManKind {
    private int sex;
    private int salary;

    public int getSex() {
        return sex;
    }
​
    public void setSex(int sex) {
        this.sex = sex;
    }
​
    public int getSalary() {
        return salary;
    }
​
    public void setSalary(int salary) {
        this.salary = salary;
    }
​
    // 方法void manOrWomen():根据sex的值显示“man”(sex==1)或者“women”(sex==0);
    public void manOrWomen() {
        if (sex == 1) {
            System.out.println("man");
        } else{
            System.out.println("women");
        }
    }
​
    // 方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
    public void employeed() {
        if (salary == 0) {
            System.out.println("no job!");
        } else {
            System.out.println("job!");
        }
    }
​
    public ManKind(int sex, int salary) {
        super();
        if(sex != 0 && sex !=1) {
            System.out.println("性别输入内容错误,0表示女,1表示男!");
            this.sex = 0;
        }else {
            this.sex = sex;
        }
        if (salary < 0) {
            System.out.println("输入工资错误,默认值1000");
            this.salary = 1000;
        } else {
            this.salary = salary;
        }
    }
​
    public ManKind() {
        super();
    }
​
}
​
//定义类Kids继承ManKind,并包括成员变量int yearsOld; 方法printAge()打印yearsOld的值。
class Kids extends ManKind{
    private int yearsOld;

    public int getYearsOld() {
        return yearsOld;
    }
​
    public void setYearsOld(int yearsOld) {
        this.yearsOld = yearsOld;
    }
​
    public void printAge() {
        System.out.println("年龄:"+yearsOld);
    }
​
    public Kids(int sex, int salary, int yearsOld) {
        super(sex, salary);
        this.yearsOld = yearsOld;
    }

    public static void main(String[] args) {
        //在另外一个非public类中 也有一个main时,点击Run As 会询问执行哪一个main
        Kids kids = new Kids(1,2000,18);
        kids.setSex(0);
        kids.manOrWomen();
        kids.employeed();
        kids.printAge();
    }
}

  

(0)

相关推荐

  • 子类的构造方法

    子类可以继承父类的除构造方法和析构方法以外的所有成员,在子类创建对象时,必须对父类的变量进行初始化.但构造方法是不被继承的,故要在子类当中调用父类的构造方法. 如果子类中没有显式调用父类的构造方法,J ...

  • 继承的使用,方法重写(覆盖),super关键字

    认识继承 不同类型的对象,相互之间经常有一定数量的共同点.例如,小明同学.小红同学.小李同学,都共享学生的特性(班级.学号等).同时,每一个对象还定义了额外的特性使得他们与众不同.例如小明的数学比较好 ...

  • Java学习——36、类的多态(一)

    多态性是指"一种定义,多种实现".例如,画画.同是画画,但每一个人,会画出来不同的画,这就是多态. 多态主要有方法的多态和类型的多态. 今天介绍方法的多态. 方法的多态包括方法的重 ...

  • Java学习——35、子类的构造方法

    本文接上篇--34.类的继承. 子类可以继承父类的除了构造方法以外的所有成员,在子类创建对象时,必须对父类的变量进行初始化.但构造方法是不被继承的,故要在子类当中调用父类的构造方法. 如果子类中没有显 ...

  • Java基础之:OOP——接口

    Java基础之:OOP--接口 usb插槽就是现实中的接口,可以把手机,相机,u盘都插在usb插槽上,而不用担心那个插槽是专门插哪个的,原因是做usb插槽的厂家和做各种设备的厂家都遵守了统一的规定包括 ...

  • Java基础之:OOP——代码块

    代码块又称初始化块,是类中的成员(即类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来,也是通过调用执行. 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象 ...

  • Java基础之:OOP——类变量与类方法

    类变量与类方法,我们习惯也将其称为静态变量与静态方法. 类变量/静态变量 通过一个实际案例来了解,为什么需要使用静态变量. 引入案例 声明一个学生类,每创建一个学生对象,统计学生的人数. public ...

  • Java基础之:泛型

    Java基础之:泛型 在不使用泛型的情况下,在ArrayList 中,添加3个Dog. Dog对象含有name 和 age, 并输出name 和 age (要求使用getXxx()). package ...

  • Java 基础知识

    Java 基础知识

  • Java 基础语法

    注释 #单行注释 // 这里是单行注释 #多行注释 /* 这里是 多行注释 */ #JavaDoc /* *@Description: *@Author: */ Java可以使用中文命名 但不建议使用 ...

  • Java基础(第二期)

    数据类型扩展以及面试题讲解 整数拓展:进制 int i=10; int i2=010; //八进制0 int i3=0x10; //十六进制0x 0~9 A~F 16 相关进制转换自行学习,用的不多 ...

  • Java开发工程师最新面试题库系列——Java基础部分(附答案)

    JAVA基础 如果你有更好的想法请在评论区留下您的答案,一起交流讨论 面向对象有哪些特征? 答:继承.封装.多态 JDK与JRE的区别是什么? 答:JDK是java开发时所需环境,它包含了Java开发 ...

  • 全栈必备 Java基础

    那一年,从北邮毕业,同一年,在大洋的彼岸诞生了一门对软件业将产生重大影响的编程语言,它就是--Java.1998年的时候,开始学习Java1.2,并在Java Orbix 上做服务,而如今Java 9 ...