1.继承
1.1继承学习
何时用继承:
子类是父类一种:比如:父类:人,子类:学生、老师。
如果父类:商品,子类:学生、手机,则不成立,不可以写成继承关系,即使语法没问题
1.2 小结1
1.3 继承的特点
java只支持单继承,不支持多继承,但支持多层继承
每一个类都直接或者间接的继承于object
默认加“extend Object”
子类可以继承父类全部成员变量和非私有成员方法,不能继承构造方法,但只能调用访问父类非私有的成员变量,注意!!!是变量,不能使用私有的(非要用,就用get/set方法)
1.4 设计一个继承(示例)
画图示意:
代码示意:
1.先创建父类1
public class Animals {
public void eat(){
System.out.println("吃东西");
}
public void drink(){
System.out.println("喝水");
}
}
2. 创建父类2(子类1)——继承父类1
public class Cat extends Animals{
public void catchMouse(){
System.out.println("猫在抓老鼠");
}
}
public class Dog extends Animals{
public void lookHome(){
System.out.println("狗在看家");
}
}
3.创建子类(方法类似)——继承父类2
public class Husky extends Dog {
public void breakHome(){
System.out.println("哈士奇在拆家");
}
}
public class Teddy extends Dog{
public void touch(){
System.out.println("泰迪在蹭我的腿");
}
}
public class Ragdoll extends Cat{
}
public class LiHua extends Cat{
}
4.创建测试类
public class Test {
public static void main(String[] args) {
//创建布偶猫
Ragdoll rd =new Ragdoll();
rd.eat();
rd.drink();
rd.catchMouse();
System.out.println("-----------------------------------------------------------");
//创建哈士奇
Husky h=new Husky();
h.eat();
h.drink();
h.lookHome();
h.breakHome();
}
}
1.5 小结2
1.6 子类能继承父类什么内容?——构造方法不能继承
小结:
1. 构造方法不能继承
2. 成员变量都能继承,只不过只能调用非私有的
3. 成员方法只能继承虚方法表内的,其余不能,object类有5个虚方法
虚方法:3点:非private、非static、非finnal
子类可以继承父类全部成员变量和非私有成员方法,不能继承构造方法,但只能调用访问父类非私有的成员变量,注意!!!是变量,不能使用私有的(非要用,就用get/set方法)
子类能用空参构造方法,不是因为继承,是因为虚拟机会默认给你添加一个空参构造
1.6.1 构造方法不能被继承(但父类空参构造,子类中会利用默认super优先访问)
1.6.2 子类可以继承父类全部成员变量,但只能调用非私有的
继承的内存图:
不同点和以往
1.方法区加载自解码文件时,会把父类也加载进去
2.在创建对象是,堆内存中一部分会存储父类继承下的变量,还有一部分是存储子类里面的成员变量
用public修饰成员变量:
用private修饰成员变量:private修饰无法调用,所以在堆内存中找不到,得用get方法
1.6.3 成员方法只能继承非私有——虚方法的定义
虚方法:3点:非private、非static、非finnal
调用继承虚方法表过程:
父类自动产生一个虚方法表,在继承时传给子类,子类在父类虚方法表的基础上添加上自己类的虚方法,继续传给下一个子类,以此类推,所以继承调用方法的前提一定是它属于虚方法!!!不是虚方法的直接无法继承!!!只有父类中的虚方法才能被子类继承!!!
1.7 成员变量访问特点
成员变量访问特点:就近原则
先在局部位置找,本类成员位置找,父类成员位置找,逐级往上
什么也没有调用本类局部位置,this调用本类成员位置,super调用父类的成员位置
成员变量访问特点:
方法的重写:父类的方法不能满足子类的需求,进行重写
方法的重写本质:覆盖了从父类继承下的虚方法表的方法
当你创建一个对象时,JVM会为这个对象的类生成一个方法表。这个表包含了该类定义的所有方法(包括从父类继承来的方法,但如果是被子类重写的方法,则方法表中的引用会指向子类的方法实现)。如果子类重写了父类的方法,那么子类对象的方法表中对应的方法引用就会指向子类中的方法实现。
方法的重写注意事项:与父类保持一致
1. 未加载到虚方法表中的方法不能重写
第三条:
比如父类animal,子类dog,子类cat,当子类与父类返回值一样都为annimal时,正常运行:
当子类返回值一样为dog/catl时,父类返回值为animal时,正常运行,因为子类返回值小于父类返回值;
当父类返回值一样为dog/catl时,子类返回值为animal时,运行报错,因为子类返回值大于父类返回值:
1.8 重写小练习
父类:
public class Dog {
public void drink(){
System.out.println("狗在喝水");
}
public void lookDoor(){
System.out.println("狗在看家");
}
public void eat(){
System.out.println("狗在吃狗粮");
}
}
子类:(以此类推)
super.eat()直接调用父类
public class SharPei extends Dog {
@Override
public void eat(){
super.eat();
System.out.println("沙皮狗在吃骨头");
}
}
测试类:
public class DogTest {
public static void main(String[] args) {
Dog d =new Dog();
Husky s = new Husky();
SharPei sp =new SharPei();
Tianyuan ty = new Tianyuan();
d.eat();
s.eat();
s.breakHouse();
sp.eat();
ty.eat();
}
}
1.9 继承中:构造方法的访问特点
1. 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
2.父类的空参构造是为了给父类的属性赋默认值,所以子类想要调用父类的成员对象就要先默认访问父类的无参构造
构造方法的作用是初始化对象成员变量数据的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法第一行中默认有一个super()
,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。(先有爸爸,才能有儿子)
以下为例子:创建新对象,student类构造对象先访问父类person中的无参构造,再继续回到自己类访问自己的无参构造
若想访问带参构造:手动在super里面写上父类带参构造的属性,如:
public Student(String name , int age){
super(name,age)
}
红字与父类带参构造中一样
访问特点小节:
2.this(访问本类)、super(访问父类)的使用总结
this访问本类其他构造方法:给一些属性做默认值时用到
此时this访问本类其他构造方法,其他构造方法第一行默认有super可以访问到父类,所以写this的空参构造方法里面没有默认的super,位置和super一样,必须写在构造方法第一行
2.1 小练习1
父类——职工:
public class Staff {
private String id;
private String name;
private double salary;
public Staff() {
}
public Staff(String id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void work(){
System.out.println("员工在工作");
}
public void eat(){
System.out.println("员工在吃米饭");
}
}
子类1——经理:子类在实参构造时需要将父类属性写入,并在第一行在super()内写上父类的属性,写完后,在get/set时写自己单独的属性即可,其余由super()读取属性,可以从父类获取get/set
public class Manager extends Staff{
private double bonus;
public Manager() {
}
//实参构造时,要把父类的属性也写入
public Manager(String id, String name, double salary, double bonus) {
super(id, name, salary);
this.bonus = bonus;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public void work(){
System.out.println("经理在管理其他人");
}
}
子类2——厨师:
public class cook extends Staff{
public cook() {
}
public cook(String id, String name, double salary) {
super(id, name, salary);
}
@Override
public void work(){
System.out.println("厨师在炒菜");
}
}
测试类:
public class StaffTest {
public static void main(String[] args) {
Manager m =new Manager("413","DD",35000,8000);
System.out.println(m.getId()+" "+m.getName()+" "+m.getSalary()+" "+m.getBonus());
m.work();
m.work();
cook c = new cook("12","ll",4500);
System.out.println(c.getId()+" "+c.getName()+" "+c.getSalary());
c.work();
c.eat();
}
}