【Java复健指南06】OOP中级01-封装、继承、super

注:从OOP中级部分开始使用IDEA构建代码

封装

封装的实现步骤

1)将属性进行私有化private【不能直接修改属性】

2)提供一个公共的set方法,用于对属性判断并赋值

public void setXxx(类型参数名){
	//加入数据验证的业务逻辑
    //属性=参数名;
}

3)提供一个公共的get方法,用于获取属性的值

public XX getXxx(){//权限判断
	return xx;
}

示例

public class Encapsulation01 {
    /*
    在java中如何实现这种类似的控制呢?
    请编写一个小程序,不能随便查看人的年龄,工资等隐私,
    并对设置的年龄进行合理的验证。年龄合理就设置,
    否则给默认年龄,必须在1-120,
    年龄,工资不能直接查看﹐ name的长度在2-6字符之间
	*/
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("jack");
        person.setAge(18);
        person.setSal(8000);
        System.out.println(person.info());

    }
}
class Person{
    public String name;
    private int age;
    private double sal;

    //自己写set、get太慢,快捷键Alt+Ins,getter
    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字符间的名字,当前默认为sb");
            this.name = "sb";
        }

    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        //判断
        if(age >= 1 && age <= 120){
            this.age = age;
        }else {
            System.out.println("年龄需要在1-120之间,当前为默认年龄24");
            this.age = 24;//否则给个默认年龄
        }
    }
    public double getSal() {
        //可以增加对薪水查看权限的判断
        return sal;
    }

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

封装练习

创建程序,在其中定义两个类:Account和AccountTest类。

   1. Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>29)
   密码(必须是六位),如果不满足,则给出提示信息,并给默认值
   2. 通过setXxox的方法给Account的属性赋值。
   3. 在AccountTest中测试

Account.java

package com.Tsengstu.encap;

public class Account {
    //为了封装设置私有属性
    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;
    }
    //设置姓名要求
    public void setName(String name) {
        if(name.length() >= 2 && name.length() <= 4){
            this.name = name;
        }else {
            System.out.println("姓名(长度为2位3位或4位),当前默认值为ad");
            this.name = "ad";
        }

    }
    public double getBalance() {
        return balance;
    }
    //设置余额
    public void setBalance(double balance) {
        if(balance >= 20){
            this.balance = balance;
        }else {
            System.out.println("余额(必须>29),默认为0");
            this.balance = 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 +"密码"+pwd);
//        }else{
//            System.out.println("你无权查看..."");
//        }
    }
}

AccountTest.java

package com.Tsengstu.encap;

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account();
        account.setName("jk");
        account.setBalance(66);
        account.setPwd("123456");

        account.showInfo();
    }
}

继承

若两个类中的很多属性和方法相同,可以使用继承来提高代码的复用性。

当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。

继承的基本语法

class 子类 extends 父类{

}

1)子类就会自动拥有父类定义的属性和方法;

2)父类又叫超类,基类;

3)子类又叫派生类;

例子

现在有这些类,关系如下

image-20221017155708081

Student是pupil和graduate的父类

package com.Tsengstu.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);
    }
}

那么pupil和graduate可以通过extends关键字去继承父类的公共属性和方法,例如pupil

package com.Tsengstu.extend_.improve_;

public class Pupil extends Student{
    public void testing(){
        System.out.println("小学生"+name+"正在考小学语文");
    }
}

在测试类中可以调用如下

package com.Tsengstu.extend_;

public class Extends01 {
    public static void main(String[] args) {
        Pupil pupil = new Pupil();
        pupil.name ="小明";
        pupil.age = 10;
        pupil.testing();
        pupil.setScore(60);
        pupil.showInfo();
    }
}

继承的细节讨论

1.

子类继承了所有的属性和方法,但是私有属性和方法不能在子类直接访问(非私有可直接访问),要通过公共的方法去访问

例子

创建三个类:ExtendsDetail(用于测试)、Base(父类)、Sub(子类)

父类中定义如下

package com.Tsengstu.extend_;

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

    //父类提供一个公共方法返回私有属性(n4)
    public int getN4(){
        return n4;
    }
    //父类提供一个公共方法返回私有方法(test400())
    public void callTest400(){
        test400();
    }

    public Base() {//无参构造器
        System.out.println("Base()....");
    }
    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");
    }
}

子类定义如下,其中私有属性/方法无法直接访问,需要通过父类中的公共方法间接获取

public class Sub extends Base {
    public Sub() {//构造器
        System.out.println("sub()....");
    }
    public void say0k() {//子类方法
        //非私有的属性和方法可以在子类直接访间
        System.out.println(n1 + " "+n2 + " "+n3 + " ");//私有的n4用不了
        test100();
        test200();
        test300();//私有的test400()用不了
        //可通过父类提供的公共方法去访问私有属性和方法
        System.out.println("n4= " + getN4());
        callTest400();
    }
}

