面向对象 这一文拿捏了 ⭐ (建议收藏)


面向对象中级部分已整理完成,建议收藏 🔴🟢🟡
在这里插入图片描述


访问修饰符

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

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

注意:

🔴 修饰符可以用来修饰类中的属性,成员方法以及类
🟢 只有默认的和public才可以修饰类!
🟡 成员方法的访问权限和属性完全一致


面向对象编程三大特征

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

封装

什么是封装?

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

封装的好处?

  • 隐藏实现细节
  • 可以对数据进行验证,保证安全合理

封装的实现步骤(3步)

  1. 将属性私有化 private
  2. 提供一个公用的 public 方法 set ,用于对属性判断并赋值
  3. 提供一个公用的 public 方法 get,用于获取属性的值

练习:对属性进行封装,并且对数据进行安全验证,从而体会封装的设计思想,两个类,一个供测试

1 用户类🔴🟢🟡

public class Account {
    private String name;
    private int balance;
    private String 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位到4位");
            this.name = "笨蛋";
        }
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        if(balance>=20){
            this.balance = balance;
        }else {
            System.out.println("余额最少为20");
        }
    }

    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 void info(){
        System.out.println("信息如下: "+" 名字:"+name+" 余额:"+balance+" 密码:"+password);
    }
}

2 测试类🔴🟢🟡

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account();
        account.info();
        account.setName("asdffggh");
        account.setBalance(1);
        account.setPassword("123");
        account.info();
        account.setName("liu");
        account.setBalance(2000);
        account.setPassword("123456");
        account.info();
    }
}

结果:
在这里插入图片描述


继承

为什么需要继承 ?

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

生活中的继承
在这里插入图片描述
语法

class 父类 {
}
 
class 子类 extends 父类 {
}

继承带来的好处

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

继承细节

  • 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访 问,要通过父类提供公共的方法去访问
  • 子类必须调用父类的构造器, 完成父类的初始化
  • 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译无法通过
  • 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
  • super 在使用时,必须放在构造器第一行,(super 只能在构造器中使用)
  • super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  • java 所有类都是 Object 类的子类, Object 是所有类的基类
  • 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
  • 子类最多只能继承一个父类(指直接继承),即 java 是单继承机制
  • 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系

继承的底层分析
在这里插入图片描述


super 关键字

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

this关键字:指向自己的引用
super关键字:用来引用当前对象的父类

super 的便利

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


方法重写/覆盖(override)

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!🔴🟢🟡

注意:子类方法不能缩小父类方法的访问权限

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

1.方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,称为方法的重载(Overloading)。
2.方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,称为重写(Overriding)。
3.方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。
在这里插入图片描述


多态

方法或对象具有多种形态,是面向对象的第三大特征
多态是建立在封装和继承基础之上的 🔴🟢🟡

重写和重载就体现多态,难点是对象的多态(熟记👇的话)

  • 一个对象的编译类型和运行类型可以不一致
  • 编译类型在定义对象时就确定了,不能改变
  • 运行类型是动态的,可变化的
  • 编译类型取决于定义时,=的左边,运行类型 =的右边

多态的前提是:两个对象(类)存在继承关系

向上转型

本质:父类引用指向了子类对象
语法:父类类型 引用名 = new 子类类型();
特点:编译类型看左边,运行类型看右边。 在访问权限允许可以调用父类的所有成员 不能调用子类中特有的成员 最终运行结果看子类的具体实现!

向下转型

本质:子类引用指向了父类
语法:子类类型 引用名 = (子类类型) 父类引用;
特点:只能强转父类的引用,不能强转父类的对象,要求父类的引用必须指向的是当前目标类型的对象,当向下转型时,可以调用子类类型中所有的成员

属性没有重写之说!属性的值看编译类型

instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX


Java 的动态绑定机制

Java 重要特性: 动态绑定机制 🔴🟢🟡

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/编译类型 进行动态绑定
  2. 当调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
🔴🟢🟡

Person[] persons = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("mary", 18, 100);
persons[2] = new Student("smith", 19, 30.1);
persons[3] = new Teacher("scot", 30, 10000);
persons[4] = new Teacher("king", 60, 20000);
System.out.println(persons[i].say());//动态绑定机制
//person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判段

person[i] 编译类型是 Person ,运行类型是是根据实际情况有 JVM 来判段


Object 类详解


== 和 equals 的对比

== 是一个比较运算符,可以判断基本以及引用类型,基本类型判断的是值相等,引用类型判断的是地址相等
equals 是 Object 类中的方法,只能用于引用类型,默认判断地址是否相等,实际上子类往往重写该方法,用于判断内容是否相等


如何重写 equals 方法
在这里插入图片描述

