【javase复习】## day 4 继承的内存分析、super、final ##

继承

继承的主要目的是 描述两个类的关系 和 减少重复代码

注意细节:
①父类的私有成员不能被继承
②父类的构造函数不能被继承
③创建子类对象的时候java编译器会默认加上super()去先调用父类的无参的构造方法以赋值一些变量。

我们知道一个类如果自定义了构造方法,就不会被编译器默认加上无参构造方法,那么这个时候去继承要注意:
① 在Fu类中声明一个无参的构造方法
② 在Zi类中明确调用父类带参的构造方法。




子类和父类在内存中是怎么样存在的呢。
首先引入super关键字
指代 堆内存中, 子类对象中 ,父类空间的空间引用。
与this不同,他并不是函数调用者的一个对象,而是一片内存空间的入口,虽然这片内存空间与一个真实的父类对象的内存空间一样
我们用一段代码解释:

class Person{

    String name;

    private int age;

    public  Person(String name){
        this.name = name;
    }

    public Person(){
        System.out.println("Person类的构造方法被调用了....");
    }

    public void eat(){
        System.out.println(name+"在吃饭...");
    }
}

//学生类
class Student extends Person {  // Student 就称作为Person类的子类, Person类就称作为Student的父类(超类、基类)

    int num; //学号

    public Student(){
        System.out.println("Student类的构造方法被调用了....");
    }

    public void study(){
        System.out.println(name+"good good study , day day up");
    }   
}




class Demo7 
{
    public static void main(String[] args) 
    {
        Student s = new Student();

        /*
        s.name = "狗娃";
        System.out.println("名字:"+ s.name);
        s.eat();
        */
    }
}

jvm在创建Student对象的时候,由于继承,会调用多次构造函数像包裹一样完成这个Student子类对象的创建

①java编译器在Student的构造函数第一句添加super(),然后执行super(),即父类的无参构造函数
②于是开始调用Person的无参构造函数,并初始化一片空间存有Person类的成员变量和方法并赋值。(其实是调用super(),运行Object的构造方法。)
③一个伪Person类对象创建完成,他并不是一个对象,但是在内存中和对象一样,并且有一个super关键字指向这片空间,然后再添加Student类新增的,重写的方法形成一个Student类对象
④栈内存中的引用类型变量s 指向Student对象。堆和栈建立连接。

盗了一张图表示这个关系。
这里写图片描述



接下来要注意的是由于java的就近原则,
①如果直接是子类对象去调用成员变量或者方法,就是调用子类独有空间中的变量或者方法
②如果子类独有空间中没有,就去super所指空间中寻找
③如果再没有,再去super的super空间中所寻找

这里写图片描述
在这里我思考一个点:
如果有一个父类继承一个祖父类,并重写一个方法,又有一个子类继承了父类,重写了同一个方法,能否使用super.super.function()去在子类对象调用祖父类的方法?

答案是行不通的,这也应征了super其实是指代一片内存空间而不是一个父类对象

另外,主要子类重写了方法之后,对于别的类来说,相当于父类的方法不存在了,只能通过子类的类体中用super关键字去调用。 然后优化成方法,再从别的类中调用这个优化的方法




super关键字:

super关键字代表了父类空间的引用。

super关键字的 作用:
1. 子父类存在着同名的成员时,在子类中默认是访问子类的成员,可以通过super关键字指定访问父类的成员。
2. 创建子类对象时,默认会先调用父类无参的构造方法,可以通过super关键字指定调用父类的构造方法。


super关键字调用父类构造方法要注意的事项:
1. 如果在子类的构造方法上没有指定调用父类的构造方法,那么java编译器会在子类的构造方法上面加上super()语句。
2. super关键字调用父类的构造函数时,该语句必须要是子类构造函数中的第一个语句。
3. super与this关键字不能同时出现在同一个构造函数中调用其他的构造函数。因为两个语句都需要第一个语句。

继承的另外一个作用就是重写

方法重写要注意的事项:
1.方法重写时, 方法名与形参列表必须一致。
2.方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。
3.方法重写时,子类的返回值类型必须要小于或者 等于父类的返回值类型。
4.方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。

方法的重载:在一个类中 存在两个或者两个 以上的同名函数,称作为方法重载。

方法重载的要求
1. 函数名要一致。
2. 形参列表不一致(形参的个数或形参 的类型不一致)
3. 与返回值类型无关。





final

final关键字的用法:
1. final关键字修饰一个基本类型的变量时,该变量不能重新赋值,第一次的值为最终的。
2. fianl关键字修饰一个引用类型变量时,该变量不能重新指向新的对象。
3. final关键字修饰一个函数的时候,该函数不能被重写。
4. final关键字修饰一个类的时候,该类不能被继承。

常量 的修饰符一般为: public static final

final修饰的变量不可变,成为有名常量。
存入方法区的常量池中。但是和static变量不同,并不止维护一份且随类文件加载而加载,而是随着对象创建才加载,且每个对象维护一份

一般与static联合修饰, 减少内存开销, 不用创建对象也可使用final常量。

但是在某些特殊情况下,我们只能用final而不能用static修饰,例如一个Employee类,里面有一个name域,表示雇员姓名,雇员姓名一旦在构造函数中被设置,以后就不能更改,所以name应该声明为final。但是name是属于每个雇员的(也就是Employee类的每个实例对象),而不是属于整个Employee类的,所以这时候,就不可声明为static。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章