Java-面向对象

2023-01-04 14:10:17 浏览数 (1)

前言

哈喽!大家好,我是小简。今天开始学习《Java-面向对象》,此系列是我做的一个 “Java 从 0 到 1 ” 实验,给自己一年左右时间,按照我自己总结的 Java-学习路线,从 0 开始学 Java 知识,并不定期更新所学笔记,期待一年后的蜕变吧!<有同样想法的小伙伴,可以联系我一起交流学习哦!>

面向对象-基础

类与对象

成员方法

方法递归

方法重载

可变参数

作用域

构造方法

对象创建

this关键字

面向对象-中级

访问修饰符

封装

继承

super关键字

重写&重载

多态

多态引出

请编写一个程序,Master 类中有一个 feed 方法, 可以完成主人给动物喂食物的信息。

使用传统的方法来解决带来的问题是什么? 如何解决?

代码语言:javascript复制
public class Poly_ {
    public static void main(String[] args) {
        Master tom = new Master("Tom");
        Dog jack = new Dog("jack");
        Cat jerry = new Cat("jerry");
        Bone bone = new Bone("大骨头");
        Fish fish = new Fish("小鱼");

        tom.feed(jack,bone);
        tom.feed(jerry,fish);
    }
}

class Master {
    private String name;
    public Master(String name) {
        this.name = name;
    }
        //主人给小狗喂食骨头
     public void feed(Dog dog, Bone bone) {
        System.out.println("主人"   name   " 给"   dog.getName()   " 吃"   bone.getName());
     }
     //主人给小猫喂黄花鱼
     public void feed(Cat cat, Fish fish) {
        System.out.println("主人"   name   " 给"   cat.getName()   " 吃"   fish.getName());
     }
}

class Animal {
    private String name;
    public Animal(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}

class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}

class Food {
    private String name;
    public Food(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

class Bone extends Food {
    public Bone(String name) {
        super(name);
    }
}

class Fish extends Food {
    public Fish(String name) {
        super(name);
    }
}

带来的问题:

  • 如果动物很多,食物很多,feed 方法很多,不利于管理和维护
  • 代码的复用性不高,而且不利于代码维护

解决方案: 采用多态解决

代码语言:javascript复制
public class Poly_ {
    public static void main(String[] args) {
        Master tom = new Master("Tom");
        Dog jack = new Dog("jack");
        Cat jerry = new Cat("jerry");
        Bone bone = new Bone("大骨头");
        Fish fish = new Fish("小鱼");

        tom.feed(jack,bone);
        tom.feed(jerry,fish);

    }

}
class Master {
    private String name;
    public Master(String name) {
        this.name = name;
    }
    //使用多态机制,可以统一的管理主人喂食的问题
        //animal 编译类型是Animal,可以指向(接收) Animal 子类的对象
        //food 编译类型是Food ,可以指向(接收) Food 子类的对象
    public void feed(Animal animal, Food food) {
        System.out.println("主人"   name   " 给"   animal.getName()   " 吃"   food.getName());
    }
}

class Animal {
    private String name;
    public Animal(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}

class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}

class Food {
    private String name;
    public Food(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

class Bone extends Food {
    public Bone(String name) {
        super(name);
    }
}

class Fish extends Food {
    public Fish(String name) {
        super(name);
    }
}
多态介绍

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

重载和重写都体现了多态

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

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

运行类型是可以变化的

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

代码语言:javascript复制
Animal animal = new Dog();//animal编译类型是Animal,运行类型Dog
animal = new Cat(); //animal的运行类型变成了Cat, 编译类型仍然是Animal

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

多态的向上转型

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

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

代码语言:javascript复制
Animal animal = new Dog();

3)特点:编译类型看左边,运行类型看右边

  • 可以调用父类中的所有成员(需遵守访问权限)
  • 不能调用子类中特有成员(属性/方法)
  • 最终运行效果看子类的具体实现
代码语言:javascript复制
public class PolyDetail {
    public static void main(String[] args) {
        //向上转型: 父类的引用指向了子类的对象
        Animal_ animal = new Cat_();
      
        //可以调用父类中的所有成员(需遵守访问权限)
        animal.eat();//吃
        animal.sleep();//睡
      
        //不能调用子类中特有成员(属性/方法)
        animal.catchMouse();//错误写法
    }
}

class Animal_ {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void eat(){
        System.out.println("吃");
    }
}

class Cat_ extends Animal_ {
    @Override
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat 特有方法
        System.out.println("猫抓老鼠");
    }
}
多态的向下转型

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

代码语言:javascript复制
Dog dog = (Dog) animal;

2)只能强转父类的引用,不能强转父类的对象

3)要求父类的引用必须指向的是当前目标类型的对象

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

