Java基础(6)面向对象编程(中级)

面向对象编程(中级)

IDEA使用(IntelliJ IDEA)

IDE(集成开发环境)

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

掌握IDEA基本的快捷键

包的三大作用

  1. 区分相同名字的类
  2. 当类很多的时候可以更好的管理类
  3. 控制访问的范围(四种级别的访问修饰符)

包的基本语法

package [包名(com.lzl...]

包的本质

创建不同的文件夹来保存类文件

当两个包中都有Dog类时,不同Dog类的调用方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HlkStVSh-1658490025971)(C:\Users\25935\AppData\Roaming\Typora\typora-user-images\image-20220717204612641.png)]

包命名

  • 命名规则
    • 只能包含数字、字母、下划线、小圆点,但不能用数字开头,不能是关键字和保留字
  • 命名规范
    • 一般是小写字母加小圆点
    • com.公司名.项目名.业务模块名

Java中常用的包

java.lang.* //lang包是基本包,默认引用,不需要在引入
java.util.* //util包,系统提供的工具包,工具类,使用Scanner
java.net.*  //网络包,网络开发
java.awt.*  //是做java的界面开发,GUI

引入包

语法:

import [];
import java.util.Scanner;//只引入一个类Scanner
import java.util.*;//表示将java.util包下的所有类都引入

在引入包时,需要哪个类引入哪个类

注意事项和使用细节

  1. package的作用是声明当前类所在的包,需要放在类的最上面,一个类最多只能有一个package
  2. import指令,放在package的下面,在定义前面,可以有多句且没有顺序要求

访问修饰符

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

  1. 公开级别:用public修饰,对外公开
  2. 受保护级别:用protected修饰,对子类和同一个包中公开
  3. 默认级别:没有修饰符,向同一个包中的类公开
  4. 私有级别:用private修饰,只有类本身可以访问,不对外公开(私有属性可以通过类实例化后调用类中的公开方法实现在其他类中调用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zrDugzn-1658490025974)(C:\Users\25935\AppData\Roaming\Typora\typora-user-images\image-20220717212356982.png)]

使用注意事项

  1. 修饰符可以用来修饰类中的属性,成员方法以及类
  2. 只有默认的和public才能修饰类,并且遵循上述访问权限的特点
  3. 子类访问(学完继承后补充)
  4. 成员方法的访问规则和属性完全一样

面向对象的三大特征

面向对象的三大基本特征:封装、继承和多态

封装

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

封装的好处
  1. 隐藏实现细节:方法(连接数据库)<–直接调用(传入参数)
  2. 可以对数据进行验证,保证安全合理
封装实现的步骤(三步)
  1. 将属性私有化private 【不能直接修改属性】

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

    public void setXxx(类型 参数名){//Xxx表示某个属性

    ​ //加入数据验证的业务逻辑

    ​ 属性 = 参数名;

    }

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

    public XX getXxx(){//权限判断

    ​ return xx;

    }

封装与构造器

在封装时,属性需要进行验证,如果直接调用构造器(如下在段落注释中的代码),就失去了在set()中对属性进行校验的效果了,所以需要在构造器中调用set()方法

 public Person(String name, int age, double salary) {
        //如果直接调用这个构造器,下面的set中的数据校验就全部失效了
       	/*
     	this.name = name;
        this.age = age;
        this.salary = salary; 
        */
      	setName(name);
        setAge(age);
        setSalary(salary);
    }

实例:

设计一个小程序,不能直接查看人的年龄,工资等隐私,并对设置的年龄进行合理性的验证。年龄合理(1-120)就设置,否则给默认值(18),工资不能直接查看,name的长度在2-6之间

package com.lzl.encap;

public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("lzl");
        person.setAge(22);
        person.setSalary(8000);
        person.info();

        Person person1 = new Person("lzl2",23,10000);
        person1.info();

    }
}
//名字长度为2-6个字符,年龄在0-120岁,工资不能直接查看
class Person{
    public String name;
    private int age;
    private double salary;

    //构造器
    public Person() {
    }

    public Person(String name, int age, double salary) {
        //如果直接调用这个构造器,下面的set中的数据校验就全部失效了,
        // 应直接调用set方法
        /*
        this.name = name;
        this.age = age;
        this.salary = salary;
        */
        setName(name);
        setAge(age);
        setSalary(salary);
    }

