B站韩顺平java学习笔记(七)--面向对象编程(中级)章节

目录

一  IDEA使用

1  IDEA使用技巧和经验

(1)设置字体

(2)字符编码设置

 2  IDEA常用快捷键

3  模板/自定义模板

二  包

1  包的三大作用

2  包的基本语法

3  包的本质分析(原理)

4  包的命名

(1)命名规则

(2)命名规范

5  常用的包

6  注意事项和使用细节

(1)package

(2)import指令

三  访问修饰符

1  基本介绍

2  四种访问修饰符的访问范围

3  使用的注意事项

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

1  封装(encapsulation)

(1)介绍

(2)理解和好处

(3)实现步骤(三步)

(4)封装和构造器合用

2  继承

(1)基本介绍和示意图

(2)基本语法

(3)细节问题

(4)继承的本质分析🚩

3  多态

(1)基本介绍

(2)具体表现

(3)多态注意事项和使用细节

(4)java的动态绑定机制🚩🚩

(5)多态的应用

五  Super关键字

1  基本介绍

2  基本语法

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

4  super和this的比较

六  方法重写(overwrite)

1  基本介绍

2  注意事项和使用细节

3  方法重载和方法重写的区别和联系

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

1  equals方法

(1)==和equals的对比

(2)equals()方法练习题

2  hashCode方法

(1)语法

(2)注意细节

3  toString方法

4  finalize方法

八  断点调试(debug)

1  一个实际需求

2  介绍

3  快捷键

(1)F7(跳入:跳入方法内)

(2)F8(跳过:逐行执行代码)

(3)shift + F8(跳出方法)

(4)F9(resume:执行到下一个断点)

4  运行模块图

九  项目

1  零钱通(面向过程编程)

2  零钱通(面向对象编程)

知识点

1  继承设计的基本思想

2  查看JDK源码

3  得到当前日期


ps:成员表示的是属性和方法

一  IDEA使用

1  IDEA使用技巧和经验

(1)设置字体

        菜单 file -> settings

(2)字符编码设置

 2  IDEA常用快捷键

        (1)删除当前行,默认ctrl + y,可以改成ctrl + d;

        (2)复制当前行到下一行,ctrl +alt + 向下光标;

        (3)补全代码:alt + /;

        (4)添加注释和取消注释:ctrl + /;

        (5)导入该行需要的类,先配置 auto import ,然后使用alt + enter即可;

        (6)快速格式化代码 ctrl + alt + L;

        (7)快速运行程序,自己定义 alt + R。

        (8)生成构造方法等 alt + insert;  [提高开发效率]

        (9)查看一个类的层次关系 ctrl + H;

        (10)将光标放在一个方法上,输入ctrl + B,可以选择定位到哪个类的方法;

        (11)自动的分配变量名,通过 在后面 .var;

3  模板/自定义模板

        file -> setting -> editor -> Live templates ->

        查看有哪些模板快捷键/可以自己增加模板

二  包

1  包的三大作用

        (1)区分相同名字的类;

        (2)当类很多时,可以很好的管理类;

        (3)控制访问范围。

2  包的基本语法

        package com.lyxlearn;

        说明:

        (1)package 关键字:表示打包;

        (2)com.lyxlearn:表示包名。

3  包的本质分析(原理)

        实际上就是创建不同的文件夹/目录来保存类文件。

4  包的命名

(1)命名规则

        只能包含数字、字母、下划线、小圆点. ,但不能用数字开头,不能是关键字或保留字。

(2)命名规范

        一般是小写字母 + 小圆点;一般是com.公司名.项目名.业务模块名。

5  常用的包

        (1)java.lang.*  //lang包是基本包,默认引入,不需要再引入;

        (2)java.util.*  //util包,是系统提供的工具包,工具类,例如使用Scanner;

        (3)java.net.*  //网络包,网络开发;

        (4)java.awt.*  //是做java的界面开发,GUI。

6  注意事项和使用细节

(1)package

         作用是声明当前类所在的包,需要在类的最上面,一个类中最多只有一句package;

(2)import指令

        位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。

三  访问修饰符

1  基本介绍

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

        (1)公开级别:用 public 修饰,对外公开;

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

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

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

2  四种访问修饰符的访问范围

