java学习笔记(8) 第8章(上)- 面向对象编程(中级部分)

8.1 IDE(集成开发环境)-IDEA

8.1.1IDEA 介绍

  1. IDEA 全称IntelliJ IDEA
  2. 在业界被公认为最好的Java 开发工具
  3. IDEA 是JetBrains 公司的产品,总部位于捷克的首都布拉格
  4. 除了支持Java 开发,还支持HTML,CSS,PHP,MySQL,Python 等

8.2 IDE(集成开发环境)-Eclipse

8.2.1Eclipse 介绍

  1. Eclipse 是一个开放源代码的、基于Java 的可扩展开发平台。
  2. 最初是由IBM 公司耗资3000 万美金开发的下一代IDE 开发环境
  3. 2001 年11 月贡献给开源社区
  4. Eclipse 是目前最优秀的Java 开发IDE 之一

8.3 IDE(集成开发环境)-IDEA 的使用

8.3.1 IDEA 的安装+pj教程

https://blog.csdn.net/m0_50736744/article/details/121272313

8.3.2 IDEA 使用技巧和经验

  • 设置字体和颜色主题

    菜单file -> settings
    菜单file -> Apprarance在这里插入图片描述

  • 字符编码设置,默认就是UTF-8。
    在这里插入图片描述

8.3.3 课堂练习

使用IDEA 开发一个java 项目testpro01,创建一个类MyTools, 编写一个方法,可以完成对int 数组冒泡排序的功能。
学员练习, 使用快捷键的开发项目
在这里插入图片描述

8.3.4 IDEA 常用快捷键

  1. 删除当前行, 默认是ctrl + Y 自己配置ctrl + d
  2. 复制当前行, 自己配置ctrl + alt + 向下光标
  3. 补全代码alt + /
  4. 添加注释和取消注释ctrl + / 【第一次是添加注释,第二次是取消注释】
  5. 导入该行需要的类先配置auto import , 然后使用alt+enter 即可
  6. 快速格式化代码ctrl + alt + L
  7. 快速运行程序自己定义alt + R
  8. 生成构造器等alt + insert [提高开发效率]
  9. 查看一个类的层级关系ctrl + H [学习继承后,非常有用]
  10. 将光标放在一个方法上,输入ctrl + B 或者 ctrl+鼠标左键 , 可以定位到方法[学继承后,非常有用]
  11. 自动的分配变量名, 通过在后面加.var 或者 Alt+回车[老师最喜欢的]
  12. 还有很多其它的快捷键…
  13. redo撤销重做,默认ctrl+shift+z,修改成ctrl+y;

8.3.5 模板/自定义模板

在这里插入图片描述

8.4 包

8.4.1看一个应用场景

现在有两个程序员共同开发一个java项目,程序员xiaoming希望定义一个类取名Dog ,程序员xiaoqiang也想定义一个类也叫 Dog。两个程序员为此还吵了起来,怎么办?–>包

8.4.2包的三大作用

  1. 区分相同名字的类
  2. 当类很多时,可以很好的管理类[看Java API文档]
  3. 控制访问范围

8.4.3包基本语法

在这里插入图片描述

8.4.4包的本质分析(原理)

在这里插入图片描述

8.4.5 快速入门

在这里插入图片描述

8.4.6 包的命名

在这里插入图片描述

8.4.7常用的包

一个包下,包含很多的类,java 中常用的包有:

  1. java.lang.* //lang 包是基本包,默认引入,不需要再引入.

    例如求-1 的绝对值:Math.abs(-1),直接用 不用在代码前边import引入
    例如:Math.PI

  2. java.util.* //util 包,系统提供的工具包, 工具类,使用Scanner

  3. java.net.* //网络包,网络开发

  4. java.awt.* //是做java 的界面开发,GUI

8.4.8 如何引入包

com.hspedu.pkg : lmport01.java
语法: import 包;
我们引入一个包的主要目的是要使用该包下的类
比如import java.util.Scanner;就只是引入一个类Scanner。
import java.util.*;1/表示将java.util包所有都引入
建议:我们需要使用到哪个类,就导入哪个类即可,不建议使用 *导入

package com.hspedu.pkg;
import java.util.Arrays;

//import java.util.Scanner; //表示只会引入java.util 包下的 Scanner
//import java.util.*;//表示将java.util 包下的所有类都引入(导入)
public class Import01 {