代码语言:javascript复制
public class PolyDetail {
    public static void main(String[] args) {
        Animal_ animal = new Cat_();
       //向下转型:希望可以调用Cat的catchMouse 方法
        Cat_ cat = (Cat_) anima;
        cat.eat();//吃
        cat.sleep();//睡
        cat.catchMouse();//特有方法也可调用
      
        //要求父类的引用必须指向的是当前目标类型的对象
        Dog dog = (Dog) animal; //错误写法
    }
}

class Animal_ {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void eat(){
        System.out.println("吃");
    }
}

class Cat_ extends Animal_ {
    @Override
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat 特有方法
        System.out.println("猫抓老鼠");
    }
}

class Dog_ extends Animal_ {//Dog 是Animal 的子类
}
属性重写问题

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

代码语言:javascript复制
public class PolyDetail02 {
        public static void main(String[] args) {
        //属性没有重写之说!属性的值看编译类型
        Base base = new Sub();//向上转型
        System.out.println(base.count);//看编译类型10

        Sub sub = new Sub();
        System.out.println(sub.count);//20
   }
}
class Base { //父类
        int count = 10;//属性
}
class Sub extends Base {//子类
        int count = 20;//属性
}
instanceOf

用于判断对象的运行类型是否为XX 类型或XX 类型的子类型

代码语言:javascript复制
public class PolyDetail03 {
      public static void main(String[] args) {
          BB bb = new BB();
          System.out.println(bb instanceof BB);//true
          System.out.println(bb instanceof AA);//true
          
          //BB 是AA 子类
          AA aa = new BB(); //aa 编译类型AA, 运行类型是BB
          System.out.println(aa instanceof AA);//true
          System.out.println(aa instanceof BB);//true
        
          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 {}//子类
动态绑定机制
  • 当调用对象方法的时候,该方法会和该对象的运行类型(内存地址)绑定
  • 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用
代码语言:javascript复制
public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型A, 运行类型B
        A a = new B();//向上转型
        //运行类型是B,先找B类里是否有sum,有就直接运行
        System.out.println(a.sum());//40 调用子类sum
        System.out.println(a.sum1());//30 调用子类sum1
    }
}
class A {//父类
    public int i = 10;
    public int sum() {//父类sum()
        return getI()   10;
    }
    public int sum1() {//父类sum1()
        return i   10;
    }
    public int getI() {//父类getI
        return i;
    }
}
class B extends A {//子类
    public int i = 20;

     @Override
     public int sum() {
         return i   20;
     }

    @Override
    public int getI() {//子类getI()
        return i;
    }

     @Override
     public int sum1() {
        return i   10;
     }
}
代码语言:javascript复制
public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型A, 运行类型B
        A a = new B();//向上转型 
        //运行类型是B,先找B类里是否有sum,没有就去父类找
        System.out.println(a.sum());//30 调用父类sum 和子类getI
        System.out.println(a.sum1());//20 调用父类sum 和父类i
    }
}
class A {//父类
    public int i = 10;
    //动态绑定机制
    public int sum() {//父类sum()
        return getI()   10;//20   10
    }
    public int sum1() {//父类sum1()
        return i   10;//10   10
    }
    public int getI() {//父类getI
        return i;
    }
}
class B extends A {//子类
    public int i = 20;
    @Override
    public int getI() {//子类getI()
        return i;
    }
}
多态的应用
多态数组

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

应用实例:现有一个继承结构如下:要求创建1 个Person 对象、2 个Student 对象和2 个Teacher 对象, 统一放在数组中,并调用每个对象 say 方法,如何调用子类特有的方法,比如 Teacher 有一个 teach , Student 有一个 study

怎么调用?