3  使用的注意事项

        (1)修饰符可以用来修饰类中的属性,成员方法以及类;

        (2)只有默认的和public才能修饰类!,并遵循上述访问权限的特点;

        (3)讲完子类再说;

        (4)成员方法的访问规则和属性完全一样。

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

1  封装(encapsulation)

(1)介绍

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

(2)理解和好处

        ①  隐藏实现细节;

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

(3)实现步骤(三步)

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

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

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

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

                        属性 = 参数名;

                }

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

                public 数据类型 getXxx(){  //权限判断,Xxx 某个属性

                        return xx;

                }

        注便捷方法:

        摁alt + insert 键 弹出框,选择Getter and Setter即可。

(4)封装和构造器合用

        为了避免构造器破环私有访问属性的隐私,可以将set方法在构造器内调用即可。

2  继承

(1)基本介绍和示意图

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

(2)基本语法

        class 子类 extends 父类{

        }

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

        ②  父类又叫超类,基类;

        ③  子类又叫派生类。

(3)细节问题

        ①  子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供的公共的方法区访问;

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

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

        ④  如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表);(若是调用父类的无参构造器,可以写super();或者说明都不写。)

        ⑤  super在使用时,必须放在构造器的第一行;(super只能在构造器种使用)

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

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

        ⑧  父类构造器的调用不限于直接父类,将一直往上追溯知道Object类(顶级父类),从上向下依次调用;

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

        思考:如何让A类继承B类和C类?

        答:可以让A类继承B类,B类继承C类,与题目同样的效果;

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

(4)继承的本质分析🚩

 

         访问时:

        ①  首先看子类是否又该属性;

        ②  如果子类又这个属性,并且可以访问,则返回信息;

        ③  如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息...);

        ④  如哦父类没有就按照 ③ 的规则,继续找上级父类,直到Object...。

3  多态

(1)基本介绍

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

(2)具体表现

        ①  方法的多态        

         ②  对象的多态🚩

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

        例如:Animal animal = new Dog();  //animal 编译类型是Animal,运行类型Dog(其中Animal是Dog的父类)

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

        c  运行类型是可以改变的;

        例如:animal = new Cat();

        d  编译类型看定义时 = 号的左边,运行类型看 = 号的右边

(3)多态注意事项和使用细节

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

        ①  多态的向上转型

        a  本质:父类的引用指向(接收)了子类的对象; 

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

        c  特点如下:

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

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

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

        ②  多态的向下转型

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

        b  只能强转父类的引用,不能强转父类的对象;

        c  要求父类的引用必须指向的是当前目标类型(即等号前的子类类型)的对象;

        d  当向下转型后,可以调用子类类型中所有的成员。

        ③  属性没有重写之说,属性的值看编译类型;

        ④  instanceof 比较操作符:用于判断对象xx的运行类型是否为XX类型或者XX类型的子类型。例如 xx instanceof XX;

(4)java的动态绑定机制🚩🚩

        ①  当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定

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

public class DynamicBinding{
    public static void main(String[] args){
    A a = new B();//a的编译类型是 A,运行类型是B
    System.out.println(a.sum());
    System.out.println(a.sum1());
    }

}
class A{  //父类
    public int i = 10;

    public int sum(){
        return getI() + 10;
    }
    
    public int sum1(){
        return i + 10;
    }
    
    public int getI(){
        return i;
    }
}
class B extends A{  //子类
    public int i = 20;
    
    public int sum(){
        return i + 10;
    }
    
    public int sum1(){
        return i + 10;
    }
    
    public int getI(){
        return i;
    }
}

        此时结果为40,30。

public class DynamicBinding{
    public static void main(String[] args){
    A a = new B();//a的编译类型是 A,运行类型是B
    System.out.println(a.sum());
    System.out.println(a.sum1());
    }

}
class A{  //父类
    public int i = 10;

    public int sum(){
        return getI() + 10;
    }
    
    public int sum1(){
        return i + 10;
    }
    
    public int getI(){
        return i;
    }
}
class B extends A{  //子类
    public int i = 20;
    
    //public int sum(){
    //    return i + 10;
    //}
    
    //public int sum1(){
    //    return i + 10;
    //}
    
