# 概述
继承是 Java 三大特性之一,它描述了事务之间的所属关系,是从已有的类中构建出新类,已有的类称为父类,新的类称为子类,子类具有父类公有的属性和方法,并能扩展新的属性和方法(子类不会继承父类私有的属性和方法)
# 继承的使用
格式:使用 extends 关键字
class person{}
class student extends person{}
# 继承的特点
提高代码的复用性
提高开发效率
让类和类之间产生联系,提供了多态的前提
所有类都是 java.lang.Object 类的子类
在 java 中,只支持单继承,不支持多重继承,一个子类只能有一个直接的父类
支持多层继承,一个类的父类可以去继承其他类,那么这个父类的子类也继承了父类继承类的属性和方法
例子说明
class perdon{ // 父类的属性和方法
private String name;
public String id;
private void MakeMoney() {
System.out.println("I will make money");
}
public void SpendMoney() {
System.out.println("I will spend money");
}
}
class Man extends person{
public void eat() {
System.out.println("I will eat");
}
}
class students extends Man{
public void say(){
System.out.print(" 我是最小的");
}
}
//students 类不仅仅继承了 Man 类的属性和方法(公有的),也继承了 perdon 类的属性和方法
// 多层继承,还可以通过接口、内部类来实现
子类和父类是相对的概念,一个类是某个类父类的同时,也可以是另一个类的子类。
一个父类可以有多个子类
# 向上转型 | 向下转型
父子对象之间的转换分为了向上转型和向下转型,它们区别如下:
向上转型:通过子类对象 (小范围) 实例化父类对象 (大范围), 这种属于自动转换
Man man = new Student();// 通过子类去实例化父类对象
这样做的意义:
当我们需要多个同父的对象调用某个方法时,通过向上转换后,则可以确定参数的统一。方便程序设计向上转型后,父类对象只能调用父类方法或者子类覆写后的方法,而子类中的方法则是无法调用的。
在这就是 Student 的方法 say () 不能调用
向下转型:通过父类对象 (大范围) 实例化子类对象 (小范围), 这种属于强制转换
Student student = (Student)new Man();// 向下转型 (Student 类是 Man 的子类)
# 继承中的关系
不同变量名子类直接调用;
相同变量名调用时,如果子类有,就不调用父类的变量,如果子类没有,父类有,则调用父类的;在继承多层父类中有方法或属性重名,会调用最接近的父类
在子类中,要调用父类的成员,使用关键字 super,调用父类方法也是一样,使用 super 关键字。
在继承关系之中,如果要实例化子类对象,会默认先调用父类构造,为父类之中的属性初始化,之后再调用子类构造,为子类之中的属性初始化,即:默认情况下,子类会找到父类之中的无参构造方法。而如果这个时候父类没有无参构造,则子类必须通过 super () 调用指定参数的构造方法。
调用父类构造方法的 super()语句必须写在子类构造方法的第一行,否则编译时将出现错误信息
class person{
person(){
System.out.println("Hi")
}
person(String s){
System.out.println(s)
}
}
// 下面的定义是正确的
class man{
man(){
super("111");
}
}
// 下面的写法是会报错的
class man_1{
man_1(){
String s;
super("123");
}
}
// JAVA 规定了 super () 调用必须是构造函数主体中的第一条语句
// 在子类中,不写 super(),系统是默认会在第一行加上的,创建子类对象时,调用子类构造方法之前会先调用父类构造方法,如果有父类一直追溯到 Object 类,它是祖宗类
super()与 this()均在构造方法内的第一行,也就是由于这个原因,它们两个无法同时存在于同一个构造方法。与 this 一样,super 指得也是对象,所以不能在 static 环境中使用,包括静态方法和静态初始化器(static 语块)。
继承的初始化顺序
1、初始化父类再初始化子类
2、先执行初始化对象中属性,再执行构造方法中的初始化。
基于上面两点,我们就知道实例化一个子类,java 程序的执行顺序是:
父类对象属性初始化 ----> 父类对象构造方法 ----> 子类对象属性初始化 ---> 子类对象构造方法
# 代码实例
先创建 person 父类(在此是爷爷类)
public class person { | |
private String age;// 私有属性,不被继承 | |
public String name;// 公有属性,可以被继承 | |
public String sex="2"; | |
public String id; | |
// 无参构造方法 | |
person(){ | |
} | |
// 有参构造方法 | |
person(String name,String id){ | |
this.name=name; | |
this.id=id; | |
} | |
// 私有方法,不被继承 | |
private void MakeMoney() { | |
System.out.println("I will make money"); | |
} | |
// 公有方法,可以被继承 | |
public void SpendMoney() { | |
System.out.println("I will spend money"); | |
} | |
public void eat(){ | |
System.out.println("I will spend eat"); | |
} | |
} |
创建 Student 父类
public class Student extends person { | |
public String grade; | |
public String classroom; | |
public String sex = "1"; | |
Student() { | |
} | |
Student(String grade, String classroom) { | |
this.grade = grade; | |
this.classroom = classroom; | |
} | |
public void sayHi(){ | |
System.out.println("hi"); | |
} | |
} |
创建 Child 类
public class Child extends Student{ | |
public String s; | |
Child(){} | |
Child(String s){ | |
super("1","101"); | |
} | |
public void say() { | |
System.out.println(); | |
} | |
} |
创建调用方法
public class transfer { | |
public static void main(String[] args) { | |
Child child =new Child(); | |
child.s="s"; | |
child.classroom="101"; | |
child.grade="1"; | |
child.id="20211226"; | |
child.sex="boy"; | |
child.name="愧诗"; | |
child.say(); | |
child.eat(); | |
child.sayHi(); | |
child.SpendMoney(); | |
Child child1= new Child("s"); | |
System.out.println(child1.grade); | |
System.out.println(child1.classroom); | |
} | |
} |
实例说明:
person类
- 公有属性和方法:name、sex、id、SpendMoney ()、eat ()
- 私有属性和方法:age ()、MakeMoney ()
Student类
定义的方法和属性(未定义私有的属性和方法)
属性:grade、classroom、sex
方法:sayHi ()
继承了:
属性和方法:name、sex、id、SpendMoney ()、eat ()
Child类
定义的方法和属性
属性:s
方法:say ()
继承的
属性和方法:name、sex、id、SpendMoney ()、eat () | grade、classroom、sex sayHi ()
在 transfer 类中 new 了 2 个对象:child、child1
child 设置和调用了其继承和有的方法与属性
child1 调用了父类 Student 的有参构造方法
// 控制台输出
我被调用了
I will spend eat
hi
I will spend money
1
101
#继承所需要注意的地方!!
- 父类一旦发生属性和方法改变,那么子类拥有的属性和方法也会改变
- 继承破坏了封装,对于父类而言,它的实现细节对于子类来说是透明的
- 继承是一种强耦合关系
在写继承的时候,好好考虑清楚是否需要从子类向父类进行向上转型。如果必须向上转型,则继承是必要的,但是如果不需要,则应当好好考虑自己是否需要继承。