    public static void main(String[] args) {

        //使用系统提供 Arrays 完成 数组排序
        int[] arr = {-1, 20, 2, 13, 3};
        //比如对其进行排序
        //传统方法是,自己编写排序(冒泡)
        //系统是提供了相关的类,可以方便完成 Arrays
        Arrays.sort(arr);
        //输出排序结果
        for (int i = 0; i < arr.length ; i++) {
            System.out.print(arr[i] + "\t");
        }
    }
}

8.4.9 注意事项和使用细节

pkgDetail.java

  1. package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package。
  2. import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。
//package的作用是声明当前类所在的包,需要放在类(或者文件)的最上面,
// 一个类中最多只有一句package

package com.hspedu.pkg;

//import指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求
import java.util.Scanner;
import java.util.Arrays;

//类定义
public class PkgDetail {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] arr = {0, -1, 1};
        Arrays.sort(args);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

8.5 访问修饰符

8.5.1基本介绍

java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):

  1. 公开级别:用public 修饰,对外公开
  2. 受保护级别:用protected 修饰,对子类和同一个包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开.
  4. 私有级别:用private 修饰,只有类本身可以访问,不对外公开.

8.5.2 4种访问修饰符的访问范围

背下来
在这里插入图片描述

  1. 修饰符可以用来修饰类中的属性,成员方法以及类
  2. 只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。
  3. 因为没有学习继承,因此关于在子类中的访问权限,我们讲完子类后,再回头讲解
  4. 成员方法的访问规则和属性完全一样.
    //com.hspedu.modifier:需要很多文件来说明(A类,B类, Test类…)

modifier包中的A类:

package com.hspedu.modifier;
public class A {

    //四个属性,分别使用不同的访问修饰符来修饰
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;
    public void m1() {
        //在同一类中,可以访问public protected 默认 private 修饰属性和方法
        System.out.println("n1=" + n1 + " n2=" + n2 + " n3=" + n3 + " n4=" + n4);
    }
    protected void m2() { }
    void m3() { }
    private void m4() { }
    public void hi() {
        //在同一类中,可以访问public protected 默认 private 修饰属性和方法
        m1();
        m2();
        m3();
        m4();
    }
}

modifier包中的B类:

package com.hspedu.modifier;

public class B {
    public void say() {
        A a = new A();
        //在同一个包下,可以访问 public , protected 和 默认修饰属性或方法,不能访问private 属性或方法
        System.out.println("n1=" + a.n1 + " n2=" + a.n2 +  " n3=" + a.n3 );

        a.m1();
        a.m2();
        a.m3();
        //a.m4(); 错误的
    }
}

modifier包中的主类Test:

package com.hspedu.modifier;

public class Test {
    public static void main(String[] args) {
        A a = new A ();
        a.m1();
        B b = new B();
        b.say();
    }
}
//只有 默认和public 可以修饰类
class Tiger{ }

pkg包里的主类:(不同包)

package com.hspedu.pkg;

import com.hspedu.modifier.A;

public class Test {
    public static void main(String[] args) {
        A a = new A();
        //在不同包下,可以访问public 修饰的属性或方法
        //但是不能访问 protected ,默认,private修饰的属性或方法
        System.out.println(a.n1);

        a.m1();
        //不能访问 a.m2() a.m3() a.m4()
    }
}

8.6 面向对象编程三大特征

面向对象编程有三大特征:封装、继承和多态。

8.6.1 封装介绍

封装(encapsulation)就是把抽象出的数据[属性] 和对数据的操作[方法] 封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。

8.6.2 封装的理解和好处

  1. 隐藏实现细节:方法(连接数据库)<–调用(传入参数…)
  2. 可以对数据进行验证,保证安全合理
    Person {name, age]
    Person p = new Person();
    p.name = “jack” ;
    p.age = 1200; //(有人活1200岁不合理)

8.6.3 封装的实现步骤(三步)

在这里插入图片描述

8.7 快速入门案例

请大家看一个小程序(com.hspedu.encap: Encapsulation01.java),不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认年龄,必须在1-120,年龄,工资不能直接查看,name的长度在2-6字符之间。

package com.hspedu.encap;

public class Encapsulation01 {

