第四章 面对对象编程(中级部分)

面对对象编程(中级部分)

idea的使用

在这里插入图片描述

IDEA 常用快捷键

  1. 删除当前行, 默认是 ctrl + Y 自己配置 ctrl + d
  1. 复制当前行, 自己配置 ctrl + alt + 向下光标
  2. 补全代码 alt + /
  3. 添加注释和取消注释 ctrl + / 【第一次是添加注释,第二次是取消注释】
  4. 导入该行需要的类 先配置 auto import , 然后使用 alt+enter 即可
  5. 快速格式化代码 ctrl + alt + L
  6. 快速运行程序 自己定义 alt + R
  7. 生成构造器等 alt + insert [提高开发效率]
  8. 查看一个类的层级关系 ctrl + H [学习继承后,非常有用]
  9. 将光标放在一个方法上,输入 ctrl + B , 可以定位到方法 [学继承后,非常有用]
  10. 自动的分配变量名 , 通过 在后面假 .var [老师最喜欢的]
import java.util.Scanner;

public class ArrayTest {
    //使用IDEA开发一个Java项目testpro01,
    // 创建一个类MyTools,编写一个方法,
    // 可以完成对int数组冒泡排序的功能
    public static void main(String[] agrs) {
        Scanner scanner = new Scanner(System.in);
        Scanner scanner1 = new Scanner(System.in);


        //开始快捷键自动分配


        int[] arr = {1, 3, 5, 4, 2, 8, 6};
        MyTools mytool = new MyTools();
        mytool.bubble(arr);
        System.out.println("=====排序后的数组=====");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}
class Percon {
    String name;
    int age;

    //构造器-快捷键
    public Percon(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
class MyTools {
    public void bubble(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {//
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    int key = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = key;
                }
            }
        }
    }
}

模板快捷键

file - > settings -> editor -> Live templates -> 可以查看有哪些快捷键 / 可以自己增加模板

模板可以高效的完成开发,提高速度

public class TestTemplate {
    //main就是一个模板的快捷键
    public static void main(String[] args) {
        //sout模板快捷键
        System.out.println();
        
        //fori模板快捷键
        for (int i = 0; i < ; i++) {
            
        }
    }
}

包的三大作用

  1. 区分相同名字的类
  2. 当类很多时,可以含好的管理类
  3. 控制访问范围

基本语法:

package com.hspedu;
  1. package 关键字,表示打包
  2. com.hspedu:表示包名

包的本质:实际上就是创建不同的文件来、目录保存类文件

在这里插入图片描述

package com.use;

import com.xiaoqiang.Dog;

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();//对应开头引入的import的包名
        System.out.println(dog);//com.xiaoqiang.Dog@14ae5a5

        com.xiaoming.Dog dog1 = new com.xiaoming.Dog();
        System.out.println(dog1);//com.xiaoming.Dog@7f31245a
    }
}

包的命名

命名规则:

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

demo.class.exec1 错

demo.12a 错

demo.ab12.oa 对

命名规范:com.公司名.项目名.业务模块名

比如:com.hspedu.oa.model; com.hspedu.oa.controller;

  1. com.sina.crm.user(用户模块)
  2. com.sina.crm.order(订单模块)
  3. com.sina.crm.utils(工具类)

常用的包

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

如何引入包

package com.hspedu.pkg;

//注意:
//我们需要使用哪个类,就使用哪个类就好,不建议使用 *导入
import java.util.Arrays;
//import java.util.Scanner;//表示只会引入java.util 包下的Scanner
//import java.util.*;//表示将java.util 包下的所有类都导入
public class Import01 {
    public static void main(String[] args) {
    //使用系统提供 Arrays 完成 数组排序
        int[] arr = {-1,20,2,13,3};
        //系统提供了相关的类,可以方便完成 Arrays
        Arrays.sort(arr);
        //输出排序结果
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
        }
    }
}

包的注意事项

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

//import指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求
import java.util.Arrays;
import java.util.Scanner;

//类定义
public class PkgDetail {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] arr = {1,2,3,4};
        Arrays.sort(arr);
    }
}

类的定义仍待完善

package 包名;
class 类名{
	成员变量、属性;
    构造器;
    成员方法;
}

访问修饰符

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

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

在这里插入图片描述

注意事项:

  1. 修饰符可以用来修饰类中的属性,成员方法以及类
  2. 只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。
  3. 后面再讲子类的访问权限的问题
  4. 成员方法的访问规则和属性完全一样

面对对象编程三大特征

封装、继承、多态

封装

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

好处

  1. 隐藏实现细节 方法(连接数据库)< --调用(传入参数…)
  2. 可以对数据进行验证,保证安全合理

实现步骤(三步)

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

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

    1. public void setXxx(类型 参数名){//Xxx表示某个属性
          //加入数据验证的业务逻辑
          属性 = 参数名;
      }
      
  3. 提供一个公共的(public)get方法,用于获取属性的值

    1. public XX getXxx(){//权限判断
          return xx;
      }
      
  4. package com.hspedu.encap;
    
    public class Encapsulation01 {
        public static void main(String[] args) {
            //如果要使用快捷键Alt + r,需要先配置主类
            //第一次使用鼠标点击形式运行,后面就可以用了
            Person person = new Person();
            person.setName("叶根春");
            person.setAge(30);
            person.setSalary(30000);
            System.out.println(person.info());
    
            //如果我们自己使用构造器指定属性
            Person smith = new Person("smith", 2000, 50000);
            System.out.println("======smith的信息======");
            System.out.println(smith.info());
        }
    }
    /*
    不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。
    年龄合理就设置,否则给默认。年龄,必须在1 - 120之间
    年龄,工资不能直接查看,name的长度在2 - 6字符之间
    */
    class Person{
        public String name;
        private int age;
        private double salary;
    
        //构造器
        public Person() {
        }
        //有三个属性的构造器
        public Person(String name, int age, double salary) {
    //        this.name = name;
    //        this.age = age;
    //        this.salary = salary;
            //可以将set方法写在构造器中,这样仍然可以验证
            setName(name);//和this.setName(name)相当
            setAge(age);
            setSalary(salary);
        }
        //自己写getXxx 和 setXxx 太慢,可以使用快捷键
        //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;
        }
    }
    

封装练习

package com.hspedu.encap;

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account();
        account.setName("jack");
        account.setBalance(15);
        account.setPassword("123456");

        System.out.println("该账户的信息为:" + account.info());
    }
}
/*
创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
1.Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、
    密码(必须是6位),如果不满足,则给出提示信息,并给默认值
2.通过setXxx的方法给Account的属性赋值。
3.在AccountTest中测试
 */
public class Account {
    private String name;
    private double balance;
    private String password;

    //提供构造器


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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        int len = name.length();
        if(len >=2 && len <= 4) {
            this.name = name;
        }else{
            System.out.println("您的名字长度不符合,默认为空");
            this.name = "";
        }
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        if(balance > 20){
            this.balance = balance;
        }else{
            System.out.println("您的余额小于20,默认为20");
            this.balance = 20;
        }
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        int len = password.length();
        if(len == 6){
            this.password = password;
        }else {
            System.out.println("您设置的密码长度不符合规定,默认为空");
            this.password = "";
        }
    }
    //显示账户信息
    public String info(){
        //可以增加一个权限校验
        return "信息为:name=" + name + " 余额=" + balance + " 密码=" + password;
    }
}

继承

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

在这里插入图片描述

继承的基本语法

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

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