    public int getI(){
        return i;
    }
}

        此时结果为30,20。

        对于30,因为子类中没有sum()方法,所以会去父类中调用sum()方法,调用方法中的return有getI()方法,因为当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定,此时对象的运行类型是B,所以调用B类中的getI()方法,返回20,加上10,得到30。

        对于20,因为子类中没有sum1()方法,所以会去父类中调用sum1()方法,调用方法中有变量i,因为当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用,所以使用A类中声明的i=10,加上10,等于20。

(5)多态的应用

        ①  多态数组

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

        实例:现有一个继承结构如下,要求创建1个Person对象,2个Student对象和2个Teacher对象,统一放在数组中,并调用say方法。

//Person类
public class Person {
    private String name = "li";
    private int age = 23;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = 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 + "\t" + age;
    }
}
//Student类
public class Student extends Person {
    private double score;

    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

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

    @Override
    public String say() {
        return super.say() + "\t" + score;
    }
    public void study(){
        System.out.println("学生" + getName() + "正在听课...");
    }
}
//Teacher类
public class Teacher extends Person{
    private double sal;

    public Teacher(String name, int age, double sal) {
        super(name, age);
        this.sal = sal;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    @Override
    public String say() {
        return super.say() + "\t" + sal;
    }
    public void teach(){
        System.out.println("老师" + getName() + "正在讲课...");
    }
}
//主类
public class PolyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("hack",30);
        persons[1] = new Student("jack1",31,60);
        persons[2] = new Student("jack2",35,80);
        persons[3] = new Teacher("mark1",50,9000);
        persons[4] = new Teacher("mark2",55,10000);
        for (int i = 1; i < persons.length; i++) {
            System.out.println(persons[i].say());
        }
    }
}

        如何调用子类特有的方法,比如Teacher有一个teach,Student有一个study,怎么调用?

        使用向下转型即可。

//在主类for循环内加如下代码即可
if (persons[i] instanceof Student) {
    Student student = (Student)persons[i];
    student.study();
    //也可以写成  ((Student)persons[i]).study();
}else if (persons[i] instanceof Teacher) {
    ((Teacher) persons[i]).teach();
}

        ②  多态参数

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

        a  定义员工类Employee,包含姓名和月工资【private】,以及计算年工资getAnnual的方法。普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求分别重写getAnnual方法;

        b  测试类中添加一个方法showEmpAnnual(Employee e),实现获取任何员工对象的年工资,并在main方法中调用该方法;

        c  测试类中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,则调用manage方法。

//Employee类
public class Employee {
    private String name;
    private double sal;

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

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public String getAnnual(){
        return "姓名:" + name + " 薪水:" + 12*sal ;
    }

}
//Manager类
public class Manager extends Employee{
    private double bonus;

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

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    public void manage(){
        System.out.println("经理:" + getName() + "管理工作.");
    }

    @Override
    public String getAnnual() {
        return "经理" + super.getAnnual() + " 奖金" + bonus;
    }
}
//OrdEmployee类
public class OrdEmployee extends Employee{
    public OrdEmployee(String name, double sal) {
        super(name, sal);
    }

    public void work(){
        System.out.println("普通员工:" + getName() + "从事工作.");
    }

    @Override
    public String getAnnual() {
        return "普通员工" + super.getAnnual();
    }
}
//主类
public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        Manager manager = new Manager("lili",10000,20000);
        OrdEmployee ordEmployee = new OrdEmployee("xiaoli",7000);
        Employee employee1 = new Manager("haha",15000,25000);
        Employee employee2 = new OrdEmployee("xiaoha",8000);
        System.out.println(test.showEmpAnnual(manager));
        System.out.println(test.showEmpAnnual(ordEmployee));
        System.out.println(test.showEmpAnnual(employee1));
        System.out.println(test.showEmpAnnual(employee2));
        test.testWork(manager);
        test.testWork(ordEmployee);
        test.testWork(employee1);
        test.testWork(employee2);
    }
    public String showEmpAnnual(Employee e){
        return e.getAnnual();
    }
    public void testWork(Employee e) {
        if (e instanceof Manager) {
            Manager manager = (Manager) e;
            manager.manage();
        } else if (e instanceof OrdEmployee) {
            OrdEmployee ordEmployee = (OrdEmployee) e;
            ordEmployee.work();
        } else {
            System.out.println("错误");
        }
    }
}