    //get\set方法直接用快捷键Alt+Insert
    public void setName(String name){
        if(name.length()>=2&&name.length()<=6){
            this.name = name;
        }else {
            System.out.println("输入名字长度有误(输入2-6个字符),自动填入默认名字:");
            this.name = "无名";
        }

    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age<=120&&age>=0){
            this.age = age;
        }else {
            System.out.println("输入年龄有误(输入年龄范围1-120),填入默认年龄:");
            this.age = 18;
        }
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public void info(){
        System.out.println("输入信息为:name = " + name);
        System.out.println("age = " + age);
        System.out.println("salary = " + salary);
    }
}

继承

在很多时候在几个不同类中的属性和方法是有很多相同,所以用继承来解决代码的复用性问题

继承的介绍

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

image-20220719082637907

继承的基本语法

class 子类 extends 父类{
    
}
  1. 子类会自动拥有父类定义的属性和方法
  2. 父类也叫基类、超类
  3. 子类又叫派生类

继承给编程带来的便利

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

继承的细节

  1. 子类继承了所以的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有的属性和方法不能再子类直接访问,要通过父类提供公共的方法去访问
  2. 子类必须调用父类的构造器,完成父类的初始化(super();默认调用父类的无参构造器)
  3. 当创建子类对象时,不管子类使用哪个构造器,默认情况下总是会调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的那个构造器完成对父类的初始化工作,否则,编译不会通过

image-20220719092842589

image-20220719092917661

  1. 如果希望指定调用父类的某个构造器,则显示的调用一下:super(参数列表)。
  2. super在使用时,必须放在构造器的第一行。
  3. super() 和this() 都只能放在构造器的第一行,因此两个方法不能共存在一个构造器。
  4. Java的所有类都是Object类的子类,Object是所有类的基类

image-20220719100248844

  1. 父类构造器的调用不限于直接父类!将一直追溯直到Object类(顶级父类)
  2. Java中子类最多只能继承一个父类(直接继承),即Java中是单继承机制
  3. 不能滥用继承,子类与父类之间必须要满足is-a的关系

继承的本质(*)

当子类对象创建好之后,建立的是查找关系

image-20220719130537045

image-20220719133005444

image-20220719134122342

  1. 在创建son对象时,先加载类信息,加载顺序是有父类到子类:Object->GrandPa->Father->Son
  2. son对象在堆中会将相应的所有父类属性等信息加载到对象空间中(不管属性名是否重复)
  3. 在用son对象输出属性时,从子类逐层向上寻找,若找到并且该属性可以访问,就直接输出(就近原则);若找到但无法访问,就报错(不管上一层父类是否有同名的属性,比如:在Father类中有 private age = 39,在GrandPa类中有 public age = 100,输出son.age,在寻找的Father类的时候便以找到age,但不可访问,就直接报错,不会再去查找GrandPa中的age);若找不到相关的属性,则直接报错。

super关键字

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

基本语法
  1. 访问父类的属性,但不能访问父类的private属性

    super.属性名;

  2. 访问父类的方法,但不能访问父类的private方法

    super.方法名(参数列表);

  3. 访问父类构造器,只能放在构造器的第一句

    super(参数列表);

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

image-20220719150046615

方法重写/复写(override)

方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法

注意事项和使用细节

  1. 子类方法的形参列表和方法名,要和父类方法的形参列表和方法名称完全一样。
  2. 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类;比如父类返回类型是Object,子类方法返回类型String、
  3. 子类方法不能缩小父类方法的访问权限

方法重新和重载的比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rrgkrCu4-1658490025981)(C:\Users\25935\AppData\Roaming\Typora\typora-user-images\image-20220719165557864.png)]

多态

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

多态的具体体现(*)

  1. 方法的多态:重写和重载
  2. 对象的多态:(核心、困难、重点)(必背)
    1. 一个对象的编译类型和运行类型可以不一致
    2. 编译类型在定义对象时,就确定了,不能改变
    3. 运行类型是可以变化的
    4. 编译类型看定义时 = 号 的左边,运行类型看 = 号 右边

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m8chToru-1658490025982)(C:\Users\25935\AppData\Roaming\Typora\typora-user-images\image-20220719211144314.png)]

多态的注意事项和细节讨论

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

1.多态的向上转型:
  1. 本质:父类的引用指向了子类的对象
  2. 语法:父类类型 引用名 = new 子类类型();
  3. 编译类型看左边,运行类型看右边

可以调用父类中的所有成员(需要遵守访问权限)