测试

public class ExtendsDetail {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.say0k();
        sub.callTest400();
    }
}
2.

子类必须调用父类的构造器,完成父类的初始化

image-20221017165200354

其实是因为在子类构造器中会默认存在"super();"(写不写都有)

其会去初始化父类的构造器,利用这点可以加载一些父类的参数

3.

当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,

如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过[举例说明]

4.

如果希望制定调用父类的某个构造器,则显式的调用一下

5.

super在使用时需要放在构造器的第一行

6.

super()和this()都需要放在构造器的第一行,且不能同时出现

7.

java所有类都是Object类的子类

8.

父类的调用不仅限于父类,会一直向上追溯到Object类(顶级父类)

子类最多只能继承一个父类(指直接继承),即java中是单继承机制

思考,如何让A类继承B类和C类?先让A继承B,再让B继承C

继承练习题

一、"this()"与"super();"

public class ExtendsExercise01 {
    public static void main(String[] args) {
        /*
        * 解析
        * 创建对象b,会先调用B类的无参构造器B()
        * 在无参构造器中有个this("abc")【有this无super】
        * 相当于去调用本类中带参数的构造器B(String name)
        * 然后该构造器中会有一个默认的"super();"去初始化其继承的父类的构造器
        * 于是调用了A()
        * 那么输出结果应该是
        * a
          b name
          b
        * */
        B b = new 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){
        System.out.println("b name");
    }
}

主要体现了继承中向上索引和子类默认有super();的机制

二、

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

public class ExtendsExercise02 {
    public static void main(String[] args) {
        //非要写个测试类也行,保证在同一个包下就行,这里直接在一个类里写了
        Computer computer = new Computer("i9-13110K","64G 5899MHz", "8T");
        System.out.println(computer.getDetails());
        PC pc = new PC("i9-13110K","64G 5899MHz", "8T", "ROG",25999);
        System.out.println(pc.getDetails());
        NotePad notePad = new NotePad("M1 Max","12G", "512GB","black", 8.5);
        System.out.println(notePad.getDetails());

    }
}

class Computer{
    String CPU;
    String RAM;
    String HDD;

    public Computer() {
    }

    public Computer(String CPU, String RAM, String HDD) {
        this.CPU = CPU;
        this.RAM = RAM;
        this.HDD = HDD;
    }

    public String getDetails(){
        return "电脑CPU: "+CPU+" 运行内存: "+RAM+" 硬盘容量: "+HDD;
    }
}

class PC extends Computer{
    String brand;
    int price;

    public PC(){

    }

    public PC(String brand, int price){
        this.brand = brand;
        this.price = price;
    }

    public PC(String CPU, String RAM, String HDD, String brand, int price){
        super(CPU, RAM, HDD);//用this也行
        this.brand = brand;
        this.price = price;
    }

    public String getDetails(){
        return "笔记本电脑CPU: "+CPU+" 运行内存: "+RAM+" 硬盘容量: "+HDD+" 笔记本电脑品牌: "+brand+" 笔记本电脑价格: "+price;
    }
}

class NotePad extends Computer{
    String color;
    double screen_inch;

    public NotePad(){

    }

    public NotePad(String color, double screen_inch) {
        this.color = color;
        this.screen_inch = screen_inch;
    }

    public NotePad(String CPU, String RAM, String HDD, String color, double screen_inch){
        super(CPU, RAM, HDD);
        this.color = color;
        this.screen_inch = screen_inch;
    }

    public String getDetails(){
        return "平板电脑CPU: "+CPU+" 运行内存: "+RAM+" 硬盘容量: "+HDD+" 平板电脑颜色: "+color+" 平板电脑尺寸: "+screen_inch;
    }
}

Super

基本介绍

​ super代表父类的引用,用于访问父类的属性、方法、构造器基本语法

1.访问父类的属性,但不能访问父类的private属性
super.属性名;

  1. 访问父类的方法,不能访问父类的private方法
    super.方法名(参数列表);
  2. 访问父类的构造器(这点前面用过):
    super(参数列表);只能放在构造器的第一句,只能出现一句

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

  1. 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子
    类初始化)

  2. 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须
    通过super。如果没有重名,使用super、this、直接访问是一样的效果!

  3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用
    super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则

A->B->C

super和this的区别和使用

https://www.cnblogs.com/cyy9310/p/16150776.html

image-20221019130842772

posted @ 2022-10-19 13:12  dayceng  阅读(28)  评论(0编辑  收藏  举报