五  Super关键字

1  基本介绍

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

2  基本语法

        ①  访问父类的属性,但不能访问父类的private属性;

        例如:super.属性名;

        ②  访问父类的方法,不能访问父类的private方法;

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

        ③  访问父类的构造器;

        例如:super(参数列表);只能放在构造器的第一句,只能出现一句。

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

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

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

        (3)super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员,如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A(子类) -> B(父类) -> C(爷爷类)(先找父类,再找爷爷类,若都没有再找子类);

4  super和this的比较

六  方法重写(overwrite)

1  基本介绍

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

2  注意事项和使用细节

        (1)子类的方法的形参列表方法名称,要和父类方法的形参列表方法名称完全一样;

        (2)子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类;

                  比如:父类返回类型是Object,子类方法返回类型是String

        (3)子类不能缩小父类方法的访问权限,但可以扩大。

3  方法重载和方法重写的区别和联系

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

1  equals方法

(1)==和equals的对比

        ==是一个比较运算符:

        ①  ==:既可以判断基本类型,又可以判断引用类型; 

        ②  ==:如果判断基本类型,判断的是值是否相等。例如:int i = 10; double d = 10.0;true

        ③  ==:如果判断引用类型,判断的是地址是否相等,及判断是不是同一个对象;

        ④  equals():是Object类中的方法,只能判断引用类型;

        ⑤  默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer,String。

//Object类中的equals方法
//判断对象/地址是否相同
public boolean equals(Object obj) {
        return (this == obj);
}
//String类中的equals方法
//判断字符串的值是否一致
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;
}
//Integer类的equals方法
//判断传入的值是否相等
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

(2)equals()方法练习题

Person p1 = new Person();
p1.name = "lyxlearn";

Person p2 = new Person();
p2.name = "lyxlearn";

system.out.println(p1 == p2);  // ==在此判断的是对象(地址),不同,false
system.out.println(p1.name.equals(p2.name));  //equals,因为p1.name是字符串,
//在Person类中重写了equals,判断的是字符串是否一样,同,true
system.out.println(p1.equals(p2));  //因为person没有重写equals方法,
//所以用的还是Object父类的该方法,所以判断的是地址,不同,false

String s1 = new String("asdf");

String s2 = new String("asdf");

system.out.println(s1.equals(s2)); //同上第二个
system.out.println(s1 == s2);//同上第一个
int it =65;
float fl = 65.0f;
System.out.println(it == fl);  //true 值一样
char ch1 = 'A'; char ch2 = 12;
System.out.println(it == ch1);  //字符的本质是数字,A字符对应的数字为65, true
System.out.println(12 == ch2);  //同上

String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);  //判断地址,不同 true
System.out.println(str1.equals(str2));  //判断字符串是否一样,true
System.out.println("hello" == new java.sql.Date());  //类型不一致,直接false  

2  hashCode方法

(1)语法

        对象名.hashCode();

        一般通过将调用对象的内部地址转换成一个整数来实现的,注意不能等价于地址。

(2)注意细节

        ①  提高具有哈希结构的容器的效率;

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

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

        ④  哈希值主要是根据地址来的,不能完全将哈希值等价于地址;

        ⑤  在集合中,hashCode如果需要的话,也会重写。

3  toString方法

(1)基本介绍

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

//Object类中的toString方法
//getClass().getName():全类名
//Integer.toHexString(hashCode()): 哈希值的十六进制

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

        子类中往往重写toString方法(快捷键 alt + insert 选择toString后勾选即可),用于返回对象的属性信息,在重写了toString方法后,打印对象或者拼接对象时,都会自动调用该对象的toString形式。

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

public class ToString_ {
    public static void main(String[] args) {
        Monster monster = new Monster("小银角", 200, "巡山的");
        System.out.println(monster.toString());
        System.out.println(monster);
    }
}
class Monster{
    private String name;
    private int age;
    private String job;

    public Monster(String name, int age, String job) {
        this.name = name;
        this.age = age;
        this.job = job;
    }

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

4  finalize方法

        (1)当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法(比如释放资源,数据库链接等,若不重写则直接调用父类Object的finalize方法),做一些释放资源的操作;

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