代码语言:javascript复制
public class PolyArray {
    public static void main(String[] args) {
        //应用实例:现有一个继承结构如下:要求创建1 个Person 对象、
        // 2 个Student 对象和2 个Teacher 对象, 统一放在数组中,并调用每个对象say 方法
        Person[] persons = new Person[5];
        persons[0] = new Person("jack", 20);
        persons[1] = new Student("mary", 18, 100);
        persons[2] = new Student("smith", 19, 30.1);
        persons[3] = new Teacher("scott", 30, 20000);
        persons[4] = new Teacher("king", 50, 25000);
        //循环遍历多态数组,调用say
        for (int i = 0; i < persons.length; i  ) {
            //person[i] 编译类型是Person ,运行类型是是根据实际情况有JVM 来判断
            System.out.println(persons[i].say());//动态绑定机制
            // 使用类型判断  向下转型
            if(persons[i] instanceof Student) {//判断person[i] 的运行类型是不是Student
                Student student = (Student)persons[i];//向下转型
                student.study();
            //也可以使用一条语句((Student)persons[i]).study();
            } else if(persons[i] instanceof Teacher) {
                Teacher teacher = (Teacher)persons[i];
                teacher.teach();
            } else if(persons[i] instanceof Person){
            System.out.println("不做处理...");
            } else {
                System.out.println("你的类型有误, 请自己检查...");
            }
        }
    }

}
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 String say() {//返回名字和年龄
        return name   "t"   age;
    }
}

class Student extends Person {
    private double score;
    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }
    //重写父类say
    @Override
    public String say() {
        return "学生"   super.say()   " score="   score;
    }
    //特有的方法
    public void study() {
        System.out.println("学生"   getName()   " 正在学java...");
    }
}


class Teacher extends Person {
    private double salary;
    public Teacher(String name, int age, double salary) {
        super(name, age);
        this.salary = salary;
    }
    //写重写父类的say 方法
    @Override
    public String say() {
        return "老师"   super.say()   " salary="   salary;
    }
    //特有方法
    public void teach() {
        System.out.println("老师"   getName()   " 正在讲java 课程...");
    }
}
多态参数

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

应用实例: 定义员工类 Employee,包含姓名和月工资[private],以及计算年工资 getAnnual 的方法。普通员工和经理继承了员工,经理类多了奖金 bonus 属性和管理 manage 方法,普通员工类多了 work 方法,普通员工和经理类要求分别重写 getAnnual 方法,测试类中添加一个方法 showEmpAnnual(Employee e),实现获取任何员工对象的年工资,并在 main 方法中调用该方法[e.getAnnual()] 测试类中添加一个方法,testWork,如果是普通员工, 则调用 work 方法,如果是经 理,则调用 manage方法

代码语言:javascript复制
public class PolyParameter {
    public static void main(String[] args) {
        Worker tom = new Worker("tom", 2500);
        Manager milan = new Manager("milan", 5000, 200000);
        PolyParameter.showEmpAnnual(tom);
        PolyParameter.showEmpAnnual(milan);
        PolyParameter.testWork(tom);
        PolyParameter.testWork(milan);
    }

    public static void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());
    }

    public static void testWork(Employee e) {
        if (e instanceof Worker) {
            ((Worker) e).work();//有向下转型操作
        } else if (e instanceof Manager) {
            ((Manager) e).manage();//有向下转型操作
        } else {
            System.out.println("不做处理...");
        }
    }
}

class Employee {
  private String name;
  private double salary;

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

  public String getName() {
    return name;
  }

  public double getSalary() {
    return salary;
  }

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

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

  public void work() {
    System.out.println("普通员工"   getName()   " is working");
  }

  @Override
  public double getAnnual() {
    return super.getAnnual();
  }
}

class Manager extends Employee {
  private double bonus;

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

  public void manage() {
    System.out.println("经理"   getName()   " is managing");
  }

  @Override
  public double getAnnual() {
    return super.getAnnual()   bonus;
  }
}

Object类

equals

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

== 和 equals 的对比

  • == 是一个比较运算符
    • 1.既可以判断基本类型,又可以判断引用类型
    • 2.如果判断基本类型,判断的是值是否相等。
    • 3.如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
  • equals 是 Object 类中的方法,只能判断引用类型,默认判断的是地址是否相等

如何重写 equals 方法

0 人点赞