🔴🟢🟡

//重写 Object 的 equals 方法
public boolean equals(Object obj) {
//判断如果比较的两个对象是同一个对象,则直接返回 true
	if(this == obj) {
		return true;
	}
	//类型判断
	if(obj instanceof Person) {//是 Person,我们才比较

		//进行 向下转型, 因为我需要得到 obj 的 各个属性
		Person p = (Person)obj;
		return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
	}
	//如果不是 Person ,则直接返回 false
	return false;
}

hashCode 方法

在这里插入图片描述

  1. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
  2. 两个引用,如果指向的是不同对象,则哈希值是不一样的
  3. 哈希值主要根据地址号来的!不能认为哈希值等于地址

toString 方法
在这里插入图片描述1) 基本介绍
默认返回:全类名+@+哈希值的十六进制,子类往往重写 toString 方法,用于返回对象的属性信息
2) 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式
3) 当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(sb); 就会默认调用sb.toString()


finalize 方法

  1. 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作
  2. 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法。
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制
    在这里插入图片描述

零钱通项目

在这里插入图片描述
项目需求 :
防一个微信零钱通的压缩版,要实现文字界面,收益支出(支出细节)等的记录,对数据合法校验,比如没钱了,还消费就会提示,以及查看退出时提醒是否确定退出
项目思路 :
化繁为简,先使用判断以及分支语句,实现可以与用户互动的界面,然后依次实现对应的四个功能即可,最后做数据的校验以及函数的封装,界面优化,用户体验优化……过程中细节拉满,开始吧

具体实现 :

在这里插入图片描述


上代码

🔴🟢🟡

/**
 * @Author: liu sen
 * @Version: 1.0
 * @Date: 2021/09/01/23:34
 */
public class SmallChangeApp {
    public static class SmallChangeAPP {
        public static void main(String[] args) {
            new SmallchangeOOP().smallMenu();
        }
    }
}

🔴🟢🟡

/**
 * @Author: liu sen
 * @Version: 1.0
 * @Date: 2021/09/01/23:33
 */

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class SmallchangeOOP {
    //while循环开关
    boolean loop = true;
    //创建扫描器对象
    Scanner scanner = new Scanner(System.in);
    String key = "";
    String det = "================零钱通明细=================";
    //钱
    double money = 0;
    //余额
    double balance = 0;
    //时间
    Date date = null;
    //关于退出
    String k = "";

    //零钱通菜单,先实现选择骨架,然后分别实现对应方法,化繁为简
    public void smallMenu() {
        do {
            System.out.println("\n=================零钱通菜单=================");
            System.out.println("\t\t\t1. 明细");
            System.out.println("\t\t\t2. 收益入账");
            System.out.println("\t\t\t3. 消费");
            System.out.println("\t\t\t4. 退   出");

            System.out.print("请选择[1~4]: ");
            key = scanner.next();//接收输入
            //使用 switch 分支控制输入后的走向 接收参数 Key
            switch (key) {
                case "1": {
                    this.details();
                    break;
                }
                case "2": {
                    this.splicing();
                    break;
                }
                case "3": {
                    this.pay();
                    break;
                }
                case "4": {
                    this.exit();
                }
                default: {
                    System.out.println(" ");
                }
            }
        } while (loop);
        System.out.println("小猪,你已退出系统,再见 Bye~~~");
    }

    //明细方法
    public void details() {
        System.out.println(det);
    }

    //收入
    public void splicing() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//日期对象
        System.out.print("\n收益入账金额::");
        money = scanner.nextDouble();
        if (money <= 0) {
            System.out.println("弄啥来,输入不合法");
            return;
        }
        balance += money;
        date = new Date();
        det += "\n收益入账\t" + money + "\t" + sdf.format(date) + "\t" + balance;
    }

    //支出
    public void pay() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String str;
        System.out.print("消费金额:");
        money = scanner.nextDouble();
        System.out.print("消费详情:");
        if (money <= 0 || money > balance) {
            System.out.println("弄啥来,你丫的,好好输入");
            return;
        }
        str = scanner.next();
        balance -= money;
        //字符串拼接
        det += "\n" + str + "\t" + money + "\t" + sdf.format(date) + "\t" + balance;
    }

    //退出系统
    public void exit() {
        while (true) {
            System.out.println("小猪,确定要退出系统吗? y/n ");
            k = scanner.next();
            if ("y".equals(k) || "n".equals(k)) {
                break;
            } else {
                System.out.println("输入有误,重新输入");
            }
        }
        if (k.equals("y")) {
            loop = false;
        }
    }
}

收工!!!🔴🟢🟡

  • 39
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王子周棋洛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值