        (3)垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动除法垃圾回收机制(不能保证一定,只是很大概率,因为垃圾回收机制可能在忙别的)。

八  断点调试(debug)

1  一个实际需求

        (1)断点调试可以在一步一步的看源码执行的过程,从而发现错误所在;

        (2)在断点调试过程中是运行状态,是以对象的运行类型来执行的。

2  介绍

        (1)断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看到各个变量当前的值,如果出错的话,调试到出错的代码行即显示错误,停下,进行分析从而找到这个Bug;

        (2)断点调试是程序员必须掌握的技能;

        (3)断点调试也能帮助我们查看java底层源代码的执行过程,提高程序员的java水平。

3  快捷键

(1)F7(跳入:跳入方法内)

        ①  例子:Array.sort(arr);//其中arr是一个数组,对数组进行排序

        就可以通过F7进入sort方法内,查看相关源码

        ②  若无法跳入有以下两种解决方法

                a  使用alt + shift +F7进行强制跳入

                b  通过设置(推荐)        

(2)F8(跳过:逐行执行代码)

(3)shift + F8(跳出方法)

        通常和F7跳入方法内连用,用于跳出方法。

(4)F9(resume:执行到下一个断点)

        注意:断点支持在运行过程中动态地下断点。

        F9尝使用于不在于两断点之间地内容,直接执行到下一个断点,不再逐行执行。

4  运行模块图

九  项目

1  零钱通(面向过程编程)

(1)完成显示菜单,并可以选择菜单,给出相应的提示;
(2)完成零钱通明细
        三种方案①数组 ②对象 ③String拼接
(3)完成收益入账
(4)完成消费
(5)完成退出,改进代码
        ①  用户输入4退出时,给出提示"是否退出(y/n)",必须输入正确的y/n,否则循环输入指令,直到输入y或者n。
        ②在收益入账和消费时,判断金额是否合理,并给出相应的提示。

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

public class SmallChangeSys {
    //1.完成显示菜单,并可以选择菜单,给出相应的提示;
    //2.完成零钱通明细
    //三种方案(1):数组(2):对象(3)String拼接
    //3.完成收益入账
    //4.完成消费
    //5.完成退出,改进代码
    //(1)用户输入4退出时,给出提示"是否退出(y/n)",必须输入正确的y/n,
    // 否则循环输入指令,直到输入y或者n。
    //(2)在收益入账和消费时,判断金额是否合理,并给出相应的提示。
    //(3)将面向过过程的代码改成面向对象的方法,编写SmallChangeSysOOP.java,
    //完成改进后的1,2,3,4,5各个功能
    //并使用SmallChangeSysApp.java,创建对象,调用方法,完成测试。
    public static void main(String[] args) {
        //定义相关变量
        boolean loop = true;
        Scanner scanner = new Scanner(System.in);
        String choseNum = "";

        //2.完成零钱通明细
        String details ="--------------零钱通明细--------------";

        //3.完成收益入账
        //定义新的变量(根据功能),完成功能驱动程序员增加新的变化和代码
        double money = 0;//收入
        double balance = 0;//余额
        Date date = null;// date 是 Java.util.Date 的类,表示日期
        //将date转换为中国常用的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //4.完成消费
        //定义新变量,保存消费的原因
        String note ="";

        //5.退出
        //定义新变量,保存退出的标记
        String choice = "";
        do {
            System.out.println("\n==============零钱通菜单==============");
            System.out.println("\t\t\t" + "1 零钱通明细");
            System.out.println("\t\t\t" + "2 收益入账");
            System.out.println("\t\t\t" + "3 消费");
            System.out.println("\t\t\t" + "4 退\t出");

            System.out.print("请选择(1-4):");
            choseNum = scanner.next();

            //使用switch分支控制
            switch (choseNum){
                case "1":
                    System.out.println(details);
                    break;
                case "2":
                    System.out.print("收益入账金额:");
                    money = scanner.nextDouble();
                    //money的范围应该校验,不可能为负数
                    if (money <= 0){
                        System.out.println("收益入账金额输入有误(小于等于0)");
                        break;
                    }
                    balance +=money;
                    date = new Date();//获取当前时间,需要SimpleDateFormat转换格式
                    //拼接收益入账信息到 details
                    details += "\n收益入账\t+" + money +"  "+ sdf.format(date) +"   余额:" + balance;
                    break;
                case "3":
                    if (balance == 0){
                        System.out.println("余额为0");
                        break;
                    }
                    System.out.print("消费金额:");
                    money = scanner.nextDouble();
                    //money的范围应该校验,不能超过余额balance
                    if (money <= 0 || money > balance){
                        System.out.println("消费金额有误(未在0-" + balance + "之间)");
                        break;
                    }
                    System.out.println("消费说明:");
                    note = scanner.next();
                    balance -= money;
                    date = new Date();
                    //拼接消费信息到 details
                    details += "\n"+ note + "\t-" + money +"  "+ sdf.format(date) +"   余额:" + balance;
                    break;
                case "4":
                    while (true){
                        //y表示是,n表示否
                        System.out.print("是否退出(y/n):");
                        choice = scanner.next();
                        if ("y".equals(choice) ||"n".equals(choice)){
                            break;
                        } else {
                            System.out.println("输入有误,请重新输入(y/n)");
                        }
                        //第二个方案,将两个功能写在一段代码里,即判断①是否输入的为y/n;②输入的是y还是n
//                        if ("y".equals(choice)){
//                            loop = false;
//                            break;
//                        }else if ("n".equals(choice)){
//                            System.out.println("程序继续");
//                            break;
//                        }else {
//                            System.out.println("输入有误,请重新输入(y/n)");
//                        }
                    }
                    if ("y".equals(choice)){
                        loop = false;
                    }else {
                        System.out.println("程序继续");
                    }
                    break;
                default:
                    System.out.println("输入号码有误,请重新输入(1-4).");
            }
        }while (loop);
        System.out.println("使用愉快,欢迎下次登陆~");
    }
}

2  零钱通(面向对象编程)

将面向过过程的代码改成面向对象的方法,编写SmallChangeSysOOP.java,完成改进后的1,2,3,4,5各个功能,并使用SmallChangeSysApp.java,创建对象,调用方法,完成测试。

//SmallChangeSysOOP类
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class SmallChangeSysOOP {
    //定义相关变量
    private boolean loop = true;
    private Scanner scanner = new Scanner(System.in);
    private String choseNum;

    //2.完成零钱通明细
    private String details ="--------------零钱通明细--------------";

    //3.完成收益入账
    //定义新的变量(根据功能),完成功能驱动程序员增加新的变化和代码
    private double money;//收入
    double balance;//余额
    private Date date;// date 是 Java.util.Date 的类,表示日期
    //将date转换为中国常用的格式
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //4.完成消费
    //定义新变量,保存消费的原因
    private String note;

    //5.退出
    //定义新变量,保存退出的标记
    private String choice;

    public boolean isLoop() {
        return loop;
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }

    //1.完成显示菜单,并可以选择菜单,给出相应的提示;
    public void ShowMenu(){
        do {
            System.out.println("\n==============零钱通菜单(OOP)==============");
            System.out.println("\t\t\t" + "1 零钱通明细");
            System.out.println("\t\t\t" + "2 收益入账");
            System.out.println("\t\t\t" + "3 消费");
            System.out.println("\t\t\t" + "4 退\t出");
            System.out.print("请选择(1-4):");
            choseNum = scanner.next();
            switch (choseNum) {
                case "1":
                    ShowDetails();
                    break;
                case "2":
                    CompleteEntry();
                    break;
                case "3":
                    CompleteConsume();
                    break;
                case "4":
                    ExitSys();
                    break;
                default:
                    System.out.println("输入号码有误,请重新输入(1-4).");
            }
        }while (loop);
    }

    //2.完成零钱通明细
    public void ShowDetails(){
        System.out.println(details);
    }

    //3.完成收益入账
    public void CompleteEntry(){
        System.out.print("收益入账金额:");
        money = scanner.nextDouble();
        //money的范围应该校验,不可能为负数
        if (money <= 0){
            System.out.println("收益入账金额输入有误(小于等于0)");
            return;
        }
        balance +=money;
        date = new Date();//获取当前时间,需要SimpleDateFormat转换格式
        //拼接收益入账信息到 details
        details += "\n收益入账\t+" + money +"  "+ sdf.format(date) +"   余额:" + balance;
    }

    //4.完成消费
    public void CompleteConsume(){
        if (balance == 0){
            System.out.println("余额为0");
            return;
        }
        System.out.print("消费金额:");
        money = scanner.nextDouble();
        //money的范围应该校验,不能超过余额balance
        if (money <= 0 || money > balance){
            System.out.println("消费金额有误(未在0-" + balance + "之间)");
            return;
        }
        System.out.println("消费说明:");
        note = scanner.next();
        balance -= money;
        date = new Date();
        //拼接消费信息到 details
        details += "\n"+ note + "\t-" + money +"  "+ sdf.format(date) +"   余额:" + balance;
    }
    //5.完成退出
    public void ExitSys(){
        while (true){
            //y表示是,n表示否
            System.out.print("是否退出(y/n):");
            choice = scanner.next();
            if ("y".equals(choice) ||"n".equals(choice)){
                break;
            } else {
                System.out.println("输入有误,请重新输入(y/n)");
            }
            //第二个方案,将两个功能写在一段代码里,即判断①是否输入的为y/n;②输入的是y还是n
//                        if ("y".equals(choice)){
//                            loop = false;
//                            break;
//                        }else if ("n".equals(choice)){
//                            System.out.println("程序继续");
//                            break;
//                        }else {
//                            System.out.println("输入有误,请重新输入(y/n)");
//                        }
        }
        if ("y".equals(choice)){
            loop = false;
        }else {
            System.out.println("程序继续");
        }
    }
}
//SmallChangeSysApp测试类

public class SmallChangeSysApp {
    public static void main(String[] args) {
        SmallChangeSysOOP smallChangeSysOOP = new SmallChangeSysOOP();

            smallChangeSysOOP.ShowMenu();

        System.out.println("使用愉快,欢迎下次登陆~");
    }
}

知识点

1  继承设计的基本思想

