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

简介: 面向对象中级部分已整理完成,建议收藏 🔴🟢🟡

文章目录


访问修饰符


面向对象编程三大特征


封装


继承


super 关键字


方法重写/覆盖(override)


多态


Java 的动态绑定机制


多态数组


Object 类详解


零钱通项目


访问修饰符



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


公开级别: 用 public 修饰,对外公开


受保护级别: 用 protected 修饰,对子类和同一个包中的类公开


默认级别: 没修饰符号,向同一个包的类公开


私有级别: 用 private 修饰,只有类本身可以访问,不对外公开


修饰符 同类 同包 子类) 其他包

public Y Y Y Y

protected Y Y Y N

default Y Y N N

private Y N N N


修饰符 同类 同包 子类) 其他包
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N


注意:


🔴 修饰符可以用来修饰类中的属性,成员方法以及类

🟢 只有默认的和public才可以修饰类!

🟡 成员方法的访问权限和属性完全一致


面向对象编程三大特征


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


封装


什么是封装?


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


封装的好处?


隐藏实现细节

可以对数据进行验证,保证安全合理

封装的实现步骤(3步)


将属性私有化 private

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

提供一个公用的 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();
    }
}


结果:


b73eaf0953e84c0a9c59341f50e642d8.png


继承


为什么需要继承 ?


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


生活中的继承


c060811085dd4c4b9f3f613b457195fb.png


语法


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


继承带来的好处


代码的复用性提高了

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


继承细节


子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性

和方法不能在子类直接访 问,要通过父类提供公共的方法去访问


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


当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译无法通过


如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)


super 在使用时,必须放在构造器第一行,(super 只能在构造器中使用)


super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器


java 所有类都是 Object 类的子类, Object 是所有类的基类


父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)


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

不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系


继承的底层分析


8d2591dd63cb4ce4a5be8cead8235f1d.png


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.方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。


32a14fb3392049b4804b7fd48de4e6da.png


多态


方法或对象具有多种形态,是面向对象的第三大特征

多态是建立在封装和继承基础之上的 🔴🟢🟡


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


一个对象的编译类型和运行类型可以不一致

编译类型在定义对象时就确定了,不能改变

运行类型是动态的,可变化的

编译类型取决于定义时,=的左边,运行类型 =的右边

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


向上转型


本质:父类引用指向了子类对象

语法:父类类型 引用名 = new 子类类型();

特点:编译类型看左边,运行类型看右边。 在访问权限允许可以调用父类的所有成员 不能调用子类中特有的成员 最终运行结果看子类的具体实现!


向下转型


本质:子类引用指向了父类

语法:子类类型 引用名 = (子类类型) 父类引用;

特点:只能强转父类的引用,不能强转父类的对象,要求父类的引用必须指向的是当前目标类型的对象,当向下转型时,可以调用子类类型中所有的成员


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


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


Java 的动态绑定机制



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


当调用对象方法的时候,该方法会和该对象的内存地址/编译类型 进行动态绑定

当调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用


多态数组


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

🔴🟢🟡


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 方法


a7d5010613f749cf8cb4a8a3a359973f.png


🔴🟢🟡


//重写 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 方法


78ad167437b744a386befe26c272922a.png


两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!

两个引用,如果指向的是不同对象,则哈希值是不一样的


哈希值主要根据地址号来的!不能认为哈希值等于地址


toString 方法


34e874275f384cb79335e5f7dee2f53e.png


1) 基本介绍

默认返回:全类名+@+哈希值的十六进制,子类往往重写 toString 方法,用于返回对象的属性信息


2) 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式


3) 当直接输出一个对象时,toString 方法会被默认的调用, 比如


System.out.println(sb); 就会默认调用sb.toString()


finalize 方法


1.当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作


2.什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法。


3.垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制


d5293ed398b94e8ea5019a2cdf8407bf.png


零钱通项目



项目需求 :


防一个微信零钱通的压缩版,要实现文字界面,收益支出(支出细节)等的记录,对数据合法校验,比如没钱了,还消费就会提示,以及查看退出时提醒是否确定退出


项目思路 :


化繁为简,先使用判断以及分支语句,实现可以与用户互动的界面,然后依次实现对应的四个功能即可,最后做数据的校验以及函数的封装,界面优化,用户体验优化……过程中细节拉满,开始吧


具体实现 :


3d620e9c912047a08a55b2b9d74c6af1.gif



上代码


🔴🟢🟡


/**
 * @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;
        }
    }
}


收工!!!🔴🟢🟡



相关文章
|
4月前
|
设计模式 安全 图形学
Unity精华☀️ 面试官眼中的「设计模式」
Unity精华☀️ 面试官眼中的「设计模式」
|
4月前
|
存储 数据处理
|
7月前
|
C语言 开发者
【C 言专栏】C 语言中的模块化编程思想
【5月更文挑战第3天】本文探讨了C语言中的模块化编程思想,阐述了其概念和实现方式,如函数和头文件。模块化编程能提升代码可读性,便于维护和复用,增强程序可靠性。实践中应合理划分模块,明确接口,保持独立性和内聚性。以计算器程序为例说明模块化应用,并展望了未来发展趋势。模块化编程是构建高质量C程序的关键,有助于提高开发效率。
170 3
【C 言专栏】C 语言中的模块化编程思想
|
7月前
|
编译器 C++
【C++初阶】第四站:类和对象(下)(理解+详解)-2
【C++初阶】第四站:类和对象(下)(理解+详解)-2
|
7月前
|
编译器 C语言 C++
【C++初阶】第四站:类和对象(下)(理解+详解)-1
【C++初阶】第四站:类和对象(下)(理解+详解)-1
|
7月前
|
前端开发 算法 JavaScript
快来get策略模式,告别编程困惑,轻松变身编程高手✨
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
设计模式 前端开发 JavaScript
图解23种设计模式(TypeScript版)——前端切图崽必修内功心法
图解23种设计模式(TypeScript版)——前端切图崽必修内功心法
图解23种设计模式(TypeScript版)——前端切图崽必修内功心法
|
编译器 C++
C++ 类与对象中类的深入知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(二)
C++ 类与对象中类的深入知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(二)
|
编译器 C++
C++ 类与对象中类的深入知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(一)
C++ 类与对象中类的深入知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(一)
C++ 类与对象中类的深入知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏(一)
面试:第十二章:所有总结
面试:第十二章:所有总结
114 0