第八章 面向对象编程(中级部分)——2

一、IDEA使用

二、包

三、访问修饰符

四、OOP三大特征(封装、继承和多态)

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

1.封装

(1)基本介绍

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

对电视机的操作就是典型的封装。

好处:
1)隐藏实现细节
2)可以对数据进行验证,保证安全合理

(2)实现步骤(三步)

1)将属性进行私有化——private(使不能直接修改属性)
2)提供一个公共的(public)set方法,用于对属性判断并赋值
        public void setXXX(类型 参数名){//XXX表示某个属性
                //加入数据验证的业务逻辑
                属性=参数名;
        }
3)提供一个公共的(public)get方法,用于获取属性的值
        public 数据类型 getXXX(){//权限判断,XXX某个属性
                return XXX;
        }

(3)快速入门

完成这样一个小程序:不能随便查看人的年龄、工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认年龄。年龄必须在1-120,年龄、工资不能直接查看,name的长度在2-6之间。

将构造器和setXXX结合:将set方法写进构造器,可以在使用构造器时也能验证信息。

package com.hspedu.encap;

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

        //如果使用构造器指定属性->设置的setXXX失效,无法对信息进行校验->将setXXX写进构造器
        Person smith = new Person("smith", 20, 50000);
        System.out.println("=====smith=======");
        System.out.println(smith.info());
    }
}

class Person {
    public String name;//名字公开
    private int age;//年龄私有化
    private double salary;//工资私有化

    //无参构造器
    public Person() {
    }

    //有3个参数的构造器
    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快捷键:alt+insert
    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;
    }
}

(4)课堂练习

com.hspedu.encap:AccountTest.java和Account.java
创建程序:在其中定义两个类:Account和AccountTest类体会Java的封装性。
1.Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、密码(必须是6位),如果不满足,则给出提示信息,并给默认值。
2.通过setXXX的方法给Account的属性赋值。
3.在AccountTest中测试

package com.hspedu.encap;

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account("xiaolin", 99.9, "8907789");
        System.out.println("====账户信息如下=====");
        System.out.println(account.info());
    }
}
package com.hspedu.encap;

public class Account {
    private String name;
    private double balance;
    private String password;

    public Account(String name, double balance, String password) {
        setName(name);
        setBalance(balance);
        setPassword(password);
    }

    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位");
            this.name = "无名";
        }
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        if(balance > 20) {
            this.balance = balance;
        } else {
            System.out.println("余额必须大于20");
            this.balance = 0000000000;
        }
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        if(password.length() == 6) {
            this.password = password;
        } else {
            System.out.println("密码应设置为6位");
            this.password = "000000";
        }
    }

    public String info() {
        return "姓名:" + this.name + " 余额:" + this.balance + " 密码:" + this.password;
    }
}

2.继承

(1)基本介绍

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

(2)基本语法

class 子类 extends 父类 {
}

1)子类就会自动拥有父类定义的属性和方法。
2)父类又叫超类、基类。
3)子类又叫派生类。

(3)快速入门

com.hspedu.extend_.improve_:Student.java
package com.hspedu.extend_.improve_;
//父类,是Pupil和Graduate的父类
public class Student {
    //共有属性
    public String name;
    public int age;
    private double score;

    //共有的方法
    //setScore:设置分数
    public void setScore(double score) {
        this.score = score;
    }

    //显示学生信息
    public void showInfo() {
        System.out.println("学生名:" + this.name + " 年龄:" + this.age + " 分数:" + score);
    }
}
com.hspedu.extend_.improve_:Graduate.java
package com.hspedu.extend_.improve_;

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

//让Pupil继承Student类
public class Pupil extends Student{
    //testing:小学生考试状态
    public void testing() {
        System.out.println("小学生" + this.name + "正在考小学数学...");
    }
}
com.hspedu.extend_.Pupil: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 = 10;
        pupil.testing();
        pupil.setScore(80);
        pupil.showInfo();

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

(4)继承给编程带来的便利

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

(5)细节

com.hspedu.extend_:Base.java(父类) Sub.java(子类) ExtendsDetail.java(主方法)

1)子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有的属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
2)子类必须调用父类的构造器,完成父类的初始化。
3)当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器。如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
4)如果希望指定去调用父类的某个构造器,则显式地调用一下:super(参数列表)。
5)super在使用时,必须放在构造器第一行。(super只能在构造器中使用)
  (先执行父类的构造器,再执行子类的构造器)
6)super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。
     如果构造器中有了this(),“默认调用父类的无参构造器”将失效。
7)java所有类都是Object类的子类,即Object是所有类的父类。
ctrl+H可以查看类的层级关系。
8)父类构造器的调用不限于直接父类,将一直往上追溯直到Object类(顶级父类)。

9)子类最多只能继承一个父类(指直接继承),即java中是单继承机制
思考:如何让A类继承B类和C类?【A继承B,B继承C】

10)不能滥用继承,子类和父类之间必须满足is-a的逻辑关系。
例如:Person is a Music?    Music extends Person;//不合理
           Cat is an Animal.  Cat extends Animal;//合理

(6)继承的本质分析

案例:
我们看一个案例来分析当子类继承父类,创建子类对象时,内存中到底发生了什么?
答:当子类对象创建好后,建立查找的关系。

子类创建的内存布局

