JavaLearn # 面向对象编程_3

Posted LRcoding

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaLearn # 面向对象编程_3相关的知识,希望对你有一定的参考价值。

1. 认识Object类

Object 类是所有类的基类,也就意味着所有的类,都具有Object类的属性和方法。

1.1 Object 类的常用方法

Object obj = new Object;
// ===================== public方法 ==========================
obj.toString();         // 将一个对象的内容转换为字符串
obj.equals("");         // 判断两个对象的内容是否相同,默认比较两个对象的 hashcode
obj.hashCode();         // 底层数据结构是哈希表,通过该方法计算哈希码
obj.getClass();         // 反射的时候使用,获取一个对象的结构信息
Obj.wait();             // 线程等待  多线程时使用   native声明的
obj.wait(1234);
obj.notify();           // 唤醒随机的一个等待线程  native声明的
obj.notifyAll();        // 唤醒所有等待的线程   native声明的

// ==================== protected方法 =======================  【【没法直接调用,可以重写】】
protected void finalize() throws Throwable() {}  // 垃圾回收某个对象之前,先调用其 finalize 方法
protected native Object clone() throws CloneNotSupportedException; // 克隆 快速复制

扩展:native关键字

  • native 方法就是 Java 调用非 Java代码的接口,该方法不是Java语言实现的,一般由C或C++实现。
  • 在定义 native 方法时,并不提供实现体,因为其实现体是由 非Java语言 在外面实现的。
  • Java可以通过 JNI 接口来调用其他语言,实现对操作系统底层的访问
  • JNI 是Java本机接口(Java Native Interface),是一个本机编程接口,它是Java软件开发工具箱(SDK)的一部分

