• Java面向对象(进阶)-- super关键字的使用与子类对象实例化全过程


    一、super关键字的使用

    (1)为什么需要super?

    举例1:子类继承父类以后,对父类的方法进行了重写,那么在子类中,是否还可以对父类中被重写的方法进行调用?

    可以!

    举例2:子类继承父类以后,发现子类和父类中定义了同名的属性(若子类造对象,就会有两个同名属性),是否可以在子类中区分两个同名的属性?(方法可以覆盖,属性不能覆盖

    可以!

    如何调用? 使用super关键字即可。

    (2)super的理解

    super的理解:父类的

    在子类中,若想调用父类中被重写的方法,就用super.方法即可;若想调用父类中的属性,就用super.属性即可。

    若没有写super,调用的就是子类中重写的方法和子类里面声明的属性。

    Java类中使用super来调用父类中的指定操作:

    • super可用于访问父类中定义的属性
    • super可用于调用父类中定义的成员方法
    • super可用于在子类构造器中调用父类的构造器

    注意:

    • 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员
    • super的追溯不仅限于直接父类
    • super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识

    (3)super可以调用的结构

    super可以调用的结构:属性、方法、构造器

    具体的:

    1、super调用方法

    • 如果子类没有重写父类的方法,只要权限修饰符允许,在子类中完全可以直接调用父类的方法;
    • 如果子类重写了父类的方法,在子类中需要通过super.才能调用父类被重写的方法,否则默认调用的子类重写的方法
    举例1

    观察下面代码的输出结果。

    【Person.java】

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        private int age;
    
        //方法
        public void eat(){
            System.out.println("人吃饭");
        }
    
        public void sleep(){
            System.out.println("人睡觉");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
    
        //方法
        public void study(){
            System.out.println("学生学习");
        }
    
        //重写
        public void eat(){
            System.out.println("学生多吃有营养的食物");
        }
    
        public void sleep(){
            System.out.println("学生保证每天不低于七小时睡眠");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1=new Student();
            s1.eat();
            s1.sleep();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果:
    image.png


    举例2

    如何在子类方法(Student.java里面,还能够调用父类中被重写的方法呢?

    如果此时在子类方法里面调用eat()方法,毫无疑问,这个eat()方法指的是自己类里面重写的方法。如下:

    image.png

    当然,使用eat()调用和this.eat()调用效果一样,前者只是省略了this.而已。

    若现在想调用父类中的eat()方法,很简单,只需要在前面写super.即可。(以不影响封装性为前提)

    【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
    
        //重写
        public void eat(){
            System.out.println("学生多吃有营养的食物");
        }
    	//...
        public void show(){
            eat();  //省略了this
            this.eat();
    
            super.eat();    //父类中的eat()方法
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    this.eat();直接在本类找,找到了,就直接调用本类的重写方法即可。

    super.eat();直接在直接父类中找,找到了,就直接调用父类被重写的方法即可。

    eat();是省略了this.,所以本质上也是调用本类中的方法,若本类中找不到,才会去父类中找。

    测试类【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1=new Student();
            //...
            s1.show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果:

    image.png


    举例3

    父类【Person.java】

    package yuyi01;
    
    public class Person {
        //...
        public void doSport(){
            System.out.println("人运动");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //...
        public void show1(){
            doSport();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时子类中调用的doSport()毫无疑问是父类中的方法,因为子类中没有重写它。

    这时候它的前缀是啥呢?

    若在本类中调用方法,前缀都会省略this.。调用show1()方法的时候,它会在本类中找doSport()方法,找不到就会去父类中找。

    此时本类中没有doSport()方法,就会去父类中找,找到并调用。若父类中还没有,就会继续往上找,直到Object,还没有找到就会报错了。

    画个图看看:

    image.png

    此时Sutdent类里面没有重写doSport(),所以只有一个父类Person中的doSport()而已,只能调用它。

    从结果上说this.doSport()super.doSport()一致;但是从过程上来说this.doSport()先从本类开始找,super.doSport()直接向直接父类中找。

    【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //...
        public void show1(){
            doSport();
            this.doSport();
            super.doSport();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试类【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1=new Student();
            //...
            s1.show1();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行结果:

    image.png

    小结
    • 方法前面没有super.和this.
      • 先从子类找匹配方法,如果没有,再从直接父类找,再没有,继续往上追溯
    • 方法前面有this.
      • 先从子类找匹配方法,如果没有,再从直接父类找,再没有,继续往上追溯
    • 方法前面有super.
      • 从当前子类的直接父类找,如果没有,继续往上追溯

    2、super调用属性

    • 如果实例变量与局部变量重名,可以在实例变量前面加this.进行区别
    • 如果子类实例变量和父类实例变量重名,并且父类的该实例变量在子类仍然可见,在子类中要访问父类声明的实例变量需要在父类实例变量前加super.,否则默认访问的是子类自己声明的实例变量
    • 如果父子类实例变量没有重名,只要权限修饰符允许,在子类中完全可以直接访问父类中声明的实例变量,也可以用this.实例访问,也可以用super.实例变量访问
    举例1

    暂且不考虑权限的事情。此时父类Person和子类Student中有同名的属性id

    父类【 Person.java】

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        private int age;
    
        int id; //身份证号
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id; //学号
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    若此时创建子类Student的对象,那么它拥有几个属性呢?和父类同名的属性会不会被干掉?

    来Debug一下:

    image.png

    所以,属性没有方法那样有覆盖之说

    属性不会覆盖,而方法可以覆盖。


    举例2

    既然有两个同名的属性,那么该如何区分它们呢?

    此时将父类和子类中的属性id都赋值。

    父类【 Person.java】

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        private int age;
    
        int id=1001; //身份证号
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在子类中写一个show2()方法,输出id的结果是什么呢?

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
        public void show2(){
            System.out.println(id); //?
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此时输出语句并没有报错,这里遵循一个就近原则

    就和之前说的get方法一样,比如:

    image.png

    再比如:

    image.png

    当时解决办法是这样:

    image.png

    具体关于this的讲解在这一篇博客:https://blog.csdn.net/m0_55746113/article/details/134089173?spm=1001.2014.3001.5502


    所以此时的id会就近找一个一样的,然后就找到了本类的id。

    若想要父类中的id,就需要加一个super.

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
        public void show2(){
            System.out.println(id); 	//1002
            System.out.println(this.id); 	//1002
    
            System.out.println(super.id); 	//1001
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试类【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1=new Student();
        	//...
            System.out.println();
            s1.show2();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果:

    image.png

    举例3

    父类【Person.java】

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        //...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    子类【Student.java】

    package yuyi01;
    
    /**
     * ClassName: Student
     * Package: yuyi04
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/29 0029 16:40
     */
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
        //方法
        public void show3(){
            System.out.println(name);   //这样写就相当于省略了this
            System.out.println(this.name);
            System.out.println(super.name);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    name先在当前类里面找,若没有找到,就去父类中找。

    从结果上,三个输出值是一样的;但从过程上来说,name先找本类再找父类,super.name直接找父类。

    测试类【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s1=new Student();
    
            s1.show3();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出结果:

    image.png


    加super与this,就是区分重名的属性,重写的方法。

    若没有重名属性和重写的方法,this与super加不加无所谓,只不过一个本类找,一个直接父类找,过程上有区别,结果上没有区别。

    若是父类中没有的属性(本类中有),用super直接父类中找是会报错的。

    image.png

    小结

    总结:起点不同(就近原则)

    • 变量前面没有super.和this.
      • 在构造器、代码块、方法中如果出现使用某个变量,先查看是否是当前块声明的局部变量
      • 如果不是局部变量,先从当前执行代码的本类去找成员变量
      • 如果从当前执行代码的本类中没有找到,会往上找父类声明的成员变量(权限修饰符允许在子类中访问的)
    • 变量前面有this.
      • 通过this找成员变量时,先从当前执行代码的本类去找成员变量
      • 如果从当前执行代码的本类中没有找到,会往上找父类声明的成员变量(权限修饰符允许在子类中访问的)
    • 变量前面super.
      • 通过super找成员变量,直接从当前执行代码的直接父类去找成员变量(权限修饰符允许在子类中访问的)
      • 如果直接父类没有,就去父类的父类中找(权限修饰符允许在子类中访问的)

    特别说明:应该避免子类声明和父类重名的成员变量

    3、super调用构造器

    引入

    为何要调用构造器?

    比如在Student类里new了一个Student对象,可以通过s1调用属性、方法。

    【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    若此时父类Person里面的name属性没有限制,那么在测试里面可以调用name属性。

    image.png

    这里我们知道内存中有name属性,才直接调用它。

    可我们new的是Student,相当于调用的是Student的构造器,会加载Student的结构,那为啥还会加载父类的结构呢(为啥内存中有

    name属性)?这里就涉及到super调用构造器的问题。

    举例1

    ① 子类继承父类时,不会继承父类的构造器(构造器只有在同名的类里面才有)。只能通过“super(形参列表)”的方式调用父类指定的构造器。

    父类【Person.java】

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        private int age;
        int id=1001; //身份证号
    
        //构造器
        public Person() {
    
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public Person(String name, int age, int id) {
            this.name = name;
            this.age = age;
            this.id = id;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
        //测试super调用父类的构造器
        public Student(){
    
        }
        public Student(String name,int age){
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    比如在子类中调用父类中的空参构造器:

    image.png

    举例2

    父类【Person.java】

    package yuyi01;
    
    public class Person {
        //构造器
        public Person() {
            System.out.println("Person()...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //测试super调用父类的构造器
        public Student(){
            super();    //调用父类中空参的构造器
            System.out.println("Student()...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试类【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s2=new Student();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:

    image.png

    当我们调用子类构造器创建对象的时候,先调用父类构造器,输出Person()...,然后再输出Student()...。如下:

    image.png

    可以在子类构造器中调用父类的构造器,格式就是super(形参列表)。

    举例3

    ② 规定:“super(形参列表)”,必须声明在构造器的首行。(和this很像)

    如下:

    image.png


    ③ 我们前面讲过,在构造器的首行可以使用"this(形参列表)",调用本类中重载的构造器, 结合②,结论:在构造器的首行,“this(形参列表)” 和 "super(形参列表)"只能二选一。

    比如:

    image.png


    ④ 如果在子类构造器的首行既没有显示调用"this(形参列表)“,也没有显式调用"super(形参列表)”, 则子类此构造器默认调用"super()",即调用父类中空参的构造器。

    父类【Person.java】

    package yuyi01;
    
    public class Person {
        //构造器
        public Person() {
            System.out.println("Person()...");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        public Student(String name,int age){
            //没有显示调用父类中空参的构造器
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试类【StudentTest.java】

    package yuyi01;
    
    public class StudentTest {
        public static void main(String[] args) {
            Student s3=new Student("Tom",13);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:

    image.png


    Student(String name,int age)构造器首行,并没有写this(形参列表),也没有写"super(形参列表)"。此时会默认是Super(),而且是空参的。

    来Debug看一下:

    image.png

    进入构造器了,如下:

    image.png

    再下一步:

    image.png

    所以,在调Student构造器的时候,没有写this,也没有super语句,会默认父类空参构造器。

    若此时将空参构造器注释掉,会发现子类中两个构造器都会报错。第一个是显示调用,但没有找到空参构造器,就会报错;第二个虽然没有显示调用谁,但是默认调用了空参构造器,也没有找到,所以也会报错。如下:

    image.png


    ⑤ 由③和④得到结论:子类的任何一个构造器中,要么会调用本类中重载的构造器,要么会调用父类的构造器。 只能是这两种情况之一。

    画个图瞅瞅:

    image.png


    ⑥ 由⑤得到:一个类中声明有n个构造器,最多有n-1个构造器中使用了"this(形参列表)“(若有n个就会形成一个环,递归了),则剩下的那个一定使用"super(形参列表)”(显示或者默认)。

    子类中的任何一个构造器,都会直接或间接地调用父类的构造器。如下:

    image.png

    开发中常见错误:

    如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有空参的构造器,则编译出错。

    调用父类构造器不是为了造对象,造对象需要搭配new,调用父类构造器是为了初始化信息–比如将父类的属性、方法加载到内存中。

    image.png


    举例4

    父类【Person.java】

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        private int age;
    
        int id=1001; //身份证号
    
        //方法
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        //构造器
        public Person() {
            System.out.println("Person()...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    子类【Student.java】

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
        public Student(String name,int age){
            //没有显示调用父类中空参的构造器
            setAge(age);
            super.name=name;	//当前类里面没有name属性,这里super也可以写成this
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上面的写法很Low,若父类Person中有这样的构造器:

    package yuyi01;
    
    public class Person {
        //属性
        String name;
        private int age;
    
        int id=1001; //身份证号
    
        //构造器
        public Person() {
            System.out.println("Person()...");
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    子类可以这样写:

    package yuyi01;
    
    public class Student extends Person {
        //属性
        String school;
        int id=1002; //学号
    
        public Student(String name,int age){
           super(name,age);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    那么子类就可以直接调用父类中的构造器,如下:(若是没有写,调用的就是父类中的空参构造器Person()

    image.png

    以后声明子类构造器的时候,构造器的首行就可以调用父类指定的结构了。

    4、总结

    子类继承父类以后(super关键字使用的前提是基于继承),我们就可以在子类的方法或构造器中,调用父类中声明的属性或方法。(满足封装性的前提下)

    super调用方法、属性

    🗃️如何调用呢?

    需要使用"super."的结构,表示调用父类的属性或方法。

    一般情况下,我们可以考虑省略"super."的结构。

    但是,如果出现子类重写了父类的方法子父类中出现了同名的属性时,则必须使用"super."的声明,显式地调用父类被重写的方法父类中声明的同名的属性

    特别说明:应该避免子类声明和父类重名的成员变量(方法没法避开)

    在阿里的开发规范等文档中都做出明确说明:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    super调用构造器

    ① 子类继承父类时,不会继承父类的构造器。只能通过“super(形参列表)”的方式调用父类指定的构造器。

    ② 规定:“super(形参列表)”,必须声明在构造器的首行。

    ③ 我们前面讲过,在构造器的首行可以使用"this(形参列表)",调用本类中重载的构造器,
    结合②,结论:在构造器的首行,“this(形参列表)” 和 "super(形参列表)"只能二选一。

    ④ 如果在子类构造器的首行既没有显示调用"this(形参列表)“,也没有显式调用"super(形参列表)”,
    则子类此构造器默认调用"super()",即调用父类中空参的构造器。

    ⑤ 由③和④得到结论:子类的任何一个构造器中,要么会调用本类中重载的构造器,要么会调用父类的构造器。
    只能是这两种情况之一。

    ⑥ 由⑤得到:一个类中声明有n个构造器,最多有n-1个构造器中使用了"this(形参列表)“,
    则剩下的那个一定使用"super(形参列表)”。

    –> 我们在通过子类的构造器创建对象时,一定在调用子类构造器的过程中,直接或间接的调用到父类的构造器
    正因为调用过父类的构造器,我们才会将父类中声明的属性或方法加载到内存中,供子类对象使用

    情景举例1:

    class A{
    
    }
    class B extends A{
    
    }
    
    class Test{
        public static void main(String[] args){
            B b = new B();
            //A类和B类都是默认有一个无参构造,B类的默认无参构造中还会默认调用A类的默认无参构造
            //但是因为都是默认的,没有打印语句,看不出来
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    情景举例2:

    class A{
        A(){
            System.out.println("A类无参构造器");
        }
    }
    class B extends A{
    
    }
    class Test{
        public static void main(String[] args){
            B b = new B();
            //A类显示声明一个无参构造,
            //B类默认有一个无参构造,
            //B类的默认无参构造中会默认调用A类的无参构造
            //可以看到会输出“A类无参构造器"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    情景举例3:

    class A{
        A(){
            System.out.println("A类无参构造器");
        }
    }
    class B extends A{
        B(){
            System.out.println("B类无参构造器");
        }
    }
    class Test{
        public static void main(String[] args){
            B b = new B();
            //A类显示声明一个无参构造,
            //B类显示声明一个无参构造,        
            //B类的无参构造中虽然没有写super(),但是仍然会默认调用A类的无参构造
            //可以看到会输出“A类无参构造器"和"B类无参构造器")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    情景举例4:

    class A{
        A(){
            System.out.println("A类无参构造器");
        }
    }
    class B extends A{
        B(){
            super();
            System.out.println("B类无参构造器");
        }
    }
    class Test{
        public static void main(String[] args){
            B b = new B();
            //A类显示声明一个无参构造,
            //B类显示声明一个无参构造,        
            //B类的无参构造中明确写了super(),表示调用A类的无参构造
            //可以看到会输出“A类无参构造器"和"B类无参构造器")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    情景举例5:

    class A{
        A(int a){
            System.out.println("A类有参构造器");
        }
    }
    class B extends A{
        B(){
            System.out.println("B类无参构造器");
        }
    }
    class Test05{
        public static void main(String[] args){
            B b = new B();
            //A类显示声明一个有参构造,没有写无参构造,那么A类就没有无参构造了
            //B类显示声明一个无参构造,        
            //B类的无参构造没有写super(...),表示默认调用A类的无参构造
            //编译报错,因为A类没有无参构造
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    image.png

    情景举例6:

    class A{
        A(int a){
            System.out.println("A类有参构造器");
        }
    }
    class B extends A{
        B(){
            super();
            System.out.println("B类无参构造器");
        }
    }
    class Test06{
        public static void main(String[] args){
            B b = new B();
            //A类显示声明一个有参构造,没有写无参构造,那么A类就没有无参构造了
            //B类显示声明一个无参构造,        
            //B类的无参构造明确写super(),表示调用A类的无参构造
            //编译报错,因为A类没有无参构造
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    image.png

    情景举例7:

    class A{
        A(int a){
            System.out.println("A类有参构造器");
        }
    }
    class B extends A{
        B(int a){
            super(a);
            System.out.println("B类有参构造器");
        }
    }
    class Test07{
        public static void main(String[] args){
            B b = new B(10);
            //A类显示声明一个有参构造,没有写无参构造,那么A类就没有无参构造了
            //B类显示声明一个有参构造,        
            //B类的有参构造明确写super(a),表示调用A类的有参构造
            //会打印“A类有参构造器"和"B类有参构造器"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    情景举例8:

    class A{
        A(){
            System.out.println("A类无参构造器");
        }
        A(int a){
            System.out.println("A类有参构造器");
        }
    }
    class B extends A{
        B(){
            super();//可以省略,调用父类的无参构造
            System.out.println("B类无参构造器");
        }
        B(int a){
            super(a);//调用父类有参构造
            System.out.println("B类有参构造器");
        }
    }
    class Test8{
        public static void main(String[] args){
            B b1 = new B();
            B b2 = new B(10);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    (4)小结:this与super

    1、this和super的意义

    this:当前对象

    • 在构造器和非静态代码块中,表示正在new的对象
    • 在实例方法中,表示调用当前方法的对象

    super:引用父类声明的成员

    2、this和super的使用格式

    • this
      • this.成员变量:表示当前对象的某个成员变量,而不是局部变量
      • this.成员方法:表示当前对象的某个成员方法,完全可以省略this.
      • this()或this(实参列表):调用另一个构造器协助当前对象的实例化,只能在构造器首行,只会找本类的构造器,找不到就报错
    • super
      • super.成员变量:表示当前对象的某个成员变量,该成员变量在父类中声明的
      • super.成员方法:表示当前对象的某个成员方法,该成员方法在父类中声明的
      • super()或super(实参列表):调用父类的构造器协助当前对象的实例化,只能在构造器首行,只会找直接父类的对应构造器,找不到就报错

    (5)练习

    1、练习1

    🌋题目描述

    修改方法重写的练习2中定义的类Kids中employeed()方法,在该方法中调用父类ManKind的employeed()方法,
    然后再输出"but Kids should study and no job."

    【Kids.java】

    package yuyi02;
    
    /**
     * ClassName: Kids
     * Package: yuyi05
     * Description:
     修改继承内容的练习1中定义的类Kids,在Kids中重新定义employeed()方法,
     覆盖父类ManKind中定义的employeed()方法,输出"Kids should study and no job."
    
     * @Author 雨翼轻尘
     * @Create 2023/10/30 0030 10:56
     */
    public class Kids extends Mankind { //父类中声明的属性和方法都被继承到子类了,构造器就不提了。后边提super关键字的时候会提到,在子类当中调用父类中的构造器
        private int yearOld;
    
        public int getYearOld() {
            return yearOld;
        }
    
        public void setYearOld(int yearOld) {
            this.yearOld = yearOld;
        }
    
        public void printAge(){
            System.out.println("I am "+yearOld+" years old");
        }
    
        @Override
        public void employeed() {
            System.out.println("Kids should study and no job.");
        }
    
        //构造器
        public Kids(){
    
        }
    
        public Kids(int yearOld){
            this.yearOld=yearOld;
        }
    
        //把父类中的属性也做一个赋值,包括自己的属性
        public Kids(int sex, int salary,int yearOld){
            this.yearOld=yearOld;
            //sex、salary两个 属性是父类继承过来的,怎么给他们赋值?
            setSex(sex);
            setSalary(salary);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    【Mankind.java】

    package yuyi02;
    
    /**
     * ClassName: Mankind
     * Package: yuyi05
     * Description:
     * (1)定义一个ManKind类,包括
     *    成员变量int sex和int salary;
     * - 方法void manOrWoman():根据sex的值显示“man”(sex==1)或者“woman”(sex==0);
     *
     * - 方法void employeed():根据salary的值显示“no job”(salary==0)或者“ job”(salary!=0)。
     * @Author 雨翼轻尘
     * @Create 2023/10/30 0030 10:32
     */
    public class Mankind {
        //属性
        private int sex;
        private int salary;
    
        //方法
    
        public int getSex() {
            return sex;
        }
    
        public void setSex(int sex) {
            this.sex = sex;
        }
    
        public int getSalary() {
            return salary;
        }
    
        public void setSalary(int salary) {
            this.salary = salary;
        }
    
        public void manOrWoman(){
            if(sex==1){
                System.out.println("man");
            } else if (sex==0) {
                System.out.println("woman");
            }
        }
    
        public void employeed(){
            if(salary==0){
                System.out.println("no job");
            } else {
                System.out.println("job");
            }
        }
    
        //构造器
    
        public Mankind() {
    
        }
    
        public Mankind(int sex, int salary) {
            this.sex = sex;
            this.salary = salary;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    【KidsTest.java】

    package yuyi02;
    
    /**
     * ClassName: KidsTest
     * Package: yuyi05
     * Description:
     *(3)定义类KidsTest,在类的main方法中实例化Kids的对象someKid,用该对象访问其父类的成员变量及方法。
     * @Author 雨翼轻尘
     * @Create 2023/10/30 0030 10:58
     */
    public class KidsTest {
        public static void main(String[] args) {
            Kids someKid=new Kids();
            someKid.setSex(1);
            someKid.setSalary(100);
            someKid.setYearOld(12);
    
            //Kids类自己声明的方法
            someKid.printAge();
    
            //来自于父类中声明的方法
            someKid.manOrWoman();
            someKid.employeed();
    
            //
            System.out.println("*************");
            someKid.employeed();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    🤺代码

    【 Kids.java】

    package yuyi02;
    
    /**
     * ClassName: Kids
     * Package: yuyi05
     * Description:
     修改方法重写的练习2中定义的类Kids中employeed()方法,在该方法中调用父类ManKind的employeed()方法,
     然后再输出"but Kids should study and no job."
    
     * @Author 雨翼轻尘
     * @Create 2023/11/4 0030 10:56
     */
    public class Kids extends Mankind { //父类中声明的属性和方法都被继承到子类了,构造器就不提了。后边提super关键字的时候会提到,在子类当中调用父类中的构造器
       //...
        
        @Override
        public void employeed() {
            //在子类中调用父类中被重写的方法
            super.employeed();    //先去调用父类中的employeed()方法
            System.out.println("but Kids should study and no job.");
        }
        
    	//...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    【Mankind.java】

    package yuyi02;
    
    public class Mankind {
        //...
        public void employeed(){
            if(salary==0){
                System.out.println("no job");
            } else {
                System.out.println("job");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    【KidsTest.java】

    package yuyi02;
    
    public class KidsTest {
        public static void main(String[] args) {
            //...
            Kids someKid=new Kids();
            someKid.employeed();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    👻输出结果

    image.png

    2、练习2

    🌋题目描述

    在Cylinder类中修改求表面积的方法findArea()和求体积的方法findVolume(),使用上super。

    【Circle.java】

    package yuyi03;
    
    /**
     * ClassName: Circle
     * Package: yuyi06
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/31 0031 10:07
     */
    public class Circle {
        //属性
        private double radius;  //半径
        //方法
        public void setRadius(double radius){
            this.radius=radius;
        }
        public double getRadius(){
            return radius;
        }
        //求圆的面积
        public double findArea(){
            return Math.PI*radius*radius;
        }
    
        //构造器
        public Circle(){
            radius=1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    【Cylinder.java】

    package yuyi03;
    
    /**
     * ClassName: Cylinder
     * Package: yuyi06
     * Description:
     *  圆柱类
     * @Author 雨翼轻尘
     * @Create 2023/10/31 0031 10:19
     */
    public class Cylinder extends Circle {
        //属性
        private double length;  //高
    
        //方法
        public void setLength(double length){
            this.length=length;
        }
        public double getLength(){
            return length;
        }
        //求圆柱的体积
        public double findVolume(){
            return Math.PI*getRadius()*getRadius()*getLength(); //底面积*高
            //return findArea()*getLength();    //错误的
        }
    
    
        //构造器
        public Cylinder(){
            length=1;
        }
    
        //求表面积
        @Override
        public double findArea() {
            return Math.PI*getRadius()*getRadius()*2+
            2*Math.PI*getRadius()*getLength();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    【CylinderTest.java】

    package yuyi03;
    
    /**
     * ClassName: CylinderTest
     * Package: yuyi06
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/10/31 0031 10:29
     */
    public class CylinderTest {
        public static void main(String[] args) {
            Cylinder cy=new Cylinder();
            cy.setRadius(2.3);
            cy.setLength(1.4);
            System.out.println("圆柱的体积为: "+cy.findVolume());
            System.out.println("圆柱的表面积为: "+cy.findArea());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    🤺代码

    【Cylinder.java】

    package yuyi03;
    
    public class Cylinder extends Circle {
        //...
    
        //求圆柱的体积
        public double findVolume(){
            //return Math.PI*getRadius()*getRadius()*getLength(); //底面积*高  正确的
            //return findArea()*getLength();    //错误的
            return super.findArea()*getLength();
        }
    
        //...
    
        //求表面积
        @Override
        public double findArea() {
            return Math.PI*getRadius()*getRadius()*2+
            2*Math.PI*getRadius()*getLength();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    【Circle.java】

    package yuyi03;
    
    public class Circle {
        //...
    
        //求圆的面积
        public double findArea(){
            return Math.PI*radius*radius;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    【CylinderTest.java】

    package yuyi03;
    
    public class CylinderTest {
        public static void main(String[] args) {
            Cylinder cy=new Cylinder();
            cy.setRadius(2.3);
            cy.setLength(1.4);
            System.out.println("圆柱的体积为: "+cy.findVolume());
            System.out.println("圆柱的表面积为: "+cy.findArea());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    👻输出结果

    image.png

    3、练习3

    🌋题目描述

    ①写一个名为Account的类模拟账户。该类的属性和方法如下图所示。

    image.png

    该类包括的属性:账号id,余额balance,年利率annualInterestRate;

    包含的方法:访问器方法(getter和setter方法),返回月利率的方法getMonthlyInterest(),取款方法withdraw(),存款方法deposit()。

    写一个用户程序测试Account类。在用户程序中,创建一个账号为1122、余额为20000、年利率4.5%的Account对象。

    使用withdraw方法提款30000元,并打印余额。

    再使用withdraw方法提款2500元,使用deposit方法存款3000元,然后打印余额和月利率。

    提示:在提款方法withdraw中,需要判断用户余额是否能够满足提款数额的要求,如果不能,应给出提示。

    运行结果如图所示。

    image.png

    ②创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft代表可透支限额。

    在CheckAccount类中重写withdraw方法,其算法如下:

    ————————————————————————————————————————

    如果(取款金额<账户余额),

    可直接取款

    如果(取款金额>账户余额),

    计算需要透支的额度

    判断可透支额overdraft是否足够支付本次透支需要,如果可以

    将账户余额修改为0,冲减可透支金额

    如果不可以

    提示用户超过可透支额的限额

    ————————————————————————————————————————

    要求:写一个用户程序测试CheckAccount类。

    在用户程序中,创建一个账号为1122、余额为20000、年利率4.5%,可透支限额为5000元的CheckAccount对象。

    使用withdraw方法提款5000元,并打印账户余额和可透支额。

    再使用withdraw方法提款18000元,并打印账户余额和可透支额。

    再使用withdraw方法提款3000元,并打印账户余额和可透支额。

    提示:

    (1)子类CheckAccount的构造方法需要将从父类继承的3个属性和子类自己的属性全部初始化。

    (2)父类Account的属性balance被设置为private,但在子类CheckAccount的withdraw方法中需要修改它的值,因此应修改父类的balance属性,定义其为protected。

    运行结果如下图所示。

    image.png


    🤺代码①

    【Account.java】

    package yuyi04;
    
    /**
     * ClassName: Account
     * Package: yuyi04
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/4 0004 8:29
     */
    public class Account {
        //属性
        private int id; //账户
        private double balance; //余额
        private double annualInterestRate;  //年利率
    
        //构造器
        public Account(int id,double balance,double annualInterestRate){
            //super();
            this.id=id;
            this.balance=balance;
            this.annualInterestRate=annualInterestRate;
        }
    
        //方法
        public void setId(int id) {
            this.id = id;
        }
    
        public void setBalance(double balance) {
            this.balance = balance;
        }
    
        public int getId() {
            return id;
        }
    
        public double getBalance() {
            return balance;
        }
    
        public void setAnnualInterestRate(double annualInterestRate) {
            this.annualInterestRate = annualInterestRate;
        }
    
        /**
         * 获取月利率
         * @return
         */
        public double getMonthlyInterest(){
            return annualInterestRate / 12;
        }
    
        /**
         * 取钱曹操作
         * @param amount  要取的钱数
         */
        public void withdraw(double amount){
            if(balance>=amount){
                balance-=amount;
            }else{
                System.out.println("余额不足!");
            }
        }
    
        /**
         * 存钱操作
         * @param amount 要存的额度
         */
        public void deposit(double amount){
            if(amount>0){
                balance+=amount;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    【AccountTest.java】

    package yuyi04;
    
    /**
     * ClassName: AccountTest
     * Package: yuyi04
     * Description:
     * 写一个用户程序测试Account类。在用户程序中,创建一个账号为1122、余额为20000、年利率4.5%的Account对象。
     *   使用withdraw方法提款30000元,并打印余额。
     *   再使用withdraw方法提款2500元,使用deposit方法存款3000元,然后打印余额和月利率。
     * @Author 雨翼轻尘
     * @Create 2023/11/4 0004 10:46
     */
    public class AccountTest {
        public static void main(String[] args) {
            Account acct=new Account(1122,20000,0.045);
            acct.withdraw(30000);
            System.out.println("您的账户余额为:"+acct.getBalance());
            acct.withdraw(2500);
            acct.deposit(3000);
            System.out.println("您的账户余额为: "+acct.getBalance());
            System.out.println("月利率为: "+acct.getMonthlyInterest());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    👻运行结果①

    image.png


    🤺代码②

    【Account.java】

    package yuyi04;
    
    /**
     * ClassName: Account
     * Package: yuyi04
     * Description:
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/4 0004 8:29
     */
    public class Account {
        //属性
        private int id; //账户
        private double balance; //余额
        private double annualInterestRate;  //年利率
    
        //构造器
        public Account(int id,double balance,double annualInterestRate){
            //super();
            this.id=id;
            this.balance=balance;
            this.annualInterestRate=annualInterestRate;
        }
    
        //方法
        public void setId(int id) {
            this.id = id;
        }
    
        /*public void setBalance(double balance) {
            this.balance = balance;
        }*/
    
        public int getId() {
            return id;
        }
    
        public double getBalance() {
            return balance;
        }
    
        public void setAnnualInterestRate(double annualInterestRate) {
            this.annualInterestRate = annualInterestRate;
        }
    
        /**
         * 获取月利率
         * @return
         */
        public double getMonthlyInterest(){
            return annualInterestRate / 12;
        }
    
        /**
         * 取钱曹操作
         * @param amount  要取的钱数
         */
        public void withdraw(double amount){
            if(balance>=amount){
                balance-=amount;
            }else{
                System.out.println("余额不足!");
            }
        }
    
        /**
         * 存钱操作
         * @param amount 要存的额度
         */
        public void deposit(double amount){
            if(amount>0){
                balance+=amount;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    【CheckAccount.java】

    package yuyi04;
    
    /**
     * ClassName: CheckAccount
     * Package: yuyi04
     * Description:
     *  创建Account类的一个子类CheckAccount代表可透支的账户,该账户中定义一个属性overdraft代表可透支限额。
     * @Author 雨翼轻尘
     * @Create 2023/11/4 0004 14:51
     */
    public class CheckAccount extends Account{
        //属性
        private double overdraft;   //可透支限额
    
        //方法
        public double getOverdraft() {
            return overdraft;
        }
    
        public void setOverdraft(double overdraft) {
            this.overdraft = overdraft;
        }
    
    
        //重写withdraw方法
        /**
         * 针对于可透支的账户的取钱操作
         * @param amount  要取的钱数
         */
        public void withdraw(double amount){
            if(getBalance()>=amount){
                //错误的:(左右结果都是一个值,何来赋值一说)
                //getBalance()=getBalance()-amount;
    
                //正确的
                super.withdraw(amount); //super别去掉了,这里调用的是父类的withdraw方法
            } else if (getBalance()+overdraft>=amount) {
                overdraft-=amount-getBalance(); //可透支的限额剩余量
                super.withdraw(getBalance());   //把原本账户的钱取光
            }else{
                System.out.println("超过可透支限额");
            }
        }
    
    
        //构造器
        public CheckAccount(int id,double balance,double annualInterestRate){
            super(id,balance,annualInterestRate);
        }
    
        public CheckAccount(int id,double balance,double annualInterestRate,double overdraft){
            super(id,balance,annualInterestRate);
            this.overdraft=overdraft;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    【CheckAccountTest.java】

    package yuyi04;
    
    /**
     * ClassName: CheckAccountTest
     * Package: yuyi04
     * Description:
     *  要求:写一个用户程序测试CheckAccount类。
     *  在用户程序中,创建一个账号为1122、余额为20000、年利率4.5%,可透支限额为5000元的CheckAccount对象。
     *
     *  使用withdraw方法提款5000元,并打印账户余额和可透支额。
     *  再使用withdraw方法提款18000元,并打印账户余额和可透支额。
     *  再使用withdraw方法提款3000元,并打印账户余额和可透支额。
     *
     * @Author 雨翼轻尘
     * @Create 2023/11/4 0004 22:05
     */
    public class CheckAccountTest {
        public static void main(String[] args) {
            CheckAccount checkAccount=new CheckAccount(1122,20000,0.045,5000);
    
            checkAccount.withdraw(5000);
            System.out.println("您的账户余额为: "+checkAccount.getBalance());
            System.out.println("您的可透支额为: "+checkAccount.getOverdraft());
    
            checkAccount.withdraw(18000);
            System.out.println("您的账户余额为: "+checkAccount.getBalance());
            System.out.println("您的可透支额为: "+checkAccount.getOverdraft());
    
            checkAccount.withdraw(3000);
            System.out.println("您的账户余额为: "+checkAccount.getBalance());
            System.out.println("您的可透支额为: "+checkAccount.getOverdraft());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    👻输出结果

    image.png

    ⚡注意

    【注意一】

    当我们写完第一问的时候,第二问写CHeckAccount继承于Account,就会报错。

    如下:

    image.png

    这是为哈呢?

    在声明一个类没有显示写构造器的时候,会默认有一个空参的构造器。任何一个构造器的首行,要么写this(形参列表),要么是super(形参列表)。若现在构造器也没有写,那就是默认super()。

    而现在父类Account里面根本没有提供空参构造器,所以会报错。

    image.png

    有两种解决办法。

    第一种是给父类提供空参的构造器:

    package yuyi04;
    
    public class Account {
        //...
        //构造器
        //空参构造器
    	public Account(){
            
        }
        
        public Account(int id,double balance,double annualInterestRate){
            //super();
            this.id=id;
            this.balance=balance;
            this.annualInterestRate=annualInterestRate;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    第二种可以直接调用有参的构造器:

    image.png


    【注意二】

    CheckAccount类里面重写的withdraw方法。

    package yuyi04;
    
    public class CheckAccount extends Account{
        //...
        //重写withdraw方法
        /**
         * 针对于可透支的账户的取钱操作
         * @param amount  要取的钱数
         */
        public void withdraw(double amount){
            if(getBalance()>=amount){
                //错误的:(左右结果都是一个值,何来赋值一说)
                //getBalance()=getBalance()-amount;
    
                //正确的
                super.withdraw(amount); //super别去掉了,这里调用的是父类的withdraw方法
            } else if (getBalance()+overdraft>=amount) {
                overdraft-=amount-getBalance(); //可透支的限额剩余量
                super.withdraw(getBalance());   //把原本账户的钱取光
            }else{
                System.out.println("超过可透支限额");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这里很容易弄混:

    image.png

    【小Tips】

    按住Ctrl+Shift+向上方向键:本行与上一行互换

    【Super的使用】

    ①子类重写的方法里面,调用父类被重写的方法:

    image.png

    image.png

    (6)面试题

    1、第一题

    如下代码输出结果是多少?

    package com.atguigu05._super.interview;
    
    /**
     * 判断运行结果
     *
     * @author 雨翼轻尘
     * @create 2023/11/5
     */
    public class Interview01 {
    
        public static void main(String[] args) {
            new A(new B());
        }
    }
    
    class A {
        public A() {
            System.out.println("A");
        }
    
        public A(B b) {
            this();
            System.out.println("AB");
        }
    }
    
    class B {
       public B() {
           System.out.println("B");
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    最终输出结果是:

    image.png

    分析一下,看图:

    image.png

    2、第二题

    如下代码输出结果是多少?

    package com.atguigu05._super.interview;
    
    /**
     * 判断运行结果
     *
     * @author 雨翼轻尘
     * @create 2023/11/5
     */
    public class Interview01 {
    
        public static void main(String[] args) {
            new A(new B());
        }
    }
    
    class A {
        public A() {
            System.out.println("A");
        }
    
        public A(B b) {
            this();
            System.out.println("AB");
        }
    }
    
    class B extends A{
        public B() {
            System.out.println("B");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    最终输出结果是:

    image.png

    分析一下,看图:

    image.png

    3、第三题

    如下代码输出结果是多少?

    package yuyi05;
    
    /**
     * @author 雨翼轻尘
     * @create 2023/11/5
     */
    public class Interview02{
            public static void main(String[] args) {
                Father f = new Father();
                Son s = new Son();
                System.out.println(f.getInfo());//atyuyi
                System.out.println(s.getInfo()); //atyuyi
                s.test();//atyuyi atyuyi
                System.out.println("-----------------");
                s.setInfo("轻尘");
                System.out.println(f.getInfo());//atyuyi
                System.out.println(s.getInfo());//轻尘
                s.test(); //轻尘 轻尘
        }
    }
    class Father{
        private String info = "atyuyi";
        public void setInfo(String info){
            this.info = info;
        }
        public String getInfo(){
            return info;
        }
    }
    class Son extends Father{
        private String info = "雨翼轻尘";
        public void test(){
            System.out.println(this.getInfo());
            System.out.println(super.getInfo());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    最终输出结果是:

    image.png

    分析一下,看图:


    image.png


    image.png


    image.png


    image.png

    4、第四题

    如下代码输出结果是多少?

    package yuyi05;
    
    /**
     * @author 雨翼轻尘
     * @create 2023/11/5
     */
    public class Interview02{
        public static void main(String[] args) {
            Father f = new Father();
            Son s = new Son();
            System.out.println(f.getInfo());//返回最近的info,即本类的"atyuyi"
            System.out.println(s.getInfo()); //返回最近的info,即本类的"雨翼轻尘"
            s.test();//“雨翼轻尘” atyuyi
            System.out.println("-----------------");
            s.setInfo("轻尘");
            System.out.println(f.getInfo());//atyuyi
            System.out.println(s.getInfo());//雨翼轻尘
            s.test(); //雨翼轻尘 轻尘
        }
    }
    class Father{
        private String info = "atyuyi";
        public void setInfo(String info){
            this.info = info;
        }
        public String getInfo(){
            return info;
        }
    }
    class Son extends Father{
        private String info = "雨翼轻尘";
        public void test(){
            System.out.println(this.getInfo());
            System.out.println(super.getInfo());
        }
        //重写
        public String getInfo(){
            return info;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    最终输出结果是:

    image.png

    分析一下,看图:


    image.png


    image.png

    二、子类对象实例化全过程

    (1)介绍

    调用子类构造器去创建对象的时候,会直接或间接地调用父类地构造器。

    整个过程其实可以理解为关于某个类的对象,在创建这个对象的过程当中是什么样的场景。
    image.png

    Dog dog = new Dog("小花","小红");
    
    • 1

    image.png

    (2)举例

    代码举例:

    class Creature{ //生物类
        //声明属性、方法、构造器
    }
    
    class Animal extends Creature{ //动物类
    
    }
    
    class Dog extends Animal{ //狗类
    
    }
    
    class DogTest{
        public static void main(String[] args){
            //子类对象DOg在实例化的过程当中整个过程是怎样的呢?
            Dog dog = new Dog();	//创建DOg的对象中,涉及到父类、父类的父类加载的过程?
    
            //通过dog调用属性、方法,只要是在Animal或Creature里面定义的属性、方法
            dog.xxx();
            
            dog.yyy = ...;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    image.png

    1. 从结果的角度来看:体现为类的继承性

    当我们创建子类对象后,子类对象就获取了其父类(所有父类,包括直接父类、间接父类)中声明的所有的属性和方法,在权限允许的情况下,可以直接调用。

    1. 从过程的角度来看:(继承性它在内存层面是怎么保证它是能够调用的)

    当我们通过子类的构造器创建对象时,子类的构造器一定会直接或间接地调用到其父类的构造器,而其父类的构造器同样会直接或间接地调用到其父类的构造器,…,直到调用了Object类中的构造器为止。

    正因为我们调用过子类所有的父类的构造器,所以我们就会将父类中声明的属性、方法加载到内存中,供子类的对象使用

    问题:在创建子类对象的过程中,一定会调用父类中的构造器吗? yes!
    先有父类的加载,才有子类的加载

    1. 问题:创建子类的对象时,内存中到底有几个对象?
      就只有一个对象(只new了一次)!即为当前new后面构造器对应的类的对象。

    ①造对象–>new

    ②构造器–>初始化


    叨叨:
    这一篇写累死我了,战线拉得很长,不过值得,有任何错误的地方欢迎指正

  • 相关阅读:
    c# Json转C#实体
    YOLOv5 PyQt5 | PyQt5快速入门 | 2/3
    C# 异步编程Invoke、beginInvoke、endInvoke的用法和作用
    23062C++&QTday5
    C# 图解教程 第5版 —— 第15章 事件
    什么?Postman也能测WebSocket接口了?
    vite+rollup
    1572.矩阵对角线元素的和
    [面试直通版]设计模式-2-
    ssm教务系统网站 毕业设计-附源码290915
  • 原文地址:https://blog.csdn.net/m0_55746113/article/details/134236895