继承的细节

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

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

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

    1. public class ExtendsDetail {
          public static void main(String[] args) {
              System.out.println("====第一个对象====");
              Sub sub = new Sub();
      //        sub.sayOk();
              System.out.println("====第二个对象====");
              Sub sub1 = new Sub("jack");
          }
      }
      public class Base {//父类
          //4个属性
          public int n1 = 100;
          protected int n2 = 200;
          int n3 = 300;
          private int n4 = 400;
      //    public Base(){//无参构造器
      //        System.out.println("父类base()构造被调用....");
      //    }
          public Base(String name,int age){
              System.out.println("父类Base(String name,int age)构造被调用....");
          }
          //父类提供一个public的方法,返回n4
          public int getN4(){
              return n4;
          }
          public void test100(){
              System.out.println("test100");
          }
          protected void test200(){
              System.out.println("test200");
          }
          void test300(){
              System.out.println("test300");
          }
          private void test400(){
              System.out.println("test400");
          }
          public void callTest400(){//调用test400
              test400();
          }
      }
      public class Sub extends Base{//子类
          public Sub(){//构造器
              super("smith",10);//默认调用父类无参构造器
              System.out.println("子类sub()构造器被调用....");
          }
          //当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
          public Sub(String name){
              //do nothing
              super("tom",30);
              System.out.println("子类Sub()构造器被调用...");
          }
          public void sayOk(){
              //我们发现 父类的非private属性和方法
              //都可以访问
              //私有的属性和方法可以间接访问
              System.out.println(n1 + " " + n2 + " " + n3);
              test100();
              test200();
              test300();
              //test400();错误的
      
              System.out.println("n4 = " + getN4());
              callTest400();
          }
      }
      
  4. 如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表);

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

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

  1. java 所有类都是 Object 类的子类, Object 是所有类的基类.
  2. 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
  3. 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
  4. 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系

继承的本质

当子类创建好后,建立查找的关系

子类创建之后,从最顶级的父类依次向下挨个挨个创建属性。

在这里插入图片描述

子类访问属性(或者方法),从该子类开始依次向上查找该属性(或者方法),直到Object(不管该属性是否是私有,一旦找到就不再向上找;如果是私有的就不能直接访问)

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.getAge());
        System.out.println(son.hobby);
    }
}
class GrandPa{//爷爷类
    String name = "大头爷爷";
    String hobby = "旅游";
    int age = 89;
    //当在Father类中找到了age之后就不会再到Grandpa找age
    //GrandPa的age已经被Father的age挡住了,尽管这个age是私有的
}
class Father extends GrandPa{//父类
    String name = "大头爸爸";
    private int age = 39;
    public int getAge(){//可以通过公共方法来间接访问父类的私有属性
        return age;
    }
}
class Son extends Father{//子类
    String name = "大头儿子";
}

继承的练习

  1. package com.hspedu.extend_.exercise;
    
    public class ExtendsExercise01 {
        public static void main(String[] args) {
            B b = new B();
        }
    }
    
    class A {
        A() {
            System.out.println("a");
        }
    
        A(String name) {
            System.out.println("a name");
        }
    }
    
    class B extends A {
        B() {
            this("abc");//调用本类的方法(可以传入一个字符串的方法)
            System.out.println("b");
        }
    
        B(String name) {
            //这里隐藏了一个super();
            System.out.println("b name");
        }
    }
    //输出:
    //a
    //b name
    //b
    
  2. package com.hspedu.extend_.exercise;
    
    import com.hspedu.modifier.A;
    
    public class ExtendsExercise02 {
        public static void main(String[] args) {
            C02 c = new C02();
        }
    }
    
    class A02 {
        public A02() {
            System.out.println("我是A类");
        }
    }
    
    class B02 extends A02 {
        public B02() {
            System.out.println("我是B类的无参构造器");
        }
    
        public B02(String name) {
            System.out.println("我是B类的有参构造器");
        }
    }
    
    class C02 extends B02 {
        public C02() {
            this("hello");
            System.out.println("我是C类的无参构造器");
        }
    
        public C02(String name) {
            super("hahah");
            System.out.println("我是C类的有参构造器");
        }
    }
    //输出:
    //我是A类
    //我是B类的有参构造器
    //我是C类的有参构造器
    //我是C类的无参构造器
    
  3. package com.hspedu.extend_.exercise;
    
    public class ExtendsExercise03 {
        public static void main(String[] args) {
            PC pc = new PC("intel",16,"500g","IBM");
            pc.printInfo();
            System.out.println("=========");
            NotePad notePad = new NotePad("intel",8,"256g","黑色");
            notePad.printInfo();
        }
    }
    /*
     *编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
     * 编写PC子类,继承Computer类,添加特有属性【品牌color】
     * 编写NotePad子类,继承Computer类,添加特有属性【演示color】
     * 编写Test类,在mian方法中创建PC和NotePad对象,分别给对象中特有的属性
     * 赋值,以及从Computer类继承的属性赋值,使用方法并打印输出信息
     */
    class Computer{
        //编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
        private String Cpu;
        private int memory;
        private String disk;
        public Computer(String cpu, int memory, String disk) {
            Cpu = cpu;
            this.memory = memory;
            this.disk = disk;
        }
        //用于返回Computer的详细信息
        public String getDetails(){
            return "CPU:" + Cpu + " memory:" + memory + " disk:" + disk;
        }
        //get set
        public String getCpu() {
            return Cpu;
        }
    
        public void setCpu(String cpu) {
            Cpu = cpu;
        }
    
        public int getMemory() {
            return memory;
        }
    
        public void setMemory(int memory) {
            this.memory = memory;
        }
    
        public String getDisk() {
            return disk;
        }
    
        public void setDisk(String disk) {
            this.disk = disk;
        }
    }
    class PC extends Computer{
        //编写PC子类,继承Computer类,添加特有属性【品牌color】
        private String brand;
        //这里IDEA 根据继承的规则,自动把构造器的调用写好
        //这里也体现:继承设计的基本思想,父类的构造器完成父类属性初始化
        //子类的构造器完成子类属性初始化
        public PC(String cpu, int memory, String 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信息如下:");
            //调用父类的getDetails方法,得到相关属性...
            System.out.println(getDetails() + " brand:" + brand);
        }
    }
    class NotePad extends Computer{
        //编写NotePad子类,继承Computer类,添加特有属性【演示color】
        private String color;
    
        public NotePad(String cpu, int memory, String 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信息如下:");
            //调用父类的getDetails方法,得到相关属性...
            System.out.println(getDetails() + " color:" + color);
        }
    }
    

super关键字

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

基本语法

  1. 访问父类的属性,但不能访问父类的private属性(super.属性名)
  2. 访问父类的方法,不能访问父类的private方法(super.方法名)
  3. 访问父类的构造器:super(参数列表); 只能放在构造器的第一句,只能出现一句
public class Super01 {
    public static void main(String[] args) {
        
    }
}
public class A{
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;
    public A(){

    }
    public A(String name){

    }
    public A(int age){}

    public void test100(){
    }
    protected void test200(){
    }
    void test300(){
    }
    private void test400(){
    }
}
public class B extends A{
    //1. 访问父类的属性,但不能访问父类的private属性(super.属性名)
    public void hi(){
        System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
    }
    //2.访问父类的方法,不能访问父类的private方法(super.方法名)
    public void ok(){
        super.test100();
        super.test200();
        super.test300();
    }
    //3.访问父类的构造器:super(参数列表);   只能放在构造器的第一句,只能出现一句
    public B(){
        super("jack");
    }
}

super细节

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

  2. 当子类中由父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super , this , 直接访问是一样的效果!(访问方法和子类访问属性的原理是类似的,不过super访问,没有查找本类的过程)

    1. public class Super01 {
          public int n1 = 100;
          public static void main(String[] args) {
              B b = new B();
              b.sum();
          }
      }
      public class A{
          public int n1 = 8;
          public void cal(){
              System.out.println("A类的cal()方法...");
          }
      }
      public class B extends A{
          public void cal(){
              System.out.println("B类的cal()方法...");
          }
          public void sum(){
              System.out.println("B类的sum()");
              //希望调用父类——A 的cal方法
              //这时,因为子类B没有cal方法,因此我们可以使用下面三种方式
      
              //找cal方法时,顺序是:1.先找本类,如果有,则调用,如果没有就向上找
              //如果父类有,并且可以调用,则调用
              //如果父类没有就找父类的父类,直到Object
              //提示:如果查找方法的过程中,找到了该方法,
              //但是不能访问,就报错   cannot access
              //     如果查找方法的过程中,没有找到,则方法不存在
              cal();
              this.cal();//等价于cal();
              super.cal();//直接向上找,跳过本类是否有cal()
              
              //演示访问属性的规则
              //n1 和 this.n1 的查找规则和访问方法的规则是一样的
              //1.先找本类,如果有,则调用
              System.out.println(n1);
              System.out.println(this.n1);
              //本类没有就向上找,规则类似
              //提示:如果查找属性的过程中,找到了该方法,
              //但是不能访问,就报错   cannot access
              //     如果查找属性的过程中,没有找到,则方法不存在
              System.out.println(super.n1);
          }
      }
      
  3. super 的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)都有同名的成员,使用super访问遵循就近原则。(也要遵守访问权限的相关规则)A ->B ->C

