项目代码
https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter08/src/com/yinhai/extend_
如果编写两个类,两个类的属性很多都相同,只在个别方法不同,会出现代码复用性很差,所以引入继承。
目录
一、继承的基本介绍
继承可以解决代码复用,当多个类存在相同属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
示意图
二、继承的基本语法
class 子类 extends 父类{
}
1.子类会自动拥有父类定义的属性和方法
2.父类又叫基类,超类
3.子类又叫派生类
三、继承的快速入门
public class Graduate extends Student{ // extends表示继承Student父类
public void testing(){
System.out.println(name);
}
}
package com.hspedu.extend_.improve_;
//是Pupli 和 Graduate
public class Student {
public String name;
public int age;
private double score;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void info(){
System.out.println();
}
}
四、继承的细节
1.
子类继承了所有属性和方法,但是私有属性和方法不能再子类直接访问,要通过父类提供的公共的方法去访问
public String name;
int age;
protected int salary;
private int num;
public int getNum() {
return num;
}
2.
子类必须调用父类的构造器,完成父类的初始化
public class Base {
public String name;
int age;
protected int salary;
private int num;
public Base(){
System.out.println("父类base...");
}
}
public class A extends Base{
public A() {
//其实这里默认有一句话,写不写都会默认放在这个位置
//super();//默认调用父类的无参构造器
System.out.println("子类A...");
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
}
}
3.
当创建子类对象,不管使用子类的哪个构造器,默认情况总会去调用父类的无参构造器。
public class Test {
public static void main(String[] args) {
A a = new A();
A a1 = new A(1);
}
}
如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译将无法通过
public class Test {
public static void main(String[] args) {
A a = new A();
A a1 = new A(1);
}
}
public class Base {
public Base(int num){
System.out.println("父类的num形参构造器base...");
}
public class A extends Base{
public A() {
super(1);
System.out.println("子类A的无参构造器...");
}
public A(int num) {
super(2);
System.out.println("子类A的num形参构造器...");
}
4.
如果希望去调用父类的某个构造器,需要显式的定义一下 super(形式参数);
5.
super在使用时,必须放在构造器的第一行(super只能在构造器中使用)
6.
super()和this()都只能放在构造器中使用,所以这两个不能放在一个构造器内使用
7.
java所有类都是object类的子类,Object是所有类的基类/父类
使用Ctrl + H
8.
父类构造器的调用不限于直接父类 将一直往上追溯直到Obeject类(顶级父类)
还会往上找到Object的无参构造器,在JAVA源码内会有
9.
子类最多只能继承一个父类 即java中是单继承机制
那么如何让A类继承B类和C类呢?
10.
不能滥用继承,子类好父类之间必须满足is-a的逻辑关系
11.
继承设计的基本思想,父类构造器完成父类的初始化,子类的构造器完成子类的初始化
五、继承的本质
package com.hspedu.extend_;
import com.hspedu.modifier.B;
public class ExtendsTheory {
public static void main(String[] args) {
Base base = new Base();
}
}
class TopBase{//顶层类
String name = "顶层";
String hobby = "旅游";
}
class Base extends TopBase{//父类
String name = "中层";
int age = 39;
}
class Default extends Base{//子类
String name = "底层";
}
先加载我们的类,随后在方法区里加载属性信息等
随后在堆里开辟空间,从最顶层开始,依次开辟空间指向常量池,最后声明对象
那么重名对象的属性按照什么规则来访问呢
//要按照查找关系来返回信息
//1.首先查看子类是否有该属性
//2.如果子类有该属性而且可以访问,则返回信息
//3.如果子类没有这个属性,就看父类有没有这个属性(如果有而且可以访问,就返回该信息
//如果父类没有就重复3依次往上寻找,直到Object
System.out.println(base.name); //所以这里返回的就是Default里面的
package com.hspedu.extend_;
import com.hspedu.modifier.B;
public class ExtendsTheory {
public static void main(String[] args) {
Base base = new Base();
//要按照查找关系来返回信息
//1.首先查看子类是否有该属性
//2.如果子类有该属性而且可以访问,则返回信息
//3.如果子类没有这个属性,就看父类有没有这个属性(如果有而且可以访问,就返回该信息
//如果父类没有就重复3依次往上寻找,直到Object
System.out.println(base.name); //所以这里返回的就是Default里面的
}
}
class TopBase{//顶层类
String name = "顶层";
String hobby = "旅游";
}
class Base extends TopBase{//父类
String name = "中层";
int age = 39;
}
class Default extends Base{//子类
String name = "底层";
}
注意,必须要可以访问,如果其中的一个无法访问就会查找路径就会被阻挡,会直接报错
六、继承的课堂练习
1.
main中 new B()传入的是无参构造器,在classB类执行,但要运行classB先要初始化父类,因为没有super所以默认初始化 A() 所以第一句输出 a
随后构造完毕后,构造B() 该构造器内有this 所以转到B(String name)构造器 注意,此时会执行该构造器内的默认super接着初始化一次父类 ,所以第二句还是a (每次调用执行一次初始化) 随后才是该构造器本身的输出语句 第二句输出 b name
随后接着跑完B()内没有跑完的 所以第四句输出b
所以输出如下
a
a
b name
b
上面是错误的分析,初始化父类是执行了子类的构造器super();才执行初始化的,而不是一建立空间就初始化。所以正确的应该是,执行调用B()后无参构造器执行,但B无参构造器里有this(形参),会执行本类的形参构造器(this和super不能在一个构造器里面)关键字跳转到B(String name)构造器,随后在{}内执行super();初始化父类,执行输出a ,输出完后执行B(String name)构造器内的b name 输出,最后执行B()的b输出
2.
同上,第一句输出 我是A类,第二句hahah我是B类的有参构造,第三句我是c类的有参构造,第四句我是c类的无参构造
3.
package com.hspedu.extend_.exercise;
public class ExtendsExercise03 {
public static void main(String[] args) {
PC pc = new PC("intel","16","500","IBN");
NotePad notePad = new NotePad("intel","16","500","yellow");
pc.infoPrint();
notePad.infoPrint();
}
}
class Computer{
private String CPU;
private String memory;
private String disk;
public Computer(String CPU, String memory, String disk) {
this.CPU = CPU;
this.memory = memory;
this.disk = disk;
}
public String getCPU() {
return CPU;
}
public String getMemory() {
return memory;
}
public String getDisk() {
return disk;
}
public String getDetails(){
return CPU + " " + memory + " " + disk;
}
}
class PC extends Computer{
private String brand;
public PC(String CPU, String memory, String disk, String brand) {
super(CPU, memory, disk);// 执行父类初始化,并给值
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void infoPrint(){
System.out.println(getDetails() + " " + getBrand());
}
}
class NotePad extends Computer{
String color;
public NotePad(String CPU, String memory, String disk, String color) {
super(CPU, memory, disk); // 执行父类初始化,并给值
this.color = color;
}
public String getColor() {
return color;
}
public void infoPrint(){
System.out.println(getDetails() + " " + getColor());
}
}
要考虑使用另一个带项目包的写文章方式了,byd写一下几千字进去了
注意,父类的构造器由父类来执行,而不要在子类赋值初始化,同理使用构造器进行对属性的赋值,而不是赋值,赋值要用setXxx方法执行