不能调用子类中特有成员(因为在编译阶段,能调用哪些成员,是由编译类型来决定的)

最终的运行效果看子类(运行类型)的具体实现!即调用方法时,按照从子类(运行类型)开始查找方法,然后调用,规则与方法调用规则一致。

2.多态的向下转型
  1. 语法:子类的引用 引用名 = (子类类型)父类引用;
  2. 只能强转父类引用,不能强转父类对象
  3. 要求父类的引用必须指向的是当前目标类型的对象
  4. 当向下转型后,就可以调用子类类型中的所有成员
3.

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

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

练习

image-20220720100446772

Java的动态绑定机制(非常重要***)

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

image-20220720103413927

多态的应用

1.多态数组

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

package com.lzl.poly;

public class Test {
    public static void main(String[] args) {
        //创建一个Person对象,2个Student对象,2个Teacher对象,
        // 存放在数组里
        //Teacher有teach方法,Student有study方法

        Person[] people = new Person[5];
        people[0] = new Person("老大",30);
        people[1] = new Student("老二",26,100);
        people[2] = new Student("老三",25,80);
        people[3] = new Teacher("老四",24,8000);
        people[4] = new Teacher("老五",23,18000);

        for (int i = 0; i < people.length; i++) {
            System.out.println(people[i].say());//动态绑定机制
            if(people[i] instanceof Student){
                System.out.println(((Student)people[i]).study());
            }else if (people[i] instanceof Teacher) {
                System.out.println(((Teacher)people[i]).teach());
            }else if (people[i] instanceof Person) {

            }else {
                System.out.println("输入类型有误!");
            }
        }


        /*笨法:
        Student student = (Student) people[1];
        System.out.println(student.study());
        Teacher teacher = (Teacher) people[3];
        System.out.println(teacher.teach());
        */
    }
}

package com.lzl.poly;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        setName(name);
        setAge(age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String say(){
        return name + "说:我的年龄:" + age;
    }
}

package com.lzl.poly;

public class Student extends Person{
    private double score;

    public Student() {
    }

    public Student(String name, int age, double score) {
        super(name, age);
        setScore(score);
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String say(){
        return super.say() + " 我的分数为" + score;
    }
    public String study(){
        return "学生" + getName() + "正在学Java";
    }
}

package com.lzl.poly;

public class Teacher extends Person{
    private double salary;

    public Teacher() {
    }

    public Teacher(String name, int age, double salary) {
        super(name, age);
        setSalary(salary);
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String say(){
        return super.say() + " 我的工资为" + salary;
    }
    public String teach(){
        return "老师" + getName() + "正在教Java";
    }
}

2.多态参数

方法定义的参数类型为父类类型,实参类型允许为子类类型

image-20220720164550483

package com.lzl.poly.polyparameter;

public class Test {
    public static void main(String[] args) {
        Employee lzl01 = new Manager("lzl01",
                15000, 200000);
        Employee lzl02work = new Worker("lzl02work",
                3000);
        Test test = new Test();
        test.showEmpAnnual(lzl01);
        test.showEmpAnnual(lzl02work);
        test.testWork(lzl01);
        test.testWork(lzl02work);

    }
    public void showEmpAnnual(Employee e){
        System.out.println(e.getName() + "的年工资为:" + e.getAnnual());
    }
    public void testWork(Employee e){
        if (e instanceof Worker){
            ((Worker) e).work();
        }else if(e instanceof Manager){
            ((Manager) e).manage();
        }else if (e instanceof Employee){}
        else {
            System.out.println("输入有误!");
        }
    }
}


package com.lzl.poly.polyparameter;

public class Employee {
    private String name;
    private double salary;

    public Employee() {
    }

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public double getAnnual(){
        return salary*12;
    }
}


package com.lzl.poly.polyparameter;

public class Manager extends Employee{
    private double bonus;