super 和 this的比较

在这里插入图片描述

类的定义完善

package 包名;
class 类名 extends 父类{
    成员变量(属性);
    构造方法(构造器);
    成员方法(成员函数);
}

方法重写 / 覆盖(override)

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

方法重写的注意事项

  1. 子类方法的参数,方法名称,要和父类方法的参数,方法名称完全一样。

  2. 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类,比如:父类 返回类型是 Object,子类方法返回类型是String

    1. public Object m1(){}
      
      public String m1(){}//String 是 Object 的子类
      
  3. 子类方法不能缩小父类方法的访问权限(但是可以扩大访问权限

    1. public > proteced > 默认 > private

方法重写练习

  1. 在这里插入图片描述

  2. public class OverrideExercise {
        public static void main(String[] args) {
            Student student = new Student("jack",17,10,97);
            Person person = new Person("tom",18);
            System.out.println(person.say());
            System.out.println(student.say());
        }
    }
    //1) 编写一个 Person 类,包括属性/private(name、age),构造器、方法 say(返回自我介绍的字符串)。
    //2) 编写一个 Student 类,继承 Person 类,增加 id、score 属性/private,
    //        以及构造器,定义 say 方法(返回自我介绍的信息)。
    //3) 在 main 中,分别创建 Person 和 Student 对象,调用 say 方法输出自我介绍
    public class Person {
    //    编写一个 Person 类,包括属性/private(name、age),
    //    构造器、方法 say(返回自我介绍的字符串)。
        private String name;
        private int age;
    
        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 = " + name + "  age = " + age;
        }
    }
    public class Student extends Person{
    //    编写一个 Student 类,继承 Person 类,增加 id、score 属性/private,
    //    以及构造器,定义 say 方法(返回自我介绍的信息)。
        private int id;
        private double score;
    
        public Student(String name, int age, int id, double score) {
            super(name, age);
            this.id = id;
            this.score = score;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public double getScore() {
            return score;
        }
    
        public void setScore(double score) {
            this.score = score;
        }
    
        public String say(){//方法重写
            return super.say() + "\nid = " + id + "  score = " + score;
        }
    }
    

多态

在这里插入图片描述

提高代码的复用性,更有利于代码的维护

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

多态的具体体现

  1. 方法的多态(重载和重写就体现了多态)

    1. public class PolyMethod {
          public static void main(String[] args) {
              //方法重载体现多态
              A a = new A();
              //这里我们传入不同的参数,就会调用不同的sum方法
              //因此对sum方法来说,就是多种状态的体现
              System.out.println(a.sum(10, 20));
              System.out.println(a.sum(10, 20, 30));
      
              //方法重写体现多态
              B b = new B();
              a.say();
              b.say();
          }
      }
      class B{//父类
          public void say(){
              System.out.println("B say() 方法被调用...");
          }
      }
      class A extends B{//子类
          public int sum(int n1, int n2){//和下面的sum 方法构成了重载
              return n1 + n2;
          }
          public int sum(int n1, int n2, int n3){
              return n1 + n2 + n3;
          }
          public void say(){
              System.out.println("A say() 方法被调用...");
          }
      }
      
  2. 对象的多态(核心)

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

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

    3. 运行类型是可以变化的

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

    5. Animal animal = new Dog();//animal 编译类型是 Aniamal,运行类型是Dog
      animal = new Cat();//animal 的运行类型变成了 Cat,编译类型仍然是 Animal
      
    6. 在这里插入图片描述

多态的注意事项

第一部分

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

多态的向上转型

  1. 本质:父类的引用指向了子类的对象
  2. 语法:父类类型 引用名 = new 子类类型();
  3. 特点:编译类型看左边,运行类型看右边,
    1. 可以调用父类中的所有成员(需遵守访问权限)
    2. 不能调用子类中的特有成员;
    3. 最终运行效果看子类的具体实现

多态的向下转型

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

public class PolyDetail {
    public static void main(String[] args) {
        //向上转型:父类的引用指向了子类的对象
        //语法:父类类型     引用名 = new  子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//Object 也是 Cat的父类

        //1. 可以调用父类中的所有成员(需遵守访问权限)
        //2. 不能调用子类中的特有成员;
        //因为在编译阶段,能调用哪些成员,是由编译类型来决定的,
        // animal 不能调用 catchMouse方法
        //3.最终运行效果看子类的具体实现
        animal.eat();//猫吃鱼,调用方法时,从子类开始往上查找该方法
        animal.run();
        animal.show();
        animal.sleep();

        //现在希望可以调用Cat的,catchMouse方法
        //多态的向下转型
        //(1)语法:子类类型    引用名  =  (子类类型)父类引用;
        Cat cat = (Cat) animal;
        cat.catchMouse();//现在cat的编译类型是Cat ,运行类型也是Cat
        //(2)要求父类的引用必须指向的是当前目标类型的对象 、要
        // 求原来的animal 本来就是指向 Cat 的
        //Dog dog = (Dog)animal; 是错误的,
        // 因为animal原来就是Cat类型,不能把Cat 变成其他子类类型

    }
}
class Animal{
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello.你好");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}
class Dog extends Animal{

}
第二部分

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

package com.hspedu.poly_.detail_;

public class PolyDetail02 {
 public static void main(String[] args) {
     //属性没有重写之说!属性的值看编译类型
     Base base = new Sub();//向上转型
     //访问属性直接看编译类型,也就是说不看运行类型
     System.out.println("base 的count = " + base.count);//所以base.count = 10;

     Sub sub = new Sub();
     System.out.println("sub 的count = " + sub.count);//输出为 20;
 }
}
class Base{//父类
 int count = 10;
}
class Sub extends Base{//子类
 int count = 20;
}

第三部分

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

package com.hspedu.poly_.detail_;

public class PolyDetail03 {
 public static void main(String[] args) {
     BB bb = new BB();
     //instanceOf 比较操作符,用于判断对象的类型是否为XX类型或XX类型的子类型
     System.out.println(bb instanceof AA);
     System.out.println(bb instanceof BB);

     AA aa = new BB();
     //判断的是运行类型是否为XX或者XX类型的子类型
     System.out.println(aa instanceof BB);
     System.out.println(aa instanceof AA);
     
     Object obj = new Object();
     System.out.println(obj instanceof AA);//false
     String str = "hello";
     System.out.println(str instanceof Object);//true
	}
}
class AA{

}
class BB extends AA{

}

多态的练习

  1. package com.hspedu.poly_.exercise_;
    
    public class PolyExercise01 {
        public static void main(String[] args) {
            double d = 13.4;//ok
            long l = (long) d;//ok
            System.out.println(l);//ok
            int in = 5;//ok
            boolean b = (boolean) int;//不对
            Object obj = "hello";//ok,向上转型
            String objStr = (String) obj;//可以,向下转型
            System.out.println(objStr);//ok
    
            Object objPri = new Integer(5);//可以,向上转型
            String str = (String) objPri;
            //错误ClassCastExcetpion,不能把指向Integer的父类引用,转成String
            Integer str1 = (Integer) objPri;//可以向下转型
        }
    }
    
  2. package com.hspedu.poly_.exercise_;
    
    public class polyExercise02 {
        public static void main(String[] args) {
            Sub sub = new Sub();
            System.out.println(sub.count);//输出20
            sub.display();//输出20
            Base base = sub;//向上转型
            System.out.println(base == sub);//输出true
            System.out.println(base.count);//输出10
            base.display();//base的运行类型是Sub 调用Sub中的display的方法
        }
    }
    class Base{
        int count = 10;
        public void display(){
            System.out.println(this.count);
        }
    }
    class Sub extends Base{
        int count = 20;
    
        @Override
        public void display() {
            System.out.println(this.count);
        }
    }
    

java 的动态绑定机制(非常非常重要.)

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

public class DynamicBinding {
    public static void main(String[] args) {
        A a = new B();//向上转型
        System.out.println(a.sum());//输出40
        System.out.println(a.sum1());//输出30

        System.out.println("==========");
        //当子类的sum方法注销之后
        //a的编译类型是A ,运行类型是B
        System.out.println(a.sum());//输出30
        //注销B中的sum1之后
        System.out.println(a.sum1());//输出20
    }
}
class A{
    public int i = 10;
    //动态绑定机制:
    //1. 当调用对象方法的时候,该方法会和对象的内存地址、运行类型绑定
    //2. 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
    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 + 20;
//    }
    public int getI() {
        return i;
    }
//    public int sum1() {
//        return i + 10;
//    }
}

多态的应用

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

    1. package com.hspedu.poly_.polyarr_;
      
      public class PolyArray {
          public static void main(String[] args) {
              Person[] people = new Person[5];//对象数组
              people[0] = new Person("jack",10);
              people[1] = new Student("jack",18,85);
              people[2] = new Student("smith",19,30.1);
              people[3] = new Teacher("scott",30,200000);
              people[4] = new Teacher("king",50,25000);
      
              //调用每个对象的say()方法
              //循环遍历对象数组
              for (int i = 0; i < people.length; i++) {
                  //person[i] 编译类型是Person,运行类型是根据实际情况由JVM来调用的
                  System.out.println(people[i].say());//动态绑定机制
                  //要调用特有的方法,用向下转型
                  if(people[i] instanceof Student){
                      ((Student) people[i]).study();
                      //这句等同于 这两句话
                      //Student student = (Student) people[i];
                      //student.study();
                  }else if(people[i] instanceof Teacher){
                      ((Teacher) people[i]).teach();
                  }
              }
          }
      }
      /*
          1. 现有一个继承结构如下:要求创建1个Person对象,
              2个Student对象和2个Teacher对象,统一放在数组中,并调用每个对象的say方法
          2. 如何调用子类特有的方法,比如Teacher 有一个teach方法,Student有一个 study方法
       */
      public class Person {
          private String name;
          private int age;
      
          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 = " + name + "\t" + "age = " + age;
          }
      }
      public class Teacher extends Person{
          private double salary;
      
          public Teacher(String name, int age, double salary) {
              super(name, age);
              this.salary = salary;
          }
      
          public double getSalary() {
              return salary;
          }
      
          public void setSalary(double salary) {
              this.salary = salary;
          }
      
          @Override
          public String say() {
              return super.say() + "salary = " + salary;
          }
          //特有的方法
          public void teach(){
              System.out.println("老师:" + getName() + "正在授课...");
          }
      }
      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(int score) {
              this.score = score;
          }
      
          @Override
          public String say() {
              return super.say() + "score = " + score;
          }
          //特有的方法
          public void study(){
              System.out.println("学生:" + getName() + "正在上课...");
          }
      }
      
  2. **多态参数:**定义的形参类型为父类类型,实参类型允许为子类类型

    1. 前面的主人喂动物

    2. package com.hspedu.poly_.polyparameter_;
      
      public class PolyParameter {
          public static void main(String[] args) {
              Worker tom = new Worker("Tom",3500);
              Manage milan = new Manage("Milan", 5000, 15000);
              Test test = new Test();
              test.showEmpAnnual(tom);
              test.testWork(tom);
              test.showEmpAnnual(milan);
              test.testWork(milan);
          }
      }
      /*
      定义员工类Employee,包含姓名和月工资[private],以及计算年工资getAnnual
      的方法。普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage
      方法,普通员工类多了work方法,普通员工和经理类要求分别重写getAnnual方法
      
      测试类中添加一个方法showEmpAnnual(Employee),实现获取任何员工对象的年工资,
      并在main方法中调用该方法[e.getAnnual()]
      
      测试类中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,
      则调用manage方法
       */
      package com.hspedu.poly_.polyparameter_;
      
      public class Employee {
          private String name;
          private double salary;
      
          public Employee(String name, double salary) {
              this.name = name;
              this.salary = salary;
          }
          //计算年工资的方法
          public double getAnnual(){
              return 12 * 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;
          }
      }
      package com.hspedu.poly_.polyparameter_;
      
      public class Manage extends Employee{
          private double bonus;
      
          public Manage(String name, double salary, double bonus) {
              super(name, salary);
              this.bonus = bonus;
          }
      
          public void manage(){
              System.out.println("经理:" + getName() + "正在管理...");
          }
      
          @Override
          public double getAnnual() {
              return super.getAnnual() +  bonus;
          }
      }
      package com.hspedu.poly_.polyparameter_;
      
      public class Worker extends Employee{
          public Worker(String name, double salary) {
              super(name, salary);
          }
          public void work(){
              System.out.println("工人:" + getName() + "正在工作...");
          }
      
          @Override
          public double getAnnual() {//因为普通员工没有其他的收入,就直接调用父类的方法
              return super.getAnnual();
          }
      }
      package com.hspedu.poly_.polyparameter_;
      
      public class Test {
          public void showEmpAnnual(Employee employee){
              System.out.println(employee.getAnnual());
          }
          public void testWork(Employee employee){
              if(employee instanceof Worker){
                  ((Worker) employee).work();//向下转型
              }else if (employee instanceof Manage){
                  ((Manage) employee).manage();//向下转型
              }
          }
      }
      //    测试类中添加一个方法showEmpAnnual(Employee e),实现获取任何员工对象的年工资,
      //    并在main方法中调用该方法[e.getAnnual()]
      //  测试类中添加一个方法,testWork,如果是普通员工,则调用work方法,如果是经理,
      //  则调用manage方法
      