    public static void main(String[] args) {
        //如果要使用快捷键alt+r, 需要先配置主类
        //第一次,我们使用鼠标点击形式运算程序,后面就可以用
        Person person = new Person();
        person.setName("韩顺平");
        person.setAge(30);
        person.setSalary(30000);
        System.out.println(person.info());
        System.out.println(person.getSalary());

        //如果我们自己使用构造器指定属性
        Person smith = new Person("smith", 800, 50000);
        System.out.println("====smith的信息======");
        System.out.println(smith.info());


    }
}
/*
那么在java中如何实现这种类似的控制呢?
请大家看一个小程序(com.hspedu.encap: Encapsulation01.java),
不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
年龄, 必须在 1-120, 年龄, 工资不能直接查看 , name的长度在 2-6字符 之间

 */
class Person {
    public  String name; //名字公开
    private int age; //age 私有化
    private double salary; //..

    public void say(int n,String name) {

    }
    //构造器 alt+insert
    public Person() {
    }
    //有三个属性的构造器
    public Person(String name, int age, double salary) {
//        this.name = name;
//        this.age = age;
//        this.salary = salary;
        //我们可以将set方法写在构造器中,这样仍然可以验证
        setName(name);
        setAge(age);
        setSalary(salary);
    }

    //自己写setXxx 和 getXxx 太慢,我们使用快捷键
    //然后根据要求来完善我们的代码.
    public String getName() {
        return name;
    }
    public void setName(String name) {
        //加入对数据的校验,相当于增加了业务逻辑
        if(name.length() >= 2 && name.length() <=6 ) {
            this.name = name;
        }else {
            System.out.println("名字的长度不对,需要(2-6)个字符,默认名字");
            this.name = "无名人";
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        //判断
        if(age >= 1 && age <= 120) {//如果是合理范围
            this.age = age;
        } else {
            System.out.println("你设置年龄不对,需要在 (1-120), 给默认年龄18 ");
            this.age = 18;//给一个默认年龄
        }
    }

    public double getSalary() {
        //可以这里增加对当前对象的权限判断
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
    //写一个方法,返回属性信息
    public String info() {
        return "信息为 name=" + name  + " age=" + age + " 薪水=" + salary;
    }
}

8.7.1 将构造器和setXxx 结合

有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
//我们可以将set 方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}

8.7.2 课堂练习

在这里插入图片描述

public class TestAccount {
    public static void main(String[] args) {
        //创建Account
        Account account = new Account();
        account.setName("jack");
        account.setBalance(60);
        account.setPwd("123456");
        account.showInfo();

        //如果我们自己使用构造器指定属性
        Account cm = new Account("cm", 25, "111111");
        cm.showInfo();
    }
}

/**
 * 创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
 * Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、
 * 密码(必须是六位), 如果不满足,则给出提示信息,并给默认值(程序员自己定)
 * 通过setXxx的方法给Account 的属性赋值。
 * 在AccountTest中测试
 */
public class Account {
    //为了封装,将3个属性设置为private
    private String name;
    private double balance;
    private String pwd;

    //提供两个构造器
    public Account() {
    }

    public Account(String name, double balance, String pwd) {
        this.setName(name);
        this.setBalance(balance);
        this.setPwd(pwd);
    }

    public String getName() {
        return name;
    }

    //姓名(长度为2位3位或4位)
    public void setName(String name) {
        if (name.length() >= 2 && name.length() <= 4) {
            this.name = name;
        } else {
            System.out.println("姓名要求(长度为2位3位或4位),默认值 无名");
            this.name = "无名";
        }
    }

    public double getBalance() {
        return balance;
    }

    //余额(必须>20)
    public void setBalance(double balance) {
        if (balance > 20) {
            this.balance = balance;
        } else {
            System.out.println("余额(必须>20) 默认为0");
        }
    }

    public String getPwd() {
        return pwd;
    }

    //密码(必须是六位)
    public void setPwd(String pwd) {
        if (pwd.length() == 6) {
            this.pwd = pwd;
        } else {
            System.out.println("密码(必须是六位)默认密码为 000000");
            this.pwd = "000000";
        }
    }
    //显示账号信息
    public void showInfo() {
        //可以增加权限的校验
        System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码" + pwd);
//        if() {
//            System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码");
//        }else{
//            System.out.println("你无权查看...");
//        }
    }
}

8.8 面向对象编程-继承

8.8.1 为什么需要继承

在这里插入图片描述

8.8.2 继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends 来声明继承父类即可。画出继承的示意图
在这里插入图片描述

8.8.3 继承的基本语法

在这里插入图片描述

8.8.4 快速入门案例

我们对Extends01.java 改进,使用继承的方法,请大家注意体会使用继承的好处

package com.hspedu.extend_.improve_;
import com.hspedu.extend_.Graduate;
import com.hspedu.extend_.Pupil;

public class Extends01 {
    public static void main(String[] args) {
        com.hspedu.extend_.Pupil pupil = new Pupil();
        pupil.name = "银角大王~";
        pupil.age = 11;
        pupil.testing();
        pupil.setScore(50);
        pupil.showInfo();

        System.out.println("=======");
        com.hspedu.extend_.Graduate graduate = new Graduate();
        graduate.name = "金角大王~";
        graduate.age = 23;
        graduate.testing();
        graduate.setScore(80);
        graduate.showInfo();
    }
}

package com.hspedu.extend_.improve_;
//父类,是Pupil 和 Graduate的父类
public class Student {
    //共有属性
    public String name;
    public int age;
    private double score;//成绩
    //共有的方法
    public void setScore(double score) {
        this.score = score;
    }

    public void showInfo() {
        System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
    }
}

package com.hspedu.extend_.improve_;
//让Pupil 继承 Student类
public class Pupil extends Student {
    public void testing() {
        System.out.println("小学生 " + name + "  正在考小学数学..");
    }
}

package com.hspedu.extend_.improve_;
//让Graduate继承 Student 类
public class Graduate extends Student {

    public void testing() {//和Pupil不一样
        System.out.println("大学生 " + name + " 正在考大学数学..");
    }
}

8.8.5 继承给编程带来的便利

  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了

8.8.6 继承的深入讨论/细节问题

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问.[代码演示]
  2. 子类必须调用父类的构造器, 完成父类的初始化。
  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解。) [举例说明]
  4. 如果希望指定去调用父类的某个构造器,则显式的调用一下: super(参数列表)
  5. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
  6. super() 和this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  7. java 所有类都是Object 类的子类, Object 是所有类的基类.
  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到Object 类(顶级父类)
  9. 子类最多只能继承一个父类(指直接继承),即java 中是单继承机制
    思考:如何让A 类继承B 类和C 类? 【先让A 继承B,再让B 继承C】
  10. 不能滥用继承,子类和父类之间必须满足is-a 的逻辑关系
    代码
//package com.hspedu.extend_;
//第1,主类。
public class ExtendsDetail {
    public static void main(String[] args) {
//        System.out.println("===第1个对象====");
//        Sub sub = new Sub(); //创建了子类对象 sub
//        sub.sayOk();

//        System.out.println("===第2个对象====");
//        Sub sub2 = new Sub("jack"); //创建了子类对象 sub2

        System.out.println("===第3对象====");
        Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
    }
}


//第2,父类。
//package com.hspedu.extend_;
public class Base extends TopBase { //父类
    //4个属性
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public Base() { //无参构造器
        System.out.println("父类Base()构造器被调用....");
    }
    public Base(String name, int age) {//有参构造器
        //默认super()
        System.out.println("父类Base(String name, int age)构造器被调用....");
    }
    public Base(String name) {//有参构造器
        System.out.println("父类Base(String name)构造器被调用....");
    }
    //父类提供一个public的方法,返回了n4
    public int getN4() {
        return n4;
    }
    public void test100() {
        System.out.println("test100");
    }
    protected void test200() {
        System.out.println("test200");
    }
    void test300() {
        System.out.println("test300");
    }
    private void test400() {
        System.out.println("test400");
    }
    //call
    public void callTest400() {
        test400();
    }
}

//第3,子类。
//package com.hspedu.extend_;
import java.util.Arrays;

//输入ctrl + H 可以看到类的继承关系
public class Sub extends Base { //子类