    public Manager() {
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    public Manager(String name, double salary, double bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    @Override
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
    public void manage(){
        System.out.println(getName() + "正在管理员工");
    }
}


package com.lzl.poly.polyparameter;

public class Worker extends Employee{
    public Worker() {
    }

    public Worker(String name, double salary) {
        super(name, salary);
    }

    @Override
    public double getAnnual() {
        return super.getAnnual();
    }
    public void work(){
        System.out.println(getName() + "正在工作!");
    }
}

Object类详解

Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

equals方法

== 与 equals对比【面试题】
  1. ==是一个比较运算符

    1. 既可以判断基本类型,又可以判断引用类型
    2. 如果判断基本类型,判断的是值是否相等:示例:int i =10; double j = 10.0; i == j 为true
    3. 如果判断引用类型,判断的是地址是否相等,即判断是不是同一个对象
  2. equals

    1. Object类中的方法,只能判断引用类型
    2. 默认判断地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如:Integer,String【可查看Integer,String的equals源码】

    在Object类中的源码

    public boolean equals(Object obj) {
            return (this == obj);
        }
    

    在Integer类中的源码

    public boolean equals(Object obj) {
            if (obj instanceof Integer) {
                return value == ((Integer)obj).intValue();
            }
            return false;
        }
    

    在String类中的源码

    public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }
    

image-20220720173204099

如何重写equals方法

实例:判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之返回false

class Person{
    private String name;
    private int age;
    private char gender;
}
package com.lzl.EqualsDemo01;

public class EqualsDemo01 {
    public static void main(String[] args) {
        //创建两个Person对象
        Person person1 = new Person("lzl01",23,'男');
        Person person2 = new Person("lzl01",23,'男');
        System.out.println(person1.equals(person2));
        //在Person类中没有重写equals方法就会返回false
    }

}
class Person{
    private String name;
    private int age;
    private char gender;
    //重写Object的equals方法。
    public boolean equals(Object obj){
        if (this == obj){
            return true;
        }
        //判断传进的类型是否与要比较的类型相符
        if (obj instanceof Person){//是Person类,就进行比较
            //进行向下转型、因为需要得到obj的各个属性,进行比较,
            // 否则用Object类型无法使用参数obj在Person类中的属性
            Person p = (Person) obj;
            return this.name.equals(p.name) && this.age == p.age && this.gender == p.gender;
        }
        //若以上两种情况都不是,就返回false
        return false;
    }

    public Person(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}
练习

image-20220720200010261

hashcode方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4cQ09w6-1658490025986)(C:\Users\25935\AppData\Roaming\Typora\typora-user-images\image-20220720202651233.png)]