        父类的构造器完成父类属性的初始化,子类的构造器完成子类属性的初始化。

2  查看JDK源码

        放在想要查看的方法上面直接ctrl+B即可(这是我的快捷键)无快捷键可以右击,选择GO TO -> Declaration or Usages即可查看源码。

        若无法查看,可能是因为jdk包没有导入,可以File -> Project Structure -> SDKs -> Sourcepath,点击右侧的加号,选择自己安装jdk的路径,导入src.zip和javafx-src.zip即可。

3  得到当前日期

        先导入包:import java.util.Date

        Date date = new Date; //此时得到的日期格式是外国格式

        导入包:import java.text.SimpleDateFormat

        然后创建对象、转换日期格式:

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//注意大小写

        sdf.format(date);即可转换成功。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
B上的顺平老师的《Linux学习笔记》系列课程非常值得推荐。通过这个课程,我学到了很多关于Linux操作系统的知识和技能。 首先,老师在课程中详细介绍了Linux的基本概念和特点。我清楚地了解到Linux是一个开源的操作系统,具有稳定性、安全性和可定制性强的特点。这让我对Linux有了更深入的理解,也更有信心去学习和使用它。 其次,老师从基础开始,逐步讲解了Linux的安装和配置。他用简单明了的语言和实际操作的示范,帮助我了解了如何在虚拟机上安装Linux系统,并设置网络、用户账户、文件系统等。这为我后续的学习和实践打下了坚实的基础。 此外,老师还讲解了Linux的常用命令和工具。他详细介绍了常用的文件和目录操作命令,比如cd、ls、mkdir、cp等。同时,他还讲解了grep、sed、awk等强大的文本处理工具的使用方法。这些内容帮助我更加高效地进行文件管理和数据处理。 最后,老师还介绍了Linux的网络管理和安全防护。他讲解了如何配置网络连接、使用ssh远程登录以及设置防火墙等内容。这些知识对我了解网络和保护系统安全非常有帮助。 总的来说,顺平老师的《Linux学习笔记》课程非常实用,对于初学者来说是入门学习Linux的好选择。他通过深入浅出的讲解和丰富的实操示范,让我可以轻松地学习到Linux的基本知识和操作技巧。我相信通过学习这个课程,我会在Linux领域有更进一步的发展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值