equals 方法
/*
* Object:是Java中提供的一个根类
*   所有类都直接或间接的继承了 Object
*   如果一个类没有显示继承父类,那么该类默认继承 Object
*   Object 中的方法是所有类都有的功能
*   Object xxx = new xxx; 可以发生多态
*   如果一个方法需要传递数据,却不能确定数据的类型的时候,可以写 Object
*
* 学习方法
*   1 该方法属于哪个类
*   2 是什么方法(静态/成员)
*   3 功能、入参、出参分别是?(能实现什么,需要什么,返回什么)
*   4 什么时候需要重写(需求不能满足时)
*
* Object中的equals方法
*   源码:public Boolean equals(Object obj) {return (this == obj)}
*   目的:比较两个对象是否相等
*       两个对象可以代表任意实体,不同对象内存地址肯定不同,因此equals方法
*       不是比较内存地址,这时将两个对象对应得equals方法进行重写,以满足需求
*       因此此时可以比较对象间的属性来判断是否相等
*       不同类的对象,没有可比性
*
* == :两边如果是基本类型,则比较值得大小,如果是引用类型,则比较内存地址
* Object中equals默认比较 内存地址 return (this == obj)
* String 的底层是Char数组
* */

public class _01_Equals {

    public static void main(String[] args) {
        _Equ_Student stu1 = new _Equ_Student(18,"小明");
        _Equ_Student stu2 = new _Equ_Student(10,"小明");

        System.out.println(stu1 == stu2); // 内存地址不相等
        System.out.println(stu1.equals(stu2)); // 重写equals方法,自定义对象相等条件

    }
}

class _Equ_Student{
    private int age;
    private String name;

    public _Equ_Student() {
        super(); // 默认存在,默认继承Object
    }

    public _Equ_Student(int age, String name) {
        super(); // 默认存在,默认继承Object
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    // 需求 name与age相等就判断两个对象相等
    // 转换成基本数据类型的比较
    @Override
    public boolean equals(Object obj) {
        // 1 比较地址,地址相同 值一定相同,地址相同说明是同一个对象
        if (this == obj) return true;
        // 2 判断 对象类型 是否为当前类类型,否返回false,不同类没有可比性
        if (obj instanceof _Equ_Student){
            // 3 强制转换,比较想要比较的数据
            _Equ_Student stu2 = (_Equ_Student) obj;
            // name调用的是String类型的equals,是引用类型
            return name.equals(stu2.name) && age == stu2.age;
        }
        return false;
    }
}

/*
* 比较字符串是否相等
*   用equals 因为 == 比较的是内存地址
*   在string类中 已经重写了equals方法,重写后比较的是 值 不是地址
*
* 任何引用类型的比较,都必须转换成基本数据类型比较,除了比较地址是否一致
* 面向对象是哟中基本数据封装的形式,比较的时候最终要转换成基本数据类型比较,也就是比较相同属性是否具有相同的属性值
* */

public class _02_Equals {

    public static void main(String[] args) {
        String s1 = new String("a123");
        String s2 = new String("a123");

        String s3 = "a123";
        String s4 = "a123";

        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));

        System.out.println(s3 == s4);
        System.out.println(s3 == s1);
        System.out.println(s3.equals(s1));
    }
}
toString 方法
/*
* toString
*   设计目的:返回该对象的字符串表示形式
*
* 输出一个引用类型的时候,会自动调用该对象的toString方法
* 输出语句中:如果对象所属类中没有重写toString方法时,默认打印对象内存地址
*
* Object中的toString方法
*   public String toString(){
*       return getClass().getName() + "@" + Integer.toHexString(hashCode());
*   }
* */

public class _01_toString {

    public static void main(String[] args) {

        String s1 = new String("123a"); // String类里面重写了toString方法
        _01_toString s2 = new _01_toString();
        System.out.println(s1);
        System.out.println(s2);

        Person_toString xiaoming = new Person_toString(18, "小明");
        System.out.println(xiaoming);
        System.out.println("姓名:"+xiaoming.getName()+" ,年龄:"+xiaoming.getAge());
    }

    // 重写后自动调用当前对象的toString方法
    @Override
    public String toString() {
       return "_01_toString方法测试";
    }
}

class Person_toString{
    private int age;
    private String name;

    public Person_toString(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        // 通过重写toString方法来对当前对象进行描述
        return "姓名:"+name+" ,年龄:"+age;
    }
}
hashCode 方法
/*
* hashCode设计目的:给每一个对象生成一个唯一的标识符
*   同一个对象多次生成的 hash值 一定是一样的
*   不同对象生成的 hash值 也可能相同,这又叫哈希冲突
* 存在哈希冲突情况,如何保证数据的唯一性?
*   1 先比较hash,如果hash不同,则对象不同
*   2 如果hash值相同,在比较对象属性(equals)
*
* 覆写hashCode的时候,还需考虑? equals
* 覆写equals的时候,还需考虑? hashCode
* 因为在Java中,可以通过equals和hashCode来表示对象的唯一性
*
* hash算法:一种安全的加密算法,把不定长的值改为定长的值,但 不能保证其唯一性(哈希冲突)
* */

public class _01_hashCode {

    public static void main(String[] args) {
        _01_hashCode hc = new _01_hashCode();
        int hash = hc.hashCode(); // 460141958

        // 1b6d3586
        // Integer.toHexString(hash)将10进制转换成16进制
        // 当前类中重写后输出为1
        System.out.println(Integer.toHexString(hash));
        // com.tianl.oop._15_Object._01_hashCode@1b6d3586
        System.out.println(hc); // 默认打印内存地址
    }

    // 可根据需求重写hashCode()
//    @Override
//    public int hashCode() {
//        return 1;
//    }
}
finalize 方法
/*
* finalize 方法
*   垃圾被回收之前 自动调用该方法。属于Object
*   可覆写该方法实现定制化
*
* 1 finalize是每个对象都有的方法
* 2 不需要手动调用,有系统自动调用
* 3 Java中如果没有更多的引用指向这个对象,那么该对象被视为垃圾数据,等待被回收
*     被回收之前,自动调用finalize方法
* 4 finalize没有垃圾回收功能,只是用于被回收之前做一些操作,回收由JVM执行
*   所以就算手动调用,也只是一个普通的成员方法调用,和对象回收没有关系
* 5 一般用于对象回收之前做一些数据销毁操作
* */

public class _01_Finalize {

    public static void main(String[] args) {
        Animal_F animal_f = new Animal_F();
        animal_f = null;

        // 程序员只能建议 垃圾回收器回收
//        System.gc();
        // 如果垃圾过多,不用建议,自动回收
        for (int i = 0; i < 999999; i++) {
            new Animal_F();
        }
    }

}

class Animal_F{

    @Override
    protected void finalize() throws Throwable {
        System.out.println(this + "马上就要被回收了");
    }
}