一、多态性
多态在java中的体现是 父类的引用指向子类的对象
格式:
父类类型 变量名 = 子类对象
1、代码案例
vi Person.java
public class Person {
    public String name;
    public int age;
    //新增方法
    public void eat(){
        System.out.println("人吃饭");
    }
    public void sleep(){
        System.out.println("人睡觉");
    }
}
vi Man.java
//Man 类继承Person类
public class Man extends Person {
    boolean isSmoking;
    public void eat(){
        System.out.println("男人吃肉长肌肉");
    }
    public void walk(){
        System.out.println("男人走路");
    }
    public void earnMoney(){
        System.out.println("男人挣钱养家");
    }
}
vi Woman.java
public class Woman extends Person {
    boolean isBeauty;
    public void eat(){
        System.out.println("女人少吃减肥");
    }
    public void walk(){
        System.out.println("女人走路");
    }
    public void goShopping(){
        System.out.println("女人喜欢逛街");
    }
}
上面我们定义了一个父类,两个子类去继承所有方法和属性,两子类都重写了eat方法,并且拥有自己独立的其他方法,我们先测试一下
vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        //未使用多态性
        Person p1 =new Person();
        Man m1   =    new Man();
        //使用多态性
        //在声明子类的时候,使用父类接收
        Person p2 = new Man();
    }
}
我们可以将子类赋值给父类的变量,就是多态性,但是要求必须是子类才能我这样做
2、多态性的应用
目前为止我们依旧不知道多态能干啥,只知道用子类能声明给父类,上代码
vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        //未使用多态性
        Person p1 =new Person();
        Man m1   =    new Man();
        //使用多态性
        //在声明子类的时候,使用父类接收
        Person p2 = new Man();
        //多态性的应用
        p2.eat();
    }
}
返回
男人吃肉长肌肉有了一丝明悟,多个子类存在相同方法时,根据传入的子类自动区分不同子类下的方法
我们将man赋值person中去调用eat,发现他调用的还是man,但是我们在idea上点住ctrl 去点击eat发现跳转到person下面了
 
3、实现多态的条件
1、继承关系
    #存在继承关系的类之间才能够使用多态性
    #多态性通常通过一个父类用变量引用子类对象来实现。
2、方法重写
    #子类必须重写(Override)父类的方法。通过在子类中重新定义和实现父类的方法
    #可以根据子类的特点行为改变这个方法的行为,如猫和狗吃东西的独特行为。
3、父类引用指向子类对象
    #使用父类的引用变量来引用子类对象。这样可以实现对不同类型的对象的统一操作
    #而具体调用哪个子类的方法会在运行时多态决定4、多态案例展示
vi Main.java
class Animal {
    public void sound() {
        System.out.println("动物发出声音");
    }
}
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("狗发出汪汪声");
    }
}
class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("猫发出喵喵声");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog(); // 父类引用指向子类对象
        Animal animal2 = new Cat(); // 父类引用指向子类对象
        animal1.sound(); // 输出:狗发出汪汪声
        animal2.sound(); // 输出:猫发出喵喵声
    }
}
如果我们测试某个类型,比如动物类下面的犬类,那么拿到的类属性都是犬科下面的,如果什么都不声明,直接调用类,那么就是访问的类本身下面的,除非有子类以父类的形式赋值,不然都会优先调用默认的父类的方法,所以说想要多态,就得使用继承和重写才能去实现多态
5、多态的弊端

二、object类
在java中,如果没有定义类继承与那个父类,那么他会默认继承object类,java.lang.object可以理解为所有类的一个超类
 
1、object说明