1.2 == 和 equals 的区别联系

  • == : 比较是否相同
    • 基本数据类型: 比较的是 是否相同
    • 引用数据类型: 比较的是 地址 是否相同
  • equals() : 用于检测两个对象是否相等
    • Object 类的equals,底层使用的是 ==
    • 其他类的equals(比如String、Integer等进行了重写,比较对象的内容是否相同
public class Dog {
    private String color = "Dog color";
    private int age;
	private String nickName; // 昵称
    
    public Dog() {

    }

    public Dog(String color, int age, String nickName) {
        this.color = color;
        this.age = age;
        this.nickName = nickName;
    }
    
    /**
     * Object类的 equals 无法满足 “内容相同即相同”的逻辑,所以此处进行重写
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o) {
        // 两个引用对象指向同一个对象,直接返回true,【this 代表调用 equals 的对象】
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Dog dog = (Dog) o;
        // age 等属性省略了 this 关键字 【this.age】
        return age == dog.age &&
                nickName.equals(dog.nickName) &&
                color.equals(dog.color);
    }

    public static void main(String[] args) {
        Dog dog1 = new Dog("黑色", 3, "旺财");
        Dog dog2 = new Dog("黑色", 3, "旺财");
        dog1 == dog2;           // ==>    false
        dog1.equals(dog2);      // ==>    false  如果要有“内容相同即相同”的逻辑,就需要重写equals方法
    }
}

2. 组合

组合是 has-a 的关系,和继承(is-a)有区别,根据面向对象设计原则:组合/聚合复用原则,应该优先使用组合

  • 除非两个类之间是 “is-a” 的关系,才使用继承
  • 不要仅仅为了实现多态而使用继承,如果类之间没有"is-a"的关系,可以通过实现接口与组合的方式来达到相同目的

组合:在类中定义其他类的对象,作为成员变量

Cpu 类

public class Cpu {
    public void calc() {
        System.out.println("========= Cpu calc() ==========");
    }
}

public class AMDcpu extends Cpu {
    public void calc() {
        System.out.println("========= AMDcpu calc() ==========");
    }
}

public class IntelCpu extends Cpu {
    public void calc() {
        System.out.println("========= IntelCpu calc() ==========");
    }
}

Memory 类

public class Memory {
    public void store() {
        System.out.println("======= Memory store() ==========");
    }
}

Computer 类

public class Computer {
    // 使用组合
    private Cpu cpu = new Cpu();
    private Memory memory = new Memory();
    
    // 可以通过方法,根据传入的值动态的修改cpu
    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    public void work() {
        cpu.calc(); // 如果使用了继承(AMDcpu继承了Cpu),此处可以使用不同cpu的calc
        memory.store();
    }

    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.work();
        
        // 传入不同的值
        Cpu cpu = new AMDcpu();
        // Cpu cpu = new IntelCpu();
        computer.setCpu(cpu);
        computer.work();
    }
}

3. 多态

面向对象三大特征之一。同一行为(方法)通过不同的子类调用,可以体现出不同的形态

3.1 引入和使用多态

现实生活中,例如同样是调用人的“休息”方法,张三是睡觉,李四是旅游等。

编译期类型指的是 “=” 左边的类型,运行期类型指的是 “=” 右边的类型。当有继承关系时,可能存在编译期类型是父类,运行期类型是子类,即:父类引用指向子类对象。

要点

  • 多态是方法的多态,不是属性的!!!!
  • 多态的存在要有 3 个必要条件:【继承】,【方法重写】,【父类引用指向子类对象】
  • 父类引用指向子类对象后,用该父类引用调用子类重写的方法,多态就出现了
  • 使用最多的场合是:使用父类做方法的形参,实参可以是任意子类的对象

Programmer 类:

public class Programmer {
    private String name;

    /**
     * 子类继承的方法
     */
    public void coding() {
        System.out.println("pro coding....");
    }

    /**
     * 子类重写的方法
     */
    public void eat() {
        System.out.println("pro eating....");
    }
}

ChinesePro 类:

public class ChinesePro extends Programmer{
    // 继承的方法:coding()

    // 重写的方法
    @Override
    public void eat() {
        System.out.println("Chinese eating....");
    }

    // 特有的方法
    public void playBoxing() {
        System.out.println("Chinese play shadowBoxing....");
    }
}

EnglishPro 类:

public class EnglishPro extends Programmer{
    // 继承的方法 coding()

    // 重写的方法
    @Override
    public void eat() {
        System.out.println("EnglishPro eating....");
    }

    // 特有的方法
    public void raceHorse() {
        System.out.println("EnglishPro raceHorse....");
    }
}

没有使用多态前

public class Test {
    // 不同国家的程序员声明不同的方法
    public static void showEat(Programmer pro) {
        pro.eat();
    }
    public static void showEat(ChinesePro pro) {
        pro.eat();
    }
    public static void showEat(EnglishPro pro) {
        pro.eat();
    }

    public static void main(String[] args) {
        // 代码重复
        Programmer pro = new Programmer();
        showEat(pro);

        ChinesePro ch = new ChinesePro();
        showEat(ch);
    }
}

使用多态后

public class Test {
    /**
     * 使用父类做方法的形参
     * @param pro
     */
    public static void showEat(Programmer pro) {
        pro.eat();
    }

    public static void main(String[] args) {
        Programmer pro = new Programmer();
        showEat(pro);

        // 第一种形式:父类做方法的形参,子类做调用方法时的实参
        ChinesePro ch = new ChinesePro();
        /**
         * 实参可以为任意子类的对象的引用
         */
        showEat(ch);  // Chinese eating....

        
        // 第二种形式:父类引用指向子类对象  ==>  父类 obj = new 子类();
        Programmer pro1 = new EnglishPro();
        pro1.eat();  // EnglishPro eating....
        //pro1.raceHorse();  ==>  无法调用子类特有的方法!!!
    }
}

开闭原则OCP

  • 对扩展开放(增加子类等),对修改关闭(不修改方法)
  • 应该在不修改现有代码的基础上,引入新功能
  • 这是面向对象设计需要遵守的最高原则,也是最终目标。

3.2 向上转型

子类对象赋给父类引用,称为向上转型(upcasting),自动进行类型转换。

// 基本数据类型的类型转换
int n = 20;
double d;
d = n;   // 自动类型转换

// 引用数据类型的类型转换
Programmer pro = new ChinesePro();  // 自动转换(向上转型 upcasting)
pro.coding();        // 如果调用从父类【继承的方法】,执行父类的
pro.eat();           // 如果调用被子类【重写的方法】,执行子类的
pro.playBoxing();    // 无法调用子类【特有的方法】

3.3 向下转型

向上转型时,父类的引用无法调用子类特有的方法。如果想调用,就需将父类的引用强制转换为子类的引用(向下转型)

// 基本数据类型的类型转换
double d = 3.14;
int n = (int) d; // 强制转换


// 引用类型的类型转换
Programmer pro = new ChinesePro();
// pro.playBoxing();   父类无法调用子类的方法
ChinesePro ch = (ChinesePro) pro; // 需要强制转换,但是只能转换为【真实的】子类类型
ch.playBoxing();


// 可以在强转之前进行判断
if (pro instanceof ChinesePro) {
    ChinesePro ch1 = (ChinesePro) pro;
} else if(pro instanceof EnglishPro) {
    EnglishPro en = (EnglishPro) pro;
}

instanceof: 变量是否属于某个类或者接口(必须在类的继承树上有上下级关系才能使用)

3.4 简单工厂模式–返回值是父类类型

不仅可以使用父类方法的形参,还可以使用父类做方法的返回值类型,真实返回的对象可以是该类的任意一个子类对象。

  • 返回值 :父类类型
  • static声明,可以通过类名直接调用
  • 传入一个String类型的参数 type,工厂根据 type 生产对应类型的商品
  • 不符合开闭原则,并不是 23 种设计模式种的一种
public class TestPoly {
    public static void main(String[] args) {
        // 此处是直接new的,相当于自己创建的
        Programmer pro = new ChinesePro();

        // 实际应该是,有专门的工厂负责生产对象,我们只需从工厂里获取即可。
        Programmer ch = factorDemo.getProgrammer("ch");
        
    }
}

// 生产对象的工厂
class factorDemo {
    public static Programmer getProgrammer(String type) {
        Programmer pro = null;
        if ("ch".equals(type)) {
            pro = new ChinesePro();
        } else if ("en".equals(type)) {
            pro = new EnglishPro();
        }
        return pro;
    }
}

简单工厂模式并不是 23 种经典设计模式的一种,是其中工厂方法模式的简化版。

4. 设计模式

23种 经典的设计模式,是一套优秀代码设计经验的总结。每个设计模式均是特定环境下特定问题的处理方式。

面向对象设计原则 是面向对象设计的基石,设计模式是面向对象设计原则的经典应用。

创建型模式

  • 工厂方法模式
  • 抽象工厂模式
  • 创建者模式
  • 原型模式
  • 单例模式

结构型模式

  • 外观模式
  • 适配器模式
  • 代理模式
  • 装饰模式
  • 桥接模式
  • 组合模式
  • 享元模式

行为型模式

  • 模板方法模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 职责链模式
  • 命令模式
  • 访问者模式
  • 调停者模式
  • 备忘录模式
  • 迭代器模式
  • 解释器模式

面向对象设计原则

  • 单一职责原则
  • 开闭原则
  • 里氏替代原则
  • 依赖注入原则
  • 接口分离原则
  • 迪米特原则
  • 组合/聚合复用原则

5. 面向对象三大特征综合练习

image-20210507210702155

Animal类:

public class Animal {
    private int age;

    public Animal() {

    }

    public Animal(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

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

    public void show() {
        System.out.println("今年" + this.age + "岁!");
    }

    @Override
    public String toString() {
        return "Animal{" +
                "age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Animal animal = (Animal) o;
        return age == animal.age;
    }
}

Fish类

public class Fish extends Animal {
    private int weight;

    public Fish() {

    }

    public Fish(int age, int weight) {
        super(age);
        this.weight = weight;
    }

    @Override
    public void show() {
        System.out.println("我是一只" + this.weight + "斤重的鱼。");
        super.show();
    }

    public void swimming() {
        System.out.println("我在水里悠闲吐泡");
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Fish{" +
                "weight=" + weight +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        boolean flag = super.equals(o);
        if (flag) {
            Fish fish = (Fish) o;
            return weight == fish.weight;
        } else {
            return false;
        }
    }
}

Test类:

public class Practice {
    public static void main(String[] args) {
        Animal an1 = new Fish(2, 5);
        an1.show();
        Fish fish = (Fish) an1;
        fish.swimming();
    }

}

class animalFactor{
    public static Animal getAnimal(String type) {
        Animal animal = null;
        if ("fish".equals(type)) {
            animal = new Fish();
        } else if ("bird".equals(type)){
            animal = new VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

JavaLearn # 面向对象案例:猜丁壳

Python基础-week06 面向对象编程进阶

读编程与类型系统笔记08_面向对象变成的元素

python之路之前没搞明白4面向对象(封装)