  1. 提高具有哈希结构的容器的效率
  2. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的
  3. 两个引用,如果指向的是不同的对象,则哈希值是不一样的(并非绝对:哈希冲突)
  4. 哈希值主要是根据地址来计算的,不能完全将哈希值等价于地址。
  5. 方法调用:obj.hashCode()
  6. 在集合,hashCode如果需要,也会重写

toString方法

基本介绍:

默认返回:全类名+@+哈希值的十六进制

Object类中的toString方法:

//Object的toString()源码
    /*
    (1)getClass().getName()类的全类名(包名+类名)
    (2)Integer.toHexString(hashCode())将对象的hashcode值转成16进制字符串
    */
    public String toString(){
        
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
重写toString方法

打印对象或拼接对象时 ,都会自动调用toString形式

当输出一个对象时,toString方法会被默认的调用

System.out.println(monster);//等价于monster.toString

finalize方法(使用情况少,更多的用于面试)

当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。子类重写 finalize 方法,以配置系统资源或执行其他清除。

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

(总的来说,就是类似于办公室里有垃圾,正常是下班后清洁工打扫,但是太脏了,你通过System.gc()方法给清洁工打了个电话,让他来打扫,但清洁工具体什么时候来不确定)

断点调试(debug)

  1. 开发中,在查找错误时,就可以用断点调试,一步步的看源码执行的过程,从而发现错误的所在
  2. 重要提示:在断点调试的过程中是运行状态,是以对象的运行类型来执行的

断点调试介绍

  1. 断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,让后可以一步步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码即显示错误后停下。程序员在进行分析从而找的Bug
  2. 断点调试是程序员必须掌握的技能
  3. 断点调试也可以帮助我们查看Java底层源码的执行过程,提高程序员水平

断点调试快捷键

image-20220721100331974

项目-零钱通

image-20220721170752108

用面向过程的方式

package com.lzlp.projcet.smallchange;

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

public class SmallChange {

    //1.化繁为简,先完成零钱通菜单界面
    //2.完成零钱通明细
    //3.收益入账
    //4.消费
    //5.退出
    //6.用户输入4退出时,给提示”是否确定退出?y/n“,
    // 必须输入y/n,否则循环输入指令直到输入y/n;
    //7.在收益入账和消费时,判断金额是否合理,并给出相应的提示
    public static void main(String[] args) {
        //1.零钱通菜单
        boolean out = true;
        int k;
        Scanner scanner = new Scanner(System.in);


        //2.零钱通明细:设计思路
        //(1)可以把收益和消费保存到数组
        //(2)可以使用对象
        //(3)可以使用字符串(String)拼接

        //(3)
        String details ="----------零钱通明细----------";

        //3.收益入账:完成功能驱动,程序员增加新的变量和代码
        //(1)定义新的变量
        double money = 0;
        double balance = 0;
        Date date = null;//date 是 java.util.Date类型,表示日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//可以用于日期格式化的对象

        //4.消费
        //定义新变量,记录消费明细
        String note = "";

        do {
            System.out.println("\n1==========零钱通菜单==========");
            System.out.println("\t\t1.零钱通明细");
            System.out.println("\t\t2.收益入账");
            System.out.println("\t\t3.消费");
            System.out.println("\t\t4.退   出");
            System.out.println("请选择(1-4)");
            k = scanner.nextInt();

            switch (k){
                case 1:
                    System.out.println(details);
                    break;
                case 2:
                    System.out.print("收益入账金额:");
                    money = scanner.nextDouble();
                    //money 范围需要有校验,在功能完成后进行完善
                    //分析思路:
                    //找出不正确金额的条件,然后给出提示,就直接break
                    if (money<=0){
                        System.out.println("收益金额要求>0");
                        break;
                    }

                    balance += money;
                    date = new Date();//获取当前日期
                    //System.out.println(sdf.format(date));//测试日期格式是否正确
                    //拼接收益入账信息到 details
                    details += "\n收益入账\t+" +money + "\t"
                            + sdf.format(date) + "\t余额:" + balance;
                    break;
                case 3:
                    System.out.print("输入消费金额:");
                    money = scanner.nextDouble();
                    //money 范围需要有校验,在功能完成后进行完善
                    //找出不正确金额的条件,然后给出提示,就直接break
                    if (money<=0||money>balance){
                        System.out.println("你的消费金额应该在0到" + balance);
                        break;
                    }
                    System.out.print("请输入消费说明:");
                    note = scanner.next();
                    balance -= money;
                    date = new Date();//获取当前日期
                    details += "\n"+ note + "\t-" +money + "\t"
                            + sdf.format(date) + "\t余额:" + balance;
                    break;
                case 4:
                    //6.用户输入4退出时,给提示”是否确定退出?y/n“
                    // 必须输入y/n,否则循环输入指令直到输入y/n;
                    //分析:(1)定义一个变量接收用户的输入
                    //(2)用while + break,来确保输入是否为y/n,是则跳出循环,否则进行循环重写输入
                    //(2)跳出while循环后,在判断输入的是y还是n,在决定是否退出;
                    //老师建议:一段代码完成一个小功能,尽量不要混在一起
                    String choice = "";
                    while (true){
                        System.out.println("是否确定退出?y/n");
                        choice = scanner.next();
                        if (choice.equals("y")||choice.equals("n")){
                            break;
                        }
                    }
                    if (choice.equals("y")){
                        out = false;
                        System.out.println("退   出");
                    }
                    break;
                default:
                    System.out.println("输入有误,请重新输入");
                    break;
            }
        }while (out);
        System.out.println("退出零钱通");
    }
}

面向对象

SmallChangeSysApp类:

package com.lzlp.projcet.smallchangeoop;

public class SmallChangeSysApp {
    public static void main(String[] args) {
        SmallChangeOop sc = new SmallChangeOop();
        sc.mainMenu();
    }
}

SmallChangeOop类:

package com.lzlp.projcet.smallchangeoop;

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

//创建零钱通的功能类,将所有功能方法写入其中
public class SmallChangeOop {
    //属性
    //1.零钱通菜单
    boolean out = true;
    int k;
    Scanner scanner = new Scanner(System.in);


    //2.零钱通明细:设计思路
    //(1)可以把收益和消费保存到数组
    //(2)可以使用对象
    //(3)可以使用字符串(String)拼接

    //(3)
    String details ="----------零钱通明细----------";

    //3.收益入账:完成功能驱动,程序员增加新的变量和代码
    //(1)定义新的变量
    double money = 0;
    double balance = 0;
    Date date = null;//date 是 java.util.Date类型,表示日期
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//可以用于日期格式化的对象

    //4.消费
    //定义新变量,记录消费明细
    String note = "";

    //零钱通显示菜单
    public void mainMenu(){
        do {
            System.out.println("\n1==========零钱通菜单==========");
            System.out.println("\t\t1.零钱通明细");
            System.out.println("\t\t2.收益入账");
            System.out.println("\t\t3.消费");
            System.out.println("\t\t4.退   出");
            System.out.println("请选择(1-4)");
            k = scanner.nextInt();

            switch (k){
                case 1:
                    this.detail();
                    break;
                case 2:
                    this.income();
                    break;
                case 3:
                    this.pay();
                    break;
                case 4:
                    this.exit();
                    break;
            }
        }while (out);
    }

    //零钱通明细
    public void detail(){
        System.out.println(details);
    }

    //收益入账
    public void income(){
        System.out.print("收益入账金额:");
        money = scanner.nextDouble();
        //money 范围需要有校验,在功能完成后进行完善
        //分析思路:
        //找出不正确金额的条件,然后给出提示,就直接break
        if (money<=0){
            System.out.println("收益金额要求>0");
            return;//退出方法,不在执行后面的代码
        }

        balance += money;
        date = new Date();//获取当前日期
        //System.out.println(sdf.format(date));//测试日期格式是否正确
        //拼接收益入账信息到 details
        details += "\n收益入账\t+" +money + "\t"
                + sdf.format(date) + "\t余额:" + balance;
    }

    //消费
    public void pay(){
        System.out.print("输入消费金额:");
        money = scanner.nextDouble();
        //money 范围需要有校验,在功能完成后进行完善
        //找出不正确金额的条件,然后给出提示,就直接break
        if (money<=0||money>balance){
            System.out.println("你的消费金额应该在0到" + balance);
            return;
        }
        System.out.print("请输入消费说明:");
        note = scanner.next();
        balance -= money;
        date = new Date();//获取当前日期
        details += "\n"+ note + "\t-" +money + "\t"
                + sdf.format(date) + "\t余额:" + balance;
    }
    //退出
    public void exit(){
//6.用户输入4退出时,给提示”是否确定退出?y/n“
        // 必须输入y/n,否则循环输入指令直到输入y/n;
        //分析:(1)定义一个变量接收用户的输入
        //(2)用while + break,来确保输入是否为y/n,是则跳出循环,否则进行循环重写输入
        //(2)跳出while循环后,在判断输入的是y还是n,在决定是否退出;
        //老师建议:一段代码完成一个小功能,尽量不要混在一起
        String choice = "";
        while (true){
            System.out.println("是否确定退出?y/n");
            choice = scanner.next();
            if (choice.equals("y")||choice.equals("n")){
                break;
            }
        }
        if (choice.equals("y")){
            out = false;
            System.out.println("退   出");
        }
    }

}

本章作业

1

image-20220721212942238

test

package OOP.OOP02.demo01;

public class test {
    public static void main(String[] args) {
        Person p1 = new Person("lzl01", 12, "java架构师");
        Person p2 = new Person("lzl02", 133, "java架构师1");
        Person p3 = new Person("lzl02", 13, "java架构师2");
   		//还可以直接创建数组
        Person[] 
        
        p1.printp(p1,p2,p3);
    }
}

Person

package OOP.OOP02.demo01;

public class Person {
    private String name;
    private int age;
    private String job;

    public Person() {
    }
    public Person(String name, int age, String job) {
        this.name = name;
        this.age = age;
        this.job = job;
    }
    //冒泡排序法看,对person对象进行排序
    public void psort(Person... p){
        Person p0;
        for (int i = 0; i < p.length-1; i++) {
            for (int j = 0; j < p.length-1-i; j++) {
                if (p[j].age<p[j+1].age){
                    p0 = p[j];
                    p[j] = p[j+1];
                    p[j+1] = p0;
                }
            }
        }
    }

    public void printp(Person... p){
        psort(p);
        for (int i = 0; i < p.length; i++) {
            System.out.println(p[i].toString());
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", job='" + job + '\'' +
                '}';
    }
}

2

image-20220722081400867

publicprotected默认修饰符private
同类同类同类同类
同包同包同包
子类子类
不同包

6

image-20220722103702120

什么是多态

image-20220722165735167

Java的动态绑定机制

  1. 当对象调用方法时,该方法会和对象的调用地址/运行类型绑定
  2. 当调用对象的属性时,没有动态绑定机制,哪里声明,哪里使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值