2、objects的常用方法
clone(): 复制对象
equals(Object obj): 用于比较对象是否相等
finalize(): 在对象被垃圾回收前调用
getClass(): 返回对象的运行时类
hashCode(): 返回对象的哈希码值
toString(): 返回对象的字符串表示。
wait(), notify(), notifyAll(): 用于线程同步。1、clone 克隆
1、在Person类中实现Cloneable接口。
2、重写clone()方法,并在方法中调用super.clone()进行对象的浅拷贝。
3、处理CloneNotSupportedException异常vi Person.java
public class Person implements Cloneable {
    public String name;
    public int age;
    public void eat() {
        System.out.println("人吃饭");
    }
    public void sleep() {
        System.out.println("人睡觉");
    }
    //实现Cloneable接口,并重写了clone()方法以支持对象的克隆
    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            // 处理异常
            e.printStackTrace();
            return null;
        }
    }
}
vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 未使用多态性
        Person p1 = new Person();
        p1.name = "Alice";
        p1.age = 30;
        // 使用克隆创建新对象
        Person p2 = (Person) p1.clone();
        p2.name = "Bob";
        p2.age = 25;
        // 输出两个对象的信息
        System.out.println("Person 1 - Name: " + p1.name + ", Age: " + p1.age);
        System.out.println("Person 2 - Name: " + p2.name + ", Age: " + p2.age);
        //输出两个类的地址
        System.out.println("Person 1 - Name: " + p1.name + ", class: " + p1);
        System.out.println("Person 2 - Name: " + p2.name + ", class: " + p2);
    }
}返回
Person 1 - Name: Alice, Age: 30
Person 2 - Name: Bob, Age: 25
Person 1 - Name: Alice, class: Person@5b480cf9
Person 2 - Name: Bob, class: Person@6f496d9f2、finalize 垃圾回收
vi Person.java
public class Person implements Cloneable {
    public String name;
    public int age;
    public void eat() {
        System.out.println("人吃饭");
    }
    public void sleep() {
        System.out.println("人睡觉");
    }
    @Override
    protected void finalize() throws Throwable {
        try {
            // 执行清理操作,例如关闭资源等
            System.out.println("对象被垃圾回收前执行finalize()方法");
        } finally {
            super.finalize();
        }
    }
    @Override
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 未使用多态性
        Person p1 = new Person();
        p1.name = "Alice";
        p1.age = 30;
        // 使用克隆创建新对象
        Person p2 = (Person) p1.clone();
        p2.name = "Bob";
        p2.age = 25;
        // 输出两个对象的信息
        System.out.println("Person 1 - Name: " + p1.name + ", Age: " + p1.age);
        System.out.println("Person 2 - Name: " + p2.name + ", Age: " + p2.age);
        // 手动置空对象引用,触发垃圾回收
        p1 = null;
        p2 = null;
        // 强制调用垃圾回收
        System.gc();
    }
}在这个修改后的代码中,我们在
Person类中重写了finalize()方法,在该方法中执行了清理操作。在PersonTest类的main方法中,我们创建了两个Person对象p1和p2,然后手动将对象引用置空,以便触发垃圾回收。最后,通过调用System.gc()强制进行垃圾回收,从而使系统调用对象的finalize()方法这个方法在1.9之后会提示过时了,但是还能用,过时的原因是内部可能出现循环引用,导致此对象不能回收
3、equals 判断地址值是否相同
vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 未使用多态性
        Person p1 = new Person();
        Person p2 = new Person();
        //对比p1和p2的地址值,如果不同则返回false
        //equals 的作用是判断两个变量的地址值是否相同,因为new了两个地址值所以一定是不同的
        System.out.println(p1.equals(p2));
        System.out.println(p1);
        System.out.println(p2);
    }
}注意
自定义的类在没有重写Object中的equals方法的情况下,调用的就是object类中声明的equals,比较两个对象的引用地址是否相同,或者说比较两个对象是否指向了堆空间中的同一个对象实体,在实际开发中,针对自定义的类,镜像会去判断两个对象是否equals,而此时主要判断两个对象的属性值是否相等,所以我们需要重写object类的equals方法,关于如何重写,推荐调用idea自动实现
在IntelliJ IDEA中可以使用快捷键快速生成和重写equals()方法。以下是在IDEA中使用快捷键的步骤:
1、在Person类中,将光标放在类名或类中的任何位置。
2、按下快捷键Alt + Insert(或者在菜单栏中选择Code -> Generate...)。
3、在弹出的菜单中选择equals() and hashCode()选项。
4、在弹出的对话框中勾选需要比较的属性(如name和age),然后点击OK。
5、IDEA会自动生成equals()和hashCode()方法的代码。4、tostring 对象转换字符串
方法是用于将对象转换为字符串表示形式的方法。当我们需要以字符串形式输出对象的内容时,可以重写
toString()方法来定义对象的字符串表示方式。
vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 未使用多态性
        Person p1 = new Person();
        System.out.println(p1.toString());
    }
}返回
Person@3b07d329看起来和我们直接System.out.println执行的效果是一样的,其实他下面就是调用的tostring
像string file date 或者包装类等object的子类,他们都重写了object类的tostring() 在调用tosring是返回当前对象的实体内容
重写tostring

5、static 类变量(公共变量)
vi Person.java
public class Person {
    public String name;
    public Person(String name){
        this.name = name;
    }
}vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 未使用多态性
        Person p1 = new Person("你好1");
        Person p2 = new Person("你好2");
    }
}在上面的代码中变量name是一个实例/成员变量,他属于类的每一个对象,p1中的变更对p2没有影响,如果想要让成员变量被类的所有实例共享,就用static修饰即可,称为类变量
1、static格式

 
2、静态变量案例
vi Person.java
class Person {
    //变更为静态变量
    static String name;
}vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 未使用多态性
        Person p1 = new Person();
        Person p2 = new Person();
        p1.name = "123";
        System.out.println(p1.name);
        System.out.println(p2.name);
    }
}我们给公共变量static赋值后,哪怕是不同的对象中也存在
3、静态方法
静态方法随着类的加载而加载,可以通过 “类.静态方法" 直接调用
vi Person.java
class Person {
    //变更为静态变量
    static String name;
    //添加静态方法
    public static void  show(){
        System.out.println("你好");
    }
}静态方法不需要声明new,可以直接调用
vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 静态方法不需要声明new  直接调用
        Person.show();
    }
}静态方法可以直接在其他方法中通过方法名调用
vi Person.java
class Person {
    //变更为静态变量
    static String name;
    //添加静态方法
    public static void  show(){
        System.out.println("你好1");
    }
    public static void get(){
        //调用静态方法
        show();
        System.out.println("你好2");
    }
}vi PersonTest.java
public class PersonTest {
    public static void main(String[] args) {
        // 静态方法不需要声明new  直接调用
        Person.get();
    }
}4、什么时候使用静态
 




















