[Java学习日记]继承

面向对象三大特征之二:第一个是封装,第二个是继承

目录

一.关于继承与简单的案例代码

二.子类能够继承父类中的哪一些内容?

问题一:为什么子类不能继承父类的构造方法呢?

问题二:子类能够继承父类的所有成员变量,但是如果父类用private修饰成员变量,子类不能直接拿来使用:

案例代码:子类如何写自己的构造方法

三.继承中的成员变量在内存中的存储原理

四.继承中的成员方法在内存中的存储原理

五.在继承中,成员变量的访问特点

六:继承中成员变量与成员方法的访问:直接使用,使用this关键字,使用super关键字

七.方法的重写

重写的简单解释:

重写时方法在内存中的表现:

重写时的注意事项:

重写方法案例代码:

八.继承中的构造方法

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

案例代码1:

案例代码2:在子类的无参构造方法中调用子类的有参构造,进而调用父类的有参构造方法:一般再给对象设置默认属性的时候使用。

九.带有继承结构的JavaBean类怎么写呢?


一.关于继承与简单的案例代码

继承的简单解释:

        为了解决对象太多,对象繁杂,且不同对象中重复属性多的问题

继承的优点:

        可以提高代码复用性,子类也可以在父类基础上添加更多功能,使子类更加强大

继承特点:

        只能支持单继承,不能支持多继承,支持多层继承,每一个类直接或者间接继承Object

在使用继承的时候需要注意的地方:

        如果在父类中修饰方法使用private(只能在本类中才能用),子类中的方法就无法使用父类中的方法 也就是说————子类只能访问父类中非私有的成员方法

对于继承的简单案例代码:这里把所有类的放在一起了,方便展示,有条件可以把这里面的类全部封装成单独的类

public class Test {
    public static void main(String[] args) {
        RagDoll rd = new RagDoll();
        rd.eat();
        rd.catchMouse();
        Husky h = new Husky();
        h.drink();
        h.LookHouse();
        h.breakHouse();
    }
}
class Animal {
    public void eat(){
        System.out.println("小动物在吃吃");
    }
    public void drink(){
        System.out.println("小动物在喝水");
    }
}
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫猫抓老鼠");
    }
}
class LiHua extends Cat{}
class RagDoll extends Cat{}
class Dog extends Animal{
    public void LookHouse(){
        System.out.println("修勾勾在看家");
    }
}
class Husky extends Dog{
    public void breakHouse(){
        System.out.println("哈士奇在拆家");
    }
}
class Teddy extends Dog{
    public void touch(){
        System.out.println("泰迪摸摸");
    }
}

 输出:


二.子类能够继承父类中的哪一些内容?

        1.构造方法:无法继承

        2.成员变量:全部继承

        3.成员方法:private不能继承,非私有能够继承(还需要看其他修饰符与类与父类所在包的相对位置)

问题一:为什么子类不能继承父类的构造方法呢?

        简单的例子:如果父类Animal的构造方法叫Animal(),子类Cat的构造方法如果继承,是不是也只能够叫Animal了? 又该如何创建Cat对象呢?所以子类的构造方法要自己写!

问题二:子类能够继承父类的所有成员变量,但是如果父类用private修饰成员变量,子类不能直接拿来使用:

        要通过GetSet方法去使用变量(这些一般设置为public)。

案例代码:子类如何写自己的构造方法
public class Test {
    public static void main(String[] args) {
        Son son =new Son();
    }
}
class Father {
    String name;
    int age;
    public Father(){};
    public Father(String name,int age){
        this.name=name;
        this.age=age;
    }
}
class Son extends Father{
    public Son() { }
    public Son(String name, int age) {
        super(name, age);
    }
}


三.继承中的成员变量在内存中的存储原理

1.在子类字节码文件加载到方法区的时候,会识别继承的父类,并且把父类字节码文件也加载到方法区

2.在new一个子类对象的时候:继承成员变量时:分别记录自己的成和员变量父类的成员变量,如果说父类中使用private修饰成员变量:子类中不能直接调用从父类中继承下来的成员变量

案例代码:

public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.name="儿子";
        son.age=20;
        son.game="上古卷轴五";
        //不能使用的父类的私有成员变量比如:
        //son.smoke="华子";
    }
}
class Father {
    String name;
    int age;
    private String smoke;
}
class Son extends Father{
    String game;
}


四.继承中的成员方法在内存中的存储原理

在java中,会从最顶级的方法开始设立虚方法表:

private,final,static修饰的成员方法不会继承到虚方法表中

若A继承于B继承于C,那么会从C开始(父类)创建虚方法表,再给B创建,最后再给A创建虚方法表。

如果代码是这样:A a = new A(); a.方法c();

a在调用方法c的时候(c方法在C类中,被A类继承),会直接在A类的虚方法表里面找方法

当然这里只考虑了private 与 public的情况。对于protect与default:在同一个包中的时候都能够继承,不在同一个包就有可能出问题,(这里指测试类与子类),这里的话可以学习后面的修饰符。

案例代码:

public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        //调用父类中的public方法:
        son.study();
        son.game();
        //调用父类中的私有方法:报错
        //son.smoke();
    }
}
class Father{
    public void study(){
        System.out.println("会学习");
    }
    private void smoke(){
        System.out.println("会吸烟");
    }
}
class Son extends Father {
    public void game(){
        System.out.println("会打游戏");
    }
}


五.在继承中,成员变量的访问特点

优先使用子类中的内容,案例代码:

public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println("在继承中,成员变量的访问特点:就近原则,优先使用子类中的内容");
        System.out.println(son.name);
    }
}
class Father {
    String name = "父亲";
}
class Son extends Father {
    String name;
}


六:继承中成员变量与成员方法的访问:直接使用,使用this关键字,使用super关键字