    public Sub(String name, int age) {
        //1. 老师要调用父类的无参构造器, 如下或者 什么都不写,默认就是调用super()
        //super();//父类的无参构造器
        //2. 老师要调用父类的 Base(String name) 构造器
        //super("hsp");
        //3. 老师要调用父类的 Base(String name, int age) 构造器
        super("king", 20);

        //细节: super在使用时,必须放在构造器第一行
        //细节: super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
        //this() 不能再使用了
        System.out.println("子类Sub(String name, int age)构造器被调用....");
    }

    public Sub() {//无参构造器
        //super(); //默认调用父类的无参构造器,写不写都存在
        super("smith", 10);
        System.out.println("子类Sub()构造器被调用....");
    }
    //当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
    public Sub(String name) {
        super("tom", 30);
        //do nothing...
        System.out.println("子类Sub(String name)构造器被调用....");
    }

    public void sayOk() {//子类方法
        //非私有的属性和方法可以在子类直接访问
        //但是私有属性和方法不能在子类直接访问
        System.out.println(n1 + " " + n2 + " " + n3);//属性,再写n4就报错
        test100();
        test200();
        test300();
        //test400();方法,错误
        //要通过父类提供公共的方法去访问
        System.out.println("n4=" + getN4());
        callTest400();//
    }
}

//第4 顶级类Object
//package com.hspedu.extend_;
public class TopBase { //父类是Object
    public TopBase() {
        //super(); Object的无参构造器
        System.out.println("构造器TopBase() 被调用...");//1
    }
}

8.8.7 继承的本质分析(重要)

在这里插入图片描述

package com.hspedu.extend_;

/**
 * 讲解继承的本质
 */
public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();//内存的布局
        //?-> 这时请大家注意,要按照查找关系来返回信息
        //(1) 首先看子类是否有该属性
        //(2) 如果子类有这个属性,并且可以访问,则返回信息
        //(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
        //(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
        System.out.println(son.name);//返回就是大头儿子
        //System.out.println(son.age);//返回的就是39
        System.out.println(son.getAge());//返回的就是39
        System.out.println(son.hobby);//返回的就是旅游
    }
}