Object类详解

equals方法

经典面试题:==和equals的对比

== 的左右两边只要有一边是基本数据类型,就是判断值是相等

在这里插入图片描述

package com.hspedu.object_;

public class Equals01 {
 public static void main(String[] args) {
     A a = new A();
     A b = a;
     A c = b;
     System.out.println(a == c);//true 两个对象的地址是否相等

     B bObj = a;
     System.out.println(bObj == a);//true 
 }
}
class B{
}
class A extends B{
}

equals方法:

  1. equals:是Object类中的方法,只能判断引用类型,如何看Jdk源码
  2. 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer,String 【看String 和 Integer 的equals 源码】
//equals 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。
        Integer integer1 = new Integer(1000);
        Integer integer2 = new Integer(1000);
        System.out.println(integer1 == integer2);//false
        System.out.println(integer1.equals(integer2));//true

        String str1 = new String("hspedu");
        String str2 = new String("hspedu");
        System.out.println(str1 == str2);//false
        System.out.println(str1.equals(str2));//true

equals重写练习

  1. package com.hspedu.object_;
    
    public class EqualsExercise01 {
        public static void main(String[] args) {
            //判断两个Person对象的内容是否相等,
            // 如果两个Person对象的各个属性值都一样,则返回true,反之false
            Person person1 = new Person("jack", 10, '男');
            Person person2 = new Person("smith", 10, '男');
            //因为equals默认是判断地址是否相等,返回false
            //System.out.println(person1.equals(person2));
    
            //重写之后,就变成了对内容的判断
            System.out.println(person1.equals(person2));
        }
    }
    class Person{
        private String name;
        private int age;
        private char gender;
    
        //重写equals方法
        public boolean equals(Object obj){
            if(this == obj){//如果两个对象是同一个对象,则直接返回true
                return true;
            }
            if(obj instanceof Person){//如果obj是Person对象,再进行下一个阶段的判断
                //向下转型,得到obj的各个属性
                Person p = (Person) obj;
                if(this.name == p.name && this.age == p.age && this.gender == p.gender){
                    return true;
                }else{
                    return false;
                }
            }else{//如果不是Person类,则直接返回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;
        }
    }
    
    
  2. package com.hspedu.object_;
    
    public class EqualsExercise02 {
        public static void main(String[] args) {
            Person p1 = new Person();
            p1.name = "hspedu";
    
            Person p2 = new Person();
            p2.name = "hspedu";
            System.out.println(p1 == p2);//false
            System.out.println(p1.name.equals(p2.name));//true
            System.out.println(p1.equals(p2));//false
    
            String s1 = new String("asdf");
    
            String s2 = new String("asdf");
            System.out.println(s1.equals(s2));//因为equals方法以及被重写了,true
            System.out.println(s1 == s2);//String 为引用数据类型 ,true
        }
    }
    class Person{
        public String name;
    }
    
  3. package com.hspedu.object_;
    
    public class EqualsExercise03 {
        public static void main(String[] args) {
            int it = 65;
            float fl = 65.0f;
            System.out.println("65和65.0f是否相等?" + (it == fl));//true
            char ch1 = 'A';
            char ch2 = 12;
            System.out.println("65和‘A’是否相等?" + (it == ch1));//true
            System.out.println("12和ch2是否相等?" + (12 == ch2));//true
    
            String str1 = new String("hello");
            String str2 = new String("hello");
            System.out.println("str1和str2是否相等?" + (str1 == str2));//String是类 所以false
    
            System.out.println("str1是否equals str2?" + (str1.equals(str2)));//equals 方法被重写 true
            System.out.println("hello" == new java.sql.Date());//类型不一样,编译报错
        }
    }
    

    hashCode方法

    在这里插入图片描述

    1. 提高具有哈希结构的容器的效率!

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

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

    4. 哈希值主要根据地址号来的!,但是不能完全将哈希值等价于地址

    5. package com.hspedu.object_;
                                    
      public class HashCode_ {
          public static void main(String[] args) {
              AA aa = new AA();
              AA aa1 = new AA();
              AA aa2 = aa1;
              System.out.println("aa.hashCode() = " + aa.hashCode());
              System.out.println("aa1.hashCode() = " + aa1.hashCode());
              System.out.println("aa2.hashCode() = " + aa2.hashCode());
          }
      }
      class AA{}
      
    6. 后面在集合中的hashCode 如果需要的话,也会重写

toString 方法

基本介绍:

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

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

package com.hspedu.object_;

public class ToString_ {
    public static void main(String[] args) {
        /*
        Object 的toString() 源码
        (1)getClass().getName() 类的全类名(包名 + 类名)
        (2)Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串
        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
         */
        Monster monster = new Monster("小妖怪", "巡山的", 1000);
        System.out.println(monster.toString() + " hashCode = " + monster.hashCode());
        //重写之后
        System.out.println(monster);

    }
}
class Monster {
    private String name;
    private String job;
    private double sal;

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

    //重写 toString方法,输出属性
    //使用快捷键即可,alt + insert
    @Override
    public String toString() {//重写后一般是把对象的属性输出
        return "Monster{" +
                "name='" + name + '\'' +
                ", job='" + job + '\'' +
                ", sal=" + sal +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public double getSal() {
        return sal;
    }

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

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

System.out.println(monster);//相当于monster.toString

finalize方法

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

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

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

  4. package com.hspedu.object_;
                               
    //演示 Finalize的用法
    public class Finalize_ {
        public static void main(String[] args) {
            Car car = new Car("宝马");
            //置空,原本指向"宝马“对象的线,断掉了,垃圾回收器就会回收(销毁对象)
            //在销毁对象前,会调用该对象的finalize方法
            //这时程序员就可以在finalize中,写自己的业务逻辑代码,(比如释放资源:数据库连接,或者打开文件..)
            //如果程序员不重写finalize方法,那么就会调用 Object类的finalize,即默认处理
            //如果程序员重写了finalize,就可以实现自己的逻辑
            car = null;
            //并不是,一个对象变成一个垃圾之后就会马上回收的,有一套算法来决定
            System.gc();//主动调用垃圾回收机制
            System.out.println("程序退出...");
        }
    }
    class Car{
        private String name;
        public Car(String name){
            this.name = name;
        }
        //重写finalize
                               
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("我们销毁了汽车:" + name);
            System.out.println("我们释放了某些资源...");
        }
    }
                               
    
  5. 实际开发中几乎不会用,仅仅为了应付面试

断点调试

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

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

快捷键

  1. F7(跳入):跳入方法内
  2. F8(跳出):逐行执行代码
  3. shift + F8(跳出):跳出方法
  4. F9:(resume,执行到下一个断点)

在这里插入图片描述

断点可以在debug过程中,动态的下断点

零钱通

使用Java开发零钱通项目,可以完成收益入账,消费,查看明细,退出系统等功能

界面:

在这里插入图片描述

编写文件 SmallChan geSys.java 完成基本功能(过程编程)

面对过程编程

  1. 先完成显示菜单,并可以选择

  2. 完成零钱通明细

  3. 完成收益入账

  4. 完成消费

  5. package com.hspedu.smallchange;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Scanner;
    
    public class SmallChangeSys {
        //化繁为简
        //1.先完成显示菜单,并可以选择菜单,给出对应提示
        //2.完成零钱通明细
        //3.完成收益入帐
        //4.完成消费
        public static void main(String[] args) {
    
            //定义相关变量
            boolean loop = true;
            Scanner scanner = new Scanner(System.in);
            String key = "";
    
            //2.完成零钱通明细
            //(1)可以把收益入账和消费,保存到数组
            //(2)可以使用对象
            //(3)简单的话可以使用String拼接
            String details = "----------零钱通明细----------";
    
            //3.完成收益入账   完成功能驱动程序员增加新的变化和代码
            //定义新的变量
            double money = 0;
            double balance = 0;
            Date date = null;//date 是 java.util.Date 类型,表示日期
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");//可以用于日期格式化的
    
            //4.完成消费
            //(1)定义新变量保存消费的说明
            String note = "";
            do {
                System.out.println("==========零钱通菜单==========");
                System.out.println("\t\t1 零钱通明细");
                System.out.println("\t\t2 收益入账");
                System.out.println("\t\t3 消费");
                System.out.println("\t\t4 退  出");
    
                System.out.print("请选择(1-4):");
                key = scanner.next();
    
                //使用switch 分支控制
                switch (key){
                    case "1":
                        System.out.println(details);
                        break;
                    case "2":
                        System.out.println("收益入账的金额:");
                        money = scanner.nextDouble();
                        //money 的值范围应该校验
    
                        balance += money;
                        //拼接收益入账信息到 details
                        date = new Date();//获取当前的日期
                        details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t余额:" + balance;
                        break;
                    case "3":
                        System.out.println("消费的金额:");
                        money = scanner.nextDouble();
                        //money的范围也应该校验
    
                        System.out.println("消费的说明:");
                        note = scanner.next();
                        balance -= money;
                        //拼接消费的信息到details
                        date = new Date();//获取当前的日期
                        details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t余额:" + balance;
                        break;
                    case "4":
                        System.out.println("4 退    出");
                        loop = false;
                        break;
                    default:
                        System.out.println("菜单选择有误,请重新选择");
                }
            }while (loop);
            System.out.println("---------退出了零钱通---------");
        }
    }
    
    

改进

  1. 用户输入4退出时,给出提示”你确定要退出吗?y/n” ,必须输入正确的 y/n ,否则循环输入指令,直到输入 y 或者 n。
  2. 在收益入账和消费时,判断金额是否合理,并给出相应的提示
  3. 将面对过程的代码修改成面对对象的方法,编写 SmallChangeSysOOP.java 类,并使用 SmallChangeSysApp.java 完成测试
package com.hspedu.smallchange.oop;

/**
 *这里我们直接调用SmallChangeSysOOP 对象,显示主菜单
 */
public class SmallChangeSys {
    public static void main(String[] args) {
        SmallChangeSysOOP app = new SmallChangeSysOOP();
        app.mainMenu();
    }
}
package com.hspedu.smallchange.oop;

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

/**
 *该类是完成零钱通的各个功能的类
 * 使用OOP(面向对象编程)
 * 将各个功能对应一个方法
 */
public class SmallChangeSysOOP {
    //定义相关变量
    boolean loop = true;
    Scanner scanner = new Scanner(System.in);
    String key = "";

    //2.完成零钱通明细
    //(1)可以把收益入账和消费,保存到数组
    //(2)可以使用对象
    //(3)简单的话可以使用String拼接
    String details = "----------零钱通明细----------";

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

    //4.完成消费
    //(1)定义新变量保存消费的说明
    String note = "";

    //先显示主菜单,并可以选择
    public void mainMenu(){
        do {
            System.out.println("\n==========选择零钱通菜单(OOP)==========");
            System.out.println("\t\t 1 零钱通明细");
            System.out.println("\t\t 2 收益入账");
            System.out.println("\t\t 3 消费");
            System.out.println("\t\t 4 退  出");

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

            //使用switch 分支控制
            switch (key){
                case "1":
                    this.detail();//调用显示细节方法
                    break;
                case "2":
                    this.income();//调用收益入账方法
                    break;
                case "3":
                    //调用消费方法
                    this.pay();
                    break;
                case "4":
                    //调用退出方法
                    this.exit();
                    break;
                default:
                    System.out.println("菜单选择有误,请重新选择");
            }
        }while (loop);
    }

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

    //完成收益入账
    public void income(){
        System.out.println("收益入账的金额:");
        money = scanner.nextDouble();
        //money 的值范围应该校验,编程思想:
        //先找出不正确的金额的条件,然后给出提示,就直接return
        if(money <=0 ){
            System.out.println("收益入账金额应该大于 0");
            return;
        }

        balance += money;
        //拼接收益入账信息到 details
        date = new Date();//获取当前的日期
        details += "\n收益入账\t+" + money + "\t" + sdf.format(date) + "\t余额:" + balance;
    }

    //完成消费
    public void pay(){
        System.out.println("消费的金额:");
        money = scanner.nextDouble();
        //money的范围也应该校验
        if(money <= 0 || money > balance){
            System.out.println("你的消费金额应该在0-" + balance + "之间");
            return;
        }
        System.out.println("消费的说明(消费地点、用途):");
        note = scanner.next();
        balance -= money;
        //拼接消费的信息到details
        date = new Date();//获取当前的日期
        details += "\n" + note + "\t-" + money + "\t" + sdf.format(date) + "\t余额:" + balance;
    }

    //退出方法
    public void exit(){
        //(1)定义一个变量,choice 接受用户的输入
        //(2)使用 while + break,
        //(3)退出while之后,再判断choice是y还是n,
        //(4)建议一段代码完成一个小功能,尽量不要混在一起
        String choice = "";
        while (true){
            System.out.println("你确定要退出吗? y/n");
            choice = scanner.next();
            if(choice.equals("y") || choice.equals("n")){
                break;
            }else{
                System.out.println("您的输入有误,请重新输入");
            }
        }
        //当退出while,进行判断
        if (choice.equals("y")){
            loop = false;
        }
    }
}

本章的作业

1.

  1. package com.hspedu.homework;
    
    /**
     * 1.定义一个Person类{name,age,job},初始化Person对象数组,
     * 有3个person对象,并按照age从大到小 进行排序
     * 使用冒泡排序
     */
    public class Homework01 {
        public static void main(String[] args) {
            Person[] people = new Person[3];
            people[0] = new Person("jack",30,"打工");
            people[1] = new Person("smith",34,"公务员");
            people[2] = new Person("tom",18,"大学生");
    
            for (int i = 0; i < people.length - 1; i++) {
                for (int j = 0; j < people.length - i -1; j++) {
                    //按照age从大到小 进行排序
                    if(people[j].getAge() < people[j + 1].getAge()){
                        Person person = null;
                            person = people[j];
                            //先将people[j]的引用置空
                            people[j] = null;
                            //再让people[j]指向people[j + 1]的对象
                            people[j] = people[j + 1];
                            people[j + 1] = null;//和上面同理
                            people[j + 1] = person;
                    }
                }
            }
    
            for (int i = 0; i < people.length; i++) {
                System.out.println(people[i]);
            }
        }
    }
    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;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", job='" + job + '\'' +
                    '}';
        }
    
        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 getJob() {
            return job;
        }
    
        public void setJob(String job) {
            this.job = job;
        }
    }
    

    2.

  2. package com.hspedu.homework;
    
    /**
     * 写出四种访问修饰符各各自的权限
     * (1) public      同一个类  同一个包  不同类  不同包
     * (2) protected   同一个类  同一个包  不同类
     * (3) 默认        同一个类  同一个包
     * (4) private    同一个类
     */
    public class Homework02 {
        public static void main(String[] args) {
    
        }
    }
    