流程:
1.先加载类信息(先加载父类,后加载子类)。
加载顺序:Object→GrandPa→Father→Son。
2.在堆中开辟空间。
....

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);//报错,因为父类中age是私有的,查找线路被堵住,爷类中的age是共有的却不会被访问到
        System.out.println(son.getAge());
        System.out.println(son.habby);//旅游
    }


}

class GrandPa {//爷类
    //成员变量(属性)
    String name = "大头爷爷";
    String habby = "旅游";
    int age = 80;
}

class Father extends GrandPa {//父类
    //成员变量(属性)
    String name = "大头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

class Son extends Father {//子类
    String name = "大头儿子";
}

(7)课堂练习

练习一:main方法中:B b = new B(); 会输出什么?

package com.hspedu.extend_.exercise;

public class ExtendsExercise01 {
    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");//因为有this(),故而不会调用A类的无参构造器
        System.out.println("b");
    }

    B(String name) {
        //默认调用A类的无参构造器
        System.out.println("b name");
    }
}

练习2:main方法中:C c = new C(); 输出什么内容?

package com.hspedu.extend_.exercise;

public class ExtendsExercise02 {
    public static void main(String[] args) {
        C c = new C();
    }
}

class A {
    public A() {
        System.out.println("我是A类");
    }
}

class B extends A {
    public B() {
        System.out.println("我是B类的无参构造");
    }

    public B(String name) {
        System.out.println(name + "我是B类的有参构造");
    }
}

class C extends B {
    public C() {
        this("hello");
        System.out.println("我是C类的无参构造");
    }

    public C(String name) {
        super("hahah");
        System.out.println("我是C类的有参构造");
    }
}

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

com.hspedu.extend_.exercise:Computer.java  PC.java  NotePad.java  ExtendsExercise.java
package com.hspedu.extend_.exercise;

public class Computer {
    //成员变量(属性)
    private String cpu;
    private int memory;
    private int disk;

    //构造器
    public Computer(String cpu, int memory, int disk) {
        this.cpu = cpu;
        this.memory = memory;
        this.disk = disk;
    }

    //成员方法
    //getDetails:返回Computer信息
    public String getDetails() {
        return "CPU:" + this.cpu + " Memory:" + this.memory + " HardDisk:" + this.disk;
    }

    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;
    }
}
com.hspedu.extend_.exercise:PC.java
package com.hspedu.extend_.exercise;

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);
    }
}
com.hspedu.extend_.exercise:NotePad.java
package com.hspedu.extend_.exercise;

public class NotePad extends Computer{
    //特有属性
    private String color;

    //构造器
    public NotePad(String cpu, int memory, int disk, String color) {
        super(cpu, memory, disk);
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void printInfo() {
        System.out.println("NotePad的信息:");
        System.out.println(getDetails() + " color:" + color);
    }


}
com.hspedu.extend_.exercise:ExtendsExercise.java
package com.hspedu.extend_.exercise;

public class ExtendsExercise03 {
    public static void main(String[] args) {
        PC pc = new PC("Intel", 128,24,"联想");
        pc.printInfo();
        NotePad notePad = new NotePad("Apple", 128,128,"银色");
        notePad.printInfo();
    }
}

五、Super关键字

1.基本介绍

super代表父类的引用,用于访问父类的属性、方法和构造器。

2.基本语法

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

(2)访问父类的方法,但不能访问父类的private方法。
        super.方法名;

(3)访问父类的构造器。
        super(参数列表);//只能放在构造器的第一句,只能出现一句!

com.hspedu.super_:A.java
package com.hspedu.super_;

public class A {
    public int n1 = 100;//public 同类 同包 子类 不同包
    protected int n2 = 200;//protected 同类 同包 子类
    int n3 = 300;//默认 同类 同包
    private int n4 = 400;//private 同类

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

    public void test100() {

    }
    protected void test200() {

    }
    void test300() {

    }
    private void test400() {

    }
}
com.hspedu.super_:B.java
package com.hspedu.super_;

public class B extends A {
    //访问父类的属性,但不能访问父类的private属性
    public void hi() {
        System.out.println(super.n1);
        System.out.println(super.n2);
        System.out.println(super.n2);
    }

    //访问父类的构造器:只能放在构造器地第一句,只能出现一句
    public B() {
//        super();//访问父类的无参构造器
//        super("王一博");//访问父类的一个参数构造器
        super("王一博", 27);//访问父类地两个参数构造器
    }

    //访问父类的方法,但不能访问父类的private方法
    public void ok() {
        super.test100();
        super.test200();
        super.test300();
    }
}

3.使用细节

(1)调用父类的构造器的好处:分工明确,父类属性由父类初始化,子类属性由子类初始化。
(2)当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果。
(3)super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。

        //say()和this.say()
        //(1)先找本类:如果有该方法,并且可以访问,则调用;如果没有,则查找父类
        //(2)查找父类:如果父类中有该方法,并且可以访问,则调用;如果没有,则查找父类的父类...直到Object类
        //提示1:如果有该方法,但却是私有的,则报错
        //提示2:如果查找到Object类,却仍旧没有找到该方法,则提示没有该方法
        say();
        this.say();

        //super.say()
        //直接查找父类中是否有该方法
        super.say();

4.super和this的比较

六、方法重写(overwrite)

七、Object类详解,垃圾回收机制

八、项目

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值