class GrandPa { //爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}

class Father extends GrandPa {//父类
    String name = "大头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

class Son extends Father { //子类
    String name = "大头儿子";
}
  • 子类创建的内存布局

在这里插入图片描述
注意:
要按照查找关系来返回信息
(1) 首先看子类是否有该属性
(2) 如果子类有这个属性,并且可以访问,则返回信息
(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息…)
(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object…

8.8.8 课堂练习

  1. 案例1 ExtendsExercise01.java
public class zuoye {
    public static void main(String[] args) {
    
        B b=new B();//a , b name, b
    }
}

class A {
    A() { //父类的无参构造器
        System.out.println("a");
    }

    A(String name) {
        System.out.println("a name");
    }
}

class B extends A {
    B() {
        this("abc");
        System.out.println("b");
    }

    B(String name) {
        //默认有 super();
        System.out.println("b name");
    }
}
  1. 案例2
    在这里插入图片描述

  2. 案例3 ExtendsExercise03.java

    编写Computer 类,包含CPU、内存、硬盘等属性,getDetails 方法用于返回Computer 的详细信息
    编写PC 子类,继承Computer 类,添加特有属性【品牌brand】
    编写NotePad 子类,继承Computer 类,添加特有属性【color】
    编写Test 类,在main 方法中创建PC 和NotePad 对象,分别给对象中特有的属性赋值,以及从Computer 类继承的属性赋值,并使用方法并打印输出信息。

package com.hspedu.extend_.exercise;

//编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
public class Computer {
    private String cpu; //没啥要求就private
    private int memory;
    private int disk;
    
    public Computer(String cpu, int memory, int disk) {//有参构造器
        this.cpu = cpu;
        this.memory = memory;
        this.disk = disk;
    }
    //返回Computer信息
    public String getDetails() { //方法
        return "cpu=" + cpu + " memory=" + memory + " disk=" + disk;
    }

//因为是私有,快捷键插入get set
    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public int getMemory() {
        return memory;
    }
    public void setMemory(int memory) {
        this.memory = memory;
    }

    public int getDisk() {
        return disk;
    }
    public void setDisk(int disk) {
        this.disk = disk;
    }
}
package com.hspedu.extend_.exercise;

//编写PC子类,继承Computer类,添加特有属性【品牌brand】

public class PC extends Computer{

    private String brand;
    //这里IDEA 根据继承的规则,自动把构造器的调用写好
    //这里也体现: 继承设计的基本思想,父类的构造器完成父类属性初始化
    //子类的构造器完成子类属性初始化
    public PC(String cpu, int memory, int disk, String brand) {
        super(cpu, memory, disk);
        this.brand = brand;
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public void printInfo() {
        System.out.println("PC信息=");
//        System.out.println(getCpu() + getMemory() + getDisk());
        //调用父类的getDetails方法,得到相关属性信息..
        System.out.println(getDetails() + " brand=" + brand);
    }
}
package com.hspedu.extend_.exercise;

public class ExtendsExercise03 {
    public static void main(String[] args) {
        PC pc = new PC("intel", 16, 500, "IBM");
        pc.printInfo();
    }
}

8.9 super 关键字

  • 基本介绍
    super 代表父类的引用,用于访问父类的属性、方法、构造器
  • 基本语法
    在这里插入图片描述

8.9.1 super 给编程带来的便利/细节

  1. 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子
    类初始化)。
  2. 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须
    通过super。如果没有重名,使用super、this、直接访问是一样的效果![举例]
  3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用
    super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则

注意1:A是父类,里边有个 cal 方法。B是子类。 希望子类B调用父类A 的cal方法。规则如下:

     这时,因为子类B没有cal方法,因此我可以使用下面三种方式
     找cal方法时(cal() 和 this.cal()),顺序是:
     (1)先找本类,如果有,则调用
     (2)如果没有,则找父类(如果有,并可以调用,则调用)
     (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
   提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
         如果查找方法的过程中,没有找到,则提示方法不存在
    // cal();
    this.cal(); //等价 cal()
    
    //(super.call()) 找cal方法的顺序是直接查找父类,本类的cal不会调用,其他的规则一样
    super.cal();

注意2:A是父类,里边有个 n1 属性。B是子类。 希望子类B调用父类A 的 n1 属性。规则如下:

    演示访问属性的规则
    n1 和 this.n1 查找的规则是
    (1) 先找本类,如果有,则调用
    (2) 如果没有,则找父类(如果有,并可以调用,则调用)
    (3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
     提示:如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
           如果查找属性的过程中,没有找到,则提示属性不存在
    System.out.println(n1);
    System.out.println(this.n1);

    // (super.n1) 找n1的顺序是直接查找父类属性,其他的规则一样
    System.out.println(super.n1);

代码:

package com.hspedu.super_;
public class Base { //父类是Object

    public int n1 = 999;
    public int age = 111;
    public void cal() {
        System.out.println("Base类的cal() 方法...");
    }
    public void eat() {
        System.out.println("Base类的eat().....");
    }
}
package com.hspedu.super_;

public class A extends Base{
    //4个属性
    //public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public A() {}
    public A(String name) {}
    public A(String name, int age) {}

//    public void cal() {  //计算方法
//        System.out.println("A类的cal() 方法...");
//    }

    public void test100() {
    }

    protected void test200() {
    }

    void test300() {
    }

    private void test400() {
    }
}
package com.hspedu.super_;

public class B extends A {

    public int n1 = 888;

    //编写测试方法
    public void test() {
        //super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;
        // 如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C

        System.out.println("super.n1=" + super.n1);
        super.cal();
    }

    //访问父类的属性 , 但不能访问父类的private属性 [案例]super.属性名
    public void hi() {
        System.out.println(super.n1 + " " + super.n2 + " " + super.n3 );
    }
    public void cal() {
        System.out.println("B类的cal() 方法...");
    }

    public void sum() {
        System.out.println("B类的sum()");
        //希望调用父类-A 的cal方法
        //这时,因为子类B没有cal方法,因此我可以使用下面三种方式

        //找cal方法时(cal() 和 this.cal()),顺序是:
        // (1)先找本类,如果有,则调用
        // (2)如果没有,则找父类(如果有,并可以调用,则调用)
        // (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
        // 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
        //      如果查找方法的过程中,没有找到,则提示方法不存在
        //cal();
        this.cal(); //等价 cal()

        //找cal方法(super.call()) 的顺序是直接查找父类,本类的cal不会调用,其他的规则一样
        //super.cal();

        //演示访问属性的规则
        //n1 和 this.n1 查找的规则是
        //(1) 先找本类,如果有,则调用
        //(2) 如果没有,则找父类(如果有,并可以调用,则调用)
        //(3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
        // 提示:如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
        //      如果查找属性的过程中,没有找到,则提示属性不存在
        System.out.println(n1);
        System.out.println(this.n1);

        //找n1 (super.n1) 的顺序是直接查找父类属性,其他的规则一样
        System.out.println(super.n1);

    }
    //访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
    public void ok() {
        super.test100();
        super.test200();
        super.test300();
        //super.test400();//不能访问父类private方法
    }
    //访问父类的构造器(这点前面用过):super(参数列表);只能放在构造器的第一句,只能出现一句!
    public  B() {
        //super();调父类的无参构造器
        //super("jack", 10);调父类的第3个构造器
        super("jack"); //调父类的第2构造器
    }
}
package com.hspedu.super_;

public class Super01 {
    public static void main(String[] args) {
        B b = new B();//子类对象
        b.sum();
       // b.test();
    }
}

8.9.2 super 和this 的比较

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值