3.

  1. package com.hspedu.homework;
    
    /**
     * 编写老师类
     * (1)要求有属性“姓名name”,“年龄age”,“职称post”,“基本工资salary”
     * (2)编写业务方法,introduce(),实现输出一个教师的信息。
     * (3)编写教师类的三个子类:教授类(Professor),副教授类,讲师类。工资级别分别为:
     *      教授为1.3、副教授为1.2、讲师为1.1。在三个子类里面都重写父类的introduce()方法。
     * (4)定义并初始化一个老师对象,调用业务方法,实现对象基本信息的后台打印。
     */
    public class Homework03 {
        public static void main(String[] args) {
            Professor professor = new Professor("贾宝玉", 28, "高级职称", 20000, 1.3);
            professor.introduce();
        }
    }
    class Teacher{
        private String name;
        private int age;
        private String post;
        private double salary;
        //这里再增加一个工资级别
        private double grade;
    
        public Teacher(String name, int age, String post, double salary,double grade) {
            this.name = name;
            this.age = age;
            this.post = post;
            this.salary = salary;
            this.grade = grade;
        }
        //编写业务方法,introduce(),实现输出一个教师的信息
        public void introduce(){
            System.out.print("name:" + name + " age:" + age
                    + " post:" + post + " salary:" + salary);
        }
    
        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 getPost() {
            return post;
        }
    
        public void setPost(String post) {
            this.post = post;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
        public double getGrade() {
            return grade;
        }
    
        public void setGrade(double grade) {
            this.grade = grade;
        }
    }
    //编写教师类的三个子类:教授类(Professor),副教授类,讲师类。
    // 工资级别分别为 教授为1.3、副教授为1.2、讲师为1.1。
    // 在三个子类里面都重写父类的introduce()方法。
    class Professor extends Teacher{
        public Professor(String name, int age, String post, double salary,double grade) {
            super(name, age, post, salary,grade);
        }
    
        public void introduce() {
            System.out.println(" 这是教授的信息:");
            super.introduce();
        }
    }
    class AP extends Teacher{
        public AP(String name, int age, String post, double salary,double grade) {
            super(name, age, post, salary,grade);
        }
    
        public void introduce() {
            System.out.println(" 这是副教授的信息:");
            super.introduce();
        }
    }
    class Instruction extends Teacher{
        public Instruction(String name, int age, String post, double salary,double grade) {
            super(name, age, post, salary,grade);
        }
    
        public void introduce() {
            System.out.println(" 这是讲师的信息:");
            super.introduce();
        }
    }
    

4.

  1. package com.hspedu.homework;
    
    /**
     * 通过继承实现员工工资核算打印功能
     * 父类:员工类
     * 子类:部门经理类、普通员工类
     * 1. 部门经理工资 = 1000 + 单日工资 * 天数 * 等级(1.2)
     * 2. 普通员工工资 = 单日工资 * 天数 * 等级(1.0)
     * 3. 员工属性:姓名,单日工资,工作天数
     * 4. 员工方法(打印工资)
     * 5. 普遍员工及部门经理都是员工子类,需要重写打印工资方法
     * 6. 定义并初始化普通员工对象,调用打印工资方法输出工资,定义并初始化部门经理对象
     *    调用打印工资方法输出工资
     */
    public class Homework04 {
        public static void main(String[] args) {
            Manager manager = new Manager("刘备", 100, 20, 1.2);
            //设置奖金
            manager.setBonus(3000);
            //打印
            manager.printSal();
    
            Worker worker = new Worker("张飞", 90, 24, 1.0);
            //打印
            worker.printSal();
        }
    }
    class Employee {
        private String name;
        private double daySal;
        private int workDays;
        //分析出还有一个属性等级
        private double grade;
    
        public Employee(String name, double daySal, int workDays, double grade) {
            this.name = name;
            this.daySal = daySal;
            this.workDays = workDays;
            this.grade = grade;
        }
    
        //员工方法(打印工资)单日工资 * 天数 * 等级(1.0)
        public void printSal(){
            System.out.println( name + "的工资为:" + getDaySal() * getWorkDays() * getGrade());
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getDaySal() {
            return daySal;
        }
    
        public void setDaySal(double daySal) {
            this.daySal = daySal;
        }
    
        public int getWorkDays() {
            return workDays;
        }
    
        public void setWorkDays(int workDays) {
            this.workDays = workDays;
        }
    
        public double getGrade() {
            return grade;
        }
    
        public void setGrade(double grade) {
            this.grade = grade;
        }
    }
    class Manager extends Employee{
        private double bonus;
        //创建manager对象时奖金是多少是不确定的,所以在构造器中先不给bonus
        //可以通过setBonus来设置
        public Manager(String name, double daySal, int workDays, double grade) {
            super(name, daySal, workDays, grade);
        }
    
        //重写父类的方法 部门经理工资 = 1000 + 单日工资 * 天数 * 等级(1.2)
        @Override
        public void printSal() {
            //因为经理的工资计算和Employee不一样,直接完全重写
            System.out.println("经理" + getName() + "的工资为:" + (getDaySal()
                    * getWorkDays() * getGrade() + getBonus()));
        }
    
        public double getBonus() {
            return bonus;
        }
    
        public void setBonus(double bonus) {
            this.bonus = bonus;
        }
    }
    class Worker extends Employee{
        public Worker(String name, double daySal, int workDays, double grade) {
            super(name, daySal, workDays, grade);
        }
    
        @Override
        public void printSal() {
            super.printSal();
        }
    }
    
    

5.

package com.hspedu.homework;

/**
 * 设计一个父类 员工类,子类:工人类worker,
 * 农民类Peasant,教师类,科学家类Scientist,服务生类Waiter,
 * 1. 其中工人,农民,服务生,只有基本工资
 * 2. 教师除基本工资外,还有课酬(元/天)
 * 3. 科学家除基本工资外,还有年终奖
 * 编写一个测试类,将各种类型的员工的全年工资打印出来
 */
public class Homework05 {
    public static void main(String[] args) {

    }
}
class Employee1 {
    private String name;
    private double basicSal;

    public Employee1(String name, double basicSal) {
        this.name = name;
        this.basicSal = basicSal;
    }
    //打印全年工资
    public void printSal(){
        System.out.println("全年工资为:" + getBasicSal());
    }

    public String getName() {
        return name;
    }

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

    public double getBasicSal() {
        return basicSal;
    }

    public void setBasicSal(double basicSal) {
        this.basicSal = basicSal;
    }
}
class Teacher1 extends Employee1{
    private double daySal;

    public Teacher1(String name, double basicSal, double daySal) {
        super(name, basicSal);
        this.daySal = daySal;
    }

    //重写打印

    @Override
    public void printSal() {
        System.out.println("教师的年工资为:" + (getBasicSal() + getDaySal() * ));
    }

    public double getDaySal() {
        return daySal;
    }

    public void setDaySal(double daySal) {
        this.daySal = daySal;
    }
}

6.

package com.hspedu.homework;

/**
 * 假定Gand,Father,Son在同一个包,问:
 * 父类和子类中通过this和super都可以调用哪些方法和属性
 */
public class Homework06 {
    public static void main(String[] args) {

    }
}
class Grand{
    String name = "AA";
    private int age = 100;
    public void g1(){}
}
class Father extends Grand{
    String id = "001";
    private double score;
    public void f1(){
        //super可以访问哪些成员(属性和方法)?
        // g1()方法,super.name
        //this可以访问哪些成员?
        // id,score属性 f1()方法 this.name  this.g1()
    }
}
class Son extends Father{
    String name = "BB";
    public void g1(){}
    private void show(){
        //super可以访问哪些成员(属性和方法)?
        // g1(),f1()方法 super.name super.id
        //this可以访问哪些成员?
        // 本类的name属性 g1(),show()方法  this,id     this.f1()
    }
}

7.

package com.hspedu.homework;

/**
 * 写出程序的结果
 */
public class Homework07 {
}
class Test{
    String name = "Rose";
    Test(){
        System.out.println("Test");
    }
    Test(String name){
        this.name = name;//这里把父类的 name 改成了 john
    }
}
class Demo extends Test{
    String name = "Jack";
    Demo(){
        super();
        System.out.println("Demo");
    }
    Demo(String s){
        super(s);
    }
    public void test(){
        System.out.println(super.name);
        System.out.println(this.name);
    }

    public static void main(String[] args) {
        //匿名对象
        new Demo().test();//输出 Test Demo Rose Jack
        new Demo("john").test();//输出 John jack
    }
}

8.

package com.hspedu.homework;

/**
 * 1,在上面的基础上扩展新类CheckingAccount对每次存款和取款都收取1美元的手续费
 * 2,扩展前一个练习的BankAccount类,新类SavingsAccount每个月都有利息产生
 *  (earnMonthlyInterrest方法被调用),并且有每个月三次免手续费的存款或取款。
 *      在earnMonthlyInterest方法中重置交易计数
 * 3,体会重写的好处
 */
public class Homework08 {
    public static void main(String[] args) {
//        CheckingAccount checkingAccount = new CheckingAccount(1000);
//        checkingAccount.deposit(10);// 1010 - 1 = 1009
//        System.out.println(checkingAccount.getBalance());

        //测试SavingsAccount方法
        SavingsAccount savingsAccount = new SavingsAccount(1000);
        savingsAccount.deposit(100);
        savingsAccount.deposit(100);
        savingsAccount.deposit(100);
        System.out.println(savingsAccount.getBalance());
        savingsAccount.deposit(100);
        System.out.println(savingsAccount.getBalance());//1400 - 1 = 1399

        //月初,定时器自动调用一下 earnMonthlyInterest
        savingsAccount.earnMonthlyInterest();
        System.out.println(savingsAccount.getBalance());//余额加了多少钱1399 + 13.99 * 0.01
        savingsAccount.withdraw(100);//取款100 免手续费
        System.out.println(savingsAccount.getBalance());
    }
}
class BankAccount{
    private double balance;//余额
    public BankAccount(double initialBalance){
        this.balance = initialBalance;
    }
    //存款
    public void deposit(double amount){
        balance += amount;
    }
    //取款
    public void withdraw(double amount){
        balance -= amount;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}
class CheckingAccount extends BankAccount{//新的账号
    public CheckingAccount(double initialBalance) {
        super(initialBalance);
    }

    @Override
    public void deposit(double amount) {
        super.deposit(amount - 1);//巧妙地使用了父类的deposit
        //1 块钱入银行的账号
    }

    @Override
    public void withdraw(double amount) {
        super.withdraw(amount + 1);
        //1 块钱入银行的账号
    }
}
//扩展前一个练习的BankAccount类,新类SavingsAccount每个月都有利息产生
//(earnMonthlyInterrest方法被调用),并且有每个月三次免手续费的存款或取款。
//在earnMonthlyInterest方法中重置交易计数
class SavingsAccount extends BankAccount{
    //增加新属性
    private int count = 3;
    private double rate = 0.01;//利率

    public void earnMonthlyInterest(){//每个月初,我们统计上个月的利息,同时将count = 3
        count = 3;//
        super.deposit(getBalance() * rate);
    }

    @Override
    public void deposit(double amount) {
        //判断是否还可以免手续费
        if(count > 0){
            super.deposit(amount);
        }else {
            super.deposit(amount - 1);
        }
        count--;//减去一次
    }

    @Override
    public void withdraw(double amount) {
        if(count > 0){
            super.withdraw(amount);
        }else {
            super.withdraw(amount + 1);
        }
        count--;//减去一次
    }

    public SavingsAccount(double initialBalance) {
        super(initialBalance);
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }
}

9.

package com.hspedu.homework;

/**
 * 设计一个Point类,其x和y坐标可以通过构造器提供。
 * 提供一个子类LabeledPoint,其构造器接受一个标签值和x,y坐标,
 * 比如:new LabeledPoint("Balck Thursday" ,1929,230.07),写出对应的构造器即可
 */
public class Homework09 {
    public static void main(String[] args) {
        LabeledPoint labeledPoint = new LabeledPoint("Balck Thursday", 1929, 230.07);
    }
}
class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}
class LabeledPoint extends Point{
    //属性
    private String label;
    //方法


    public LabeledPoint(String label,double x, double y ) {
        super(x, y);
        this.label = label;
    }
}

10.

package com.hspedu.homework;

/**
 * 编写Doctor类{name,age,job,gender,sal}
 * 相应的getter()和setter()方法,5个参数的构造器,
 * 重写父类的equals()方法:public boolean equals(Object obj),
 * 并判断测试类中创建的两个对象是否相等。相等就是判断属性是否相同
 */
public class Homework10 {
    public static void main(String[] args) {

    }
}
class Doctor {
    private String name;
    private int age;
    private String job;
    private String gender;
    private double sal;

    public boolean equals(Object obj){
        if(this == obj){//如果是同一个对象
            return true;
        }else if(obj instanceof Doctor){//不是同一个对象
            //向下转型,得到obj的各个属性
            Doctor doctor1 = (Doctor) obj;
            if(this.name == doctor1.name && this.age == doctor1.age
                    && this.job == doctor1.job && this.gender == doctor1.gender
                    && this.sal == doctor1.sal){
                return true;
            }else {//如果不是Doctor类的
                return false;
            }
        }else {
            return false;
        }
    }
    public Doctor(String name, int age, String job, String gender, double sal) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.gender = gender;
        this.sal = sal;
    }

    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 getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public double getSal() {
        return sal;
    }

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

11.

package com.hspedu.homework;

public class Homework11 {
    public static void main(String[] args) {
        Person02 student = new Student();
        //向上转型
        //可以调用父类中的所有成员(需遵守访问权限)
        //不能调用子类中的特有成员,可以调用子类重写的方法,动态绑定机制
        //最终运行效果看子类的具体实现
        student.run();
        student.eat();

        //可以调用子类类型中所有的成员
        Student student1 = (Student) student;
        student1.run();
        student1.study();
        student1.eat();
    }
}
class Person02 {
    public void run(){
        System.out.println("person run");
    }
    public void eat(){
        System.out.println("person eat");
    }
}
class Student extends Person02 {
    @Override
    public void run() {
        System.out.println("student run");
    }
    public void study(){
        System.out.println("student study..");
    }
}

12.

//写出== 和 equals 的区别 

//==   是比较运算符  可以判断基本数据类型,判断值是否相等  可以判断引用类型,判断两个对象是否指向同一个对象


//equals 是Object类的方法 Java类都可以用equals  不可以用于判断基本数据类型  可以判断引用类型,判断两个对象的地址是否相等,但是子类往往重写该方法,比较对象属性是否相等,比如:String int

13.

14.

package com.hspedu.homework.Homework13_;

public class Homework14 {
    public static void main(String[] args) {
        C c = new C();
        //输出
        //我是A类
        //hahah我是B类的有参构造器
        //我是C类的有参构造器
        //我是C类的无参构造器
    }
}
class A{
    public A(){
        System.out.println("我是A类");//(1)
    }
}
class B extends A{
    public B(){
        System.out.println("我是B类的无参构造器");
    }
    public B(String name){
        System.out.println(name + "我是B类的有参构造器");//(2)
    }
}
class C extends B{
    public C(){
        this("hello");
        System.out.println("我是C类的无参构造器");//(4)
    }
    public C(String name){
        super("hahah");
        System.out.println("我是C类的有参构造器");//(3)
    }
}

15.

什么是多态,多态的具体体现有哪些?

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

多态的具体体现:

  1. 方法多态:
    1. 重载体现多态
    2. 重写体现多态
  2. 对象多态
    1. 对象的编译类型和运行类型可以不一致,编译类型在定义时,就确定,不能变化
    2. 对象的运行类型是可以变化的,可以通过getClass() 方法来查看运行类型
    3. 编译类型看定义时 = 的左边 ,运行类型是看 = 的右边

16.

Java的动态绑定机制是什么?

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

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 getJob() {
    return job;
}

public void setJob(String job) {
    this.job = job;
}

public String getGender() {
    return gender;
}

public void setGender(String gender) {
    this.gender = gender;
}

public double getSal() {
    return sal;
}

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

}


### 11.

```java
package com.hspedu.homework;

public class Homework11 {
    public static void main(String[] args) {
        Person02 student = new Student();
        //向上转型
        //可以调用父类中的所有成员(需遵守访问权限)
        //不能调用子类中的特有成员,可以调用子类重写的方法,动态绑定机制
        //最终运行效果看子类的具体实现
        student.run();
        student.eat();

        //可以调用子类类型中所有的成员
        Student student1 = (Student) student;
        student1.run();
        student1.study();
        student1.eat();
    }
}
class Person02 {
    public void run(){
        System.out.println("person run");
    }
    public void eat(){
        System.out.println("person eat");
    }
}
class Student extends Person02 {
    @Override
    public void run() {
        System.out.println("student run");
    }
    public void study(){
        System.out.println("student study..");
    }
}

12.

//写出== 和 equals 的区别 

//==   是比较运算符  可以判断基本数据类型,判断值是否相等  可以判断引用类型,判断两个对象是否指向同一个对象


//equals 是Object类的方法 Java类都可以用equals  不可以用于判断基本数据类型  可以判断引用类型,判断两个对象的地址是否相等,但是子类往往重写该方法,比较对象属性是否相等,比如:String int

13.

14.

package com.hspedu.homework.Homework13_;

public class Homework14 {
    public static void main(String[] args) {
        C c = new C();
        //输出
        //我是A类
        //hahah我是B类的有参构造器
        //我是C类的有参构造器
        //我是C类的无参构造器
    }
}
class A{
    public A(){
        System.out.println("我是A类");//(1)
    }
}
class B extends A{
    public B(){
        System.out.println("我是B类的无参构造器");
    }
    public B(String name){
        System.out.println(name + "我是B类的有参构造器");//(2)
    }
}
class C extends B{
    public C(){
        this("hello");
        System.out.println("我是C类的无参构造器");//(4)
    }
    public C(String name){
        super("hahah");
        System.out.println("我是C类的有参构造器");//(3)
    }
}

15.

什么是多态,多态的具体体现有哪些?

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

多态的具体体现:

  1. 方法多态:
    1. 重载体现多态
    2. 重写体现多态
  2. 对象多态
    1. 对象的编译类型和运行类型可以不一致,编译类型在定义时,就确定,不能变化
    2. 对象的运行类型是可以变化的,可以通过getClass() 方法来查看运行类型
    3. 编译类型看定义时 = 的左边 ,运行类型是看 = 的右边

16.

Java的动态绑定机制是什么?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值