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. 面向对象三大特征综合练习
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中的面向对象编程