案例代码:

public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println("在成员方法中使用不同关键字访问父亲,儿子中的成员变量");
        son.showName();
    }
}
class Grandpa {
    String name = "爷爷";
}
class Father extends Grandpa{
    String name = "父亲";
}
class Son extends Father{
    String name = "儿子";
    void showName(){
        String name ="儿子类中方法的局部变量";
        System.out.println("使用super访问父亲类中的变量:(在子类中最多调用一个super)"+super.name);
        System.out.println("使用this访问当前类的变量:"+this.name);
        System.out.println("直接使用就近访问当前方法中的局部变量:"+name);
    }
}

在继承中,成员方法的使用与调用与成员变量类似,都是就近原则与使用关键字super,this调用


七.方法的重写

重写的简单解释:

        子类中把父类的方法再写一遍,来代替父类中的方法,当父类方法不能够满足子类需求的时候,就需要进行方法的重写。

        在重写方法的时候需要标注@Override(重写注解,加上这个如果重写错误会标红,更加安全)

重写时方法在内存中的表现:

        子类中的虚方法表中,会对父类中的虚方法表进行继承,如果写了重写方法,就会对虚方法表中原来的方法进行覆盖

重写时的注意事项:

         重写方法时,重写方法的名称形参列表必须与父类中的一样。

        子类方法访问权限子类必须大于等于父类(下面的案例中的重写方法用private是不行的,子类必须比父类更加开放)

        子类方法返回值类型必须小于等于父类(返回类型是可以继承的类的情况):父类中的方法返回类型是B类,子类中的方法返回类型是A类,【A是父类,B是子类,C是B的子类】 则会报错,子类中的方法返回类型必须是B类或者C类(子类必须比父类跟专精),在这个案例中,如果person类返回类型是son,student类返回类型是father,会报错

如果返回类型是基本数据类型:如int,byte,float,那么子类与父类就需要返回相同的类型了

重写方法案例代码:
public class Test {
    public static void main(String[] args) {
        Student  s = new Student();
        s.eat();
    }
}
class Father{}
class Son extends Father {}
class Person {
    Father eat() {
        System.out.println("吃饭");
        return null;
    }
}
class Student extends Person{
    @Override
    Son eat(){
        super.eat();
        System.out.println("吃食堂");
        return null;
    }
}


八.继承中的构造方法

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

        1.父类中的构造方法不会被子类继承

        2.子类中的无参构造方法默认先访问父类中的无参构造,再访问自己

        原因:子类在初始化的时候有可能会使用到父类中的数据,父类没有初始化子类就用不了

        所以:子类的无参的构造方法中第一句默认是super(),不写也存在!

        对于有参构造: 想要调用父类的有参构造,就必须手动写super(参数)进行调用

案例代码1:
public class Test {
    public static void main(String[] args) {
        Son son1 = new Son();
        Son son2 = new Son("张三",23);
    }
}
class Father {
    String name;
    int age;
    public Father(){
        System.out.println("先执行父类的无参构造");
    };
    public Father(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("先执行父类的有参构造");
    }
}
class Son extends Father {
    public Son() {
        System.out.println("后执行子类的无参构造");
    }
    public Son(String name, int age) {
        super(name, age);
        System.out.println("后执行子类的有参构造");
    }
}

运行结果:

 

案例代码2:在子类的无参构造方法中调用子类的有参构造,进而调用父类的有参构造方法:一般再给对象设置默认属性的时候使用。
//this:一个局部变量,当前方法调用者的地址
//super:代表父类存储空间
public class Test {
    public static void main(String[] args) {
        System.out.println("在子类的无参构造里面调用子类的有参构造:一般在给对象设置默认属性的时候使用");
        Son son = new Son();
        System.out.println(son.age);
    }
}
class Father {
    String name;
    int age;
    public Father(){
        System.out.println("先执行父类的无参构造");
    };
    public Father(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("先执行父类的有参构造");
    }
}
class Son extends Father {
    public Son() {
        //调用本类的其他构造方法,这里虚拟机就不会自动添加super()
        this(null,20);
    }
    public Son(String name, int age) {
        super(name, age);
        System.out.println("后执行子类的有参构造");
    }
}

 运行结果:


九.带有继承结构的JavaBean类怎么写呢?

案例代码:

Employee类(父类):

public class Employee {
    private String id;
    private String name;
    private int salary;
    public void work(){}
    public void eat(){System.out.println("吃米饭");}
    public Employee() {}
    public Employee(String id, String name, int salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }
    public String getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public int getSalary() {
        return salary;
    }
    public void setId(String id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
}

Cook类:只用写构造方法与特殊方法

public class Cook extends Employee{
    @Override
    public void work(){
        System.out.println("做饭");
    }
    public Cook() {
    }
    public Cook(String id, String name, int salary) {
        super(id, name, salary);
    }
}

Manager类:多了一个成员变量,对比Cook类:

1.要多加getset方法

2.全部参数的构造方法。先super父类,再赋值多出来的参数

public class Manager extends Employee{
    private int managementPrice;
    @Override
    public void work(){
        System.out.println("管理其他人");
    }
    public Manager() {
    }
    public Manager(String id, String name, int salary, int managementPrice) {
        super(id, name, salary);
        this.managementPrice = managementPrice;
    }
    public int getManagementPrice() {
        return managementPrice;
    }
    public void setManagementPrice(int managementPrice) {
        this.managementPrice = managementPrice;
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Manager manager = new Manager("001","zhangsan",15000,8000);
        System.out.println(manager.getId()+" "+manager.getName()+" "+manager.getSalary()+" "+manager.getManagementPrice());
        Cook cook = new Cook("002","lisi",8000);
        System.out.println(cook.getId()+" "+cook.getName()+" "+cook.getSalary());
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值