017-Object和匿名内部类(老杜)

目录

Test01.java

Test02.java

Test03.java

Test04.java

Test05.java

Test06.java

Test07.java

匿名内部类

Test01.java


Test01.java

/*
    关于Object类中的toString()方法

        1、源代码长什么样?
            public String toString() {
                return this.getClass().getName() + "@" + Integer.toHexString(hashCode());
            }
            源代码上toString()方法的默认实现是:
                类名@对象的内存地址转换为十六进制的形式

        2、SUN公司设计toString()方法的目的是什么?
            toString()方法的作用是什么?
                toString()方法的设计目的是:通过调用这个方法可以将一个“java对象”转换成“字符串表示形式”

        3、其实SUN公司开发java语言的时候,建议所有的子类都去重写toString()方法。
        toString()方法应该是一个简洁的、详实的、易阅读的.
*/
public class Test01{
    public static void main(String[] args){
        MyTime t1 = new MyTime(1970, 1, 1);
        // 一个日期对象转换成字符串形式的话,我可能还是希望能看到具体的日期信息。
        String s1 = t1.toString();

        //MyTime类重写toString()方法之前
        //System.out.println(s1); // MyTime@28a418fc
        
        //MyTime类重写toString()方法之后
        System.out.println(s1); // 1970年1月1日

        
        //System.out.println(t1.toString()); //1970年1月1日

        // 注意:输出引用的时候,会自动调用该引用的toString()方法。
        System.out.println(t1);
    }
}
class MyTime{
    int year;
    int month;
    int day;

    public MyTime(){
    
    }

    public MyTime(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }

    // 重写toString()方法
    // 这个toString()方法怎么重写呢?
    // 越简洁越好,可读性越强越好。
    // 向简洁的、详实的、易阅读的方向发展
    public String toString(){
        //return this.year + "年" + this.month + "月" + this.day + "日";
        return this.year + "/" + this.month + "/" + this.day;
    }
}

Test02.java

/*
    关于Object类中的equals方法
        1、equals方法的源代码
            public boolean equals(Object obj) {
                return (this == obj);
            }
            以上这个方法是Object类的默认实现。
                
        
        2、SUN公司设计equals方法的目的是什么?
            以后编程的过程当中,都要通过equals方法来判断两个对象是否相等。
            equals方法是判断两个对象是否相等的。
        
        3、我们需要研究一下Object类给的这个默认的equals方法够不够用!!!!
                在Object类中的equals方法当中,默认采用的是“==”判断两个java对象
                是否相等。而“==”判断的是两个java对象的内存地址,我们应该判断
                两个java对象的内容是否相等。所以老祖宗的equals方法不够用,
                需要子类重写equals。
        
        4、判断两个java对象是否相等,不能使用“==”,因为“==”比较的是两个
        对象的内存地址。
*/
public class Test02{
    public static void main(String[] args){

        // 判断两个基本数据类型的数据是否相等直接使用“==”就行。
        int a = 100;
        int b = 100;
        // 这个“==”是判断a中保存的100和b中保存的100是否相等。
        System.out.println(a == b); //true(相等) false(不相等)

        // 判断两个java对象是否相等,我们怎么办?能直接使用“==”吗?
        // 创建一个日期对象是:2008年8月8日。
        MyTime t1 = new MyTime(2008, 8, 8); //MyTime t1 = 0x1234;
        // 创建了一个新的日期对象,但表示的日期也是:2008年8月8日。
        MyTime t2 = new MyTime(2008, 8, 8); //MyTime t2 = 0x3698;
        
        //测试以下,比较两个对象是否相等,能不能使用“==”???
        // 这里的“==”判断的是:t1中保存的对象内存地址和t2中保存的对象内存地址是否相等。
        System.out.println(t1 == t2); // false
        
        // 重写Object equals方法之前(比较的是对象内存地址)
        /*
        boolean flag = t1.equals(t2);
        System.out.println(flag); //false
        */
        

        // 重写Object equals方法之后(比较的是内容。)
        boolean flag = t1.equals(t2);
        System.out.println(flag); //true

        // 再创建一个新的日期
        MyTime t3 = new MyTime(2008, 8, 9);
        // 两个日期不相等,就是false。
        System.out.println(t1.equals(t3)); // false

        // 我们这个程序有bug吗?可以运行,但是效率怎么样?低(怎么改造。)
        MyTime t4 = null;
        System.out.println(t1.equals(t4)); //false
    }
}

class MyTime { //extends Object{
    int year;
    int month;
    int day;

    public MyTime(){
    
    }
    public MyTime(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }

    // 默认的equals方法
    /*
    public boolean equals(Object obj) {
        return (this == obj);
    }
    */

    /*
    // 重写Object类的equals方法
    // 怎么重写?复制粘贴。相同的返回值类型、相同的方法名、相同的形式参数列表。
    // equals到底应该怎么重写?你自己定,你认为两个对象什么相等的时候表示相等,你就怎么重写。
    public boolean equals(Object obj) {
        // 当年相同,月相同,并且日也相同的时候,表示两个日期相同。两个对象相等。
        // 获取第一个日期的年月日
        int year1 = this.year;
        int month1 = this.month;
        int day1 = this.day;

        // 获取第二个日期的年月日
        //int year2 = obj.year;
        //int month2 = obj.month;
        //int day2 = obj.day;

        if(obj instanceof MyTime){
            MyTime t = (MyTime)obj;
            int year2 = t.year;
            int month2 = t.month;
            int day2 = t.day;
            if(year1 == year2 && month1 == month2 && day1 == day2){
                return true;
            }
        }
        // 程序能够执行到此处表示日期不相等。
        return false;
    }
    */

    /*
    // 改良equals方法
    public boolean equals(Object obj) {
        // 如果obj是空,直接返回false
        if(obj == null){
            return false;
        }
        // 如果obj不是一个MyTime,没必要比较了 ,直接返回false
        if(!(obj instanceof MyTime)){
            return false;
        }
        // 如果this和obj保存的内存地址相同,没必要比较了,直接返回true。
        // 内存地址相同的时候指向的堆内存的对象肯定是同一个。
        if(this == obj){
            return true;
        }
        // 程序能够执行到此处说明什么?
        // 说明obj不是null,obj是MyTime类型。
        MyTime t = (MyTime)obj;
        if(this.year == t.year && this.month == t.month && this.day == t.day){
            return true;
        }

        // 程序能到这里返回false
        return false;
    }
    */

    
    //再次改良。
    /*
    public boolean equals(Object obj) {
        // 如果obj是空,直接返回false
        if(obj == null){
            return false;
        }
        // 如果obj不是一个MyTime,没必要比较了 ,直接返回false
        if(!(obj instanceof MyTime)){
            return false;
        }
        // 如果this和obj保存的内存地址相同,没必要比较了,直接返回true。
        // 内存地址相同的时候指向的堆内存的对象肯定是同一个。
        if(this == obj){
            return true;
        }
        // 程序能够执行到此处说明什么?
        // 说明obj不是null,obj是MyTime类型。
        MyTime t = (MyTime)obj;
        return this.year == t.year && this.month == t.month && this.day == t.day ;
    }
    */

    public boolean equals(Object obj) {
        if(obj == null || !(obj instanceof MyTime)){
            return false;
        }
        if(this == obj){
            return true;
        }
        MyTime t = (MyTime)obj;
        return this.year == t.year && this.month == t.month && this.day == t.day ;
    }

}

/*
class Person{
    private String idCard;
}
*/

Test03.java

/*
    java语言当中的字符串String有没有重写toString方法,有没有重写equals方法。

    总结:
        1、String类已经重写了equals方法,比较两个字符串不能使用==,必须使用equals。
        equals是通用的。

        2、String类已经重写了toString方法。
    
    大结论:
        java中什么类型的数据可以使用“==”判断
            java中基本数据类型比较是否相等,使用==

        java中什么类型的数据需要使用equals判断
            java中所有的引用数据类型统一使用equals方法来判断是否相等。
        
        这是规矩。
*/
public class Test03{
    public static void main(String[] args){

        // 大部分情况下,采用这样的方式创建字符串对象
        String s1 = "hello";
        String s2 = "abc";

        // 实际上String也是一个类。不属于基本数据类型。
        // 既然String是一个类,那么一定存在构造方法。
        String s3 = new String("Test1");
        String s4 = new String("Test1");
        // new两次,两个对象内存地址,s3保存的内存地址和s4保存的内存地址不同。
        // == 判断的是内存地址。不是内容。
        System.out.println(s3 == s4); // false

        // 比较两个字符串能不能使用双等号?
        // 不能,必须调用equals方法。
        // String类已经重写equals方法了。
        System.out.println(s3.equals(s4)); // true

        // String类有没有重写toString方法呢?
        String x = new String("动力节点");
        // 如果String没有重写toString()方法,输出结果:java.lang.String@十六进制的地址
        // 经过测试:String类已经重写了toString()方法。
        System.out.println(x.toString()); //动力节点
        System.out.println(x); //动力节点
    }
}

Test04.java

// String对象比较的时候必须使用equals方法。
public class Test04{
    public static void main(String[] args){
        /*
        Student s1 = new Student(111, "北京大兴亦庄二小");
        Student s2 = new Student(111, "北京大兴亦庄二小");
        System.out.println(s1 == s2); // false
        System.out.println(s1.equals(s2)); // true
        */

        Student s1 = new Student(111, new String("北京大兴亦庄二小"));
        Student s2 = new Student(111, new String("北京大兴亦庄二小"));
        System.out.println(s1 == s2); // false
        System.out.println(s1.equals(s2)); // true
    }
}

class Student{
    // 学号
    int no; //基本数据类型,比较时使用:==
    // 所在学校
    String school; //引用数据类型,比较时使用:equals方法。

    public Student(){}
    public Student(int no,String school){
        this.no = no;
        this.school = school;
    }

    // 重写toString方法
    public String toString(){
        return "学号" + no + ",所在学校名称" + school;
    }

    // 重写equals方法
    // 需求:当一个学生的学号相等,并且学校相同时,表示同一个学生。
    // 思考:这个equals该怎么重写呢?
    // equals方法的编写模式都是固定的。架子差不多。
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof Student)) return false;
        if(this == obj) return true;
        Student s = (Student)obj;
        return this.no == s.no && this.school.equals(s.school);

        //字符串用双等号比较可以吗?
        // 不可以
        //return this.no == s.no && this.school == s.school;
    }
}

Test05.java

// equals方法重写的时候要彻底。

public class Test05{
    public static void main(String[] args){
        
        // 多态(自动类型转换。)
        Object o1 = new String("hello world!");
        Object o2 = new User();
        Object o3 = new Address();

        User u1 = new User("zhangsan", new Address("北京","大兴区","11111"));
        User u2 = new User("zhangsan", new Address("北京","大兴区","11111"));

        System.out.println(u1.equals(u2)); // true

        User u3 = new User("zhangsan", new Address("北京","朝阳区","11112"));
        System.out.println(u1.equals(u3)); // false
    }
}

class User{
    // 用户名
    String name; 
    // 用户的住址
    Address addr;

    public User(){
    }
    public User(String name, Address addr){
        this.name = name;
        this.addr = addr;
    }

    // 重写equals方法
    // 重写规则:当一个用户的用户名和家庭住址都相同,表示同一个用户。
    // 这个equals判断的是User对象和User对象是否相等。
    public boolean equals(Object obj){
        // 用户名和用户名相同,住址和住址相同的时候,认定是同一个用户。
        if(obj == null || !(obj instanceof User)) return false;
        if(this == obj) return true;
        
        User u = (User)obj;
        if(this.name.equals(u.name) && this.addr.equals(u.addr)){
            return true;
        }
        return false;
    }
}

class Address{
    String city;
    String street;
    String zipcode;

    public Address(){
    
    }
    public Address(String city,String street,String zipcode){
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }

    // 注意:这里并没有重写equals方法。
    // 这里的equals方法判断的是:Address对象和Address对象是否相等。
    public boolean equals(Object obj){
        if(obj == null || !(obj instanceof Address)) return false;
        if(this == obj) return true;
        // 怎么算是家庭住址相同呢?
        // 城市相同,街道相同,邮编相同,表示相同。
        Address a = (Address)obj;
        if(this.city.equals(a.city) 
            && this.street.equals(a.street) 
            && this.zipcode.equals(a.zipcode)){
            return true;
        }
        return false;
    }
}

Test06.java

/*
    关于Object类中的finalize()方法。(非重点  非重点  非重点  了解即可。)

        1、在Object类中的源代码:
            protected void finalize() throws Throwable { }

            GC:负责调用finalize()方法。

        2、finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的。

        3、这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。
        不像equals toString,equals和toString()方法是需要你写代码调用的。
        finalize()只需要重写,重写完将来自动会有程序来调用。

        4、finalize()方法的执行时机:
            当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用
            finalize()方法。
        
        5、finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机。
        如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中。

        6、静态代码块的作用是什么?
            static {
                ....
            }
            静态代码块在类加载时刻执行,并且只执行一次。
            这是一个SUN准备的类加载时机。

            finalize()方法同样也是SUN为程序员准备的一个时机。
            这个时机是垃圾回收时机。

        7、提示:    
            java中的垃圾回收器不是轻易启动的,
            垃圾太少,或者时间没到,种种条件下,
            有可能启动,也有可能不启动。
*/
public class Test06{
    public static void main(String[] args){
        /*
        // 创建对象
        Person p = new Person();

        // 怎么把Person对象变成垃圾?
        p = null;
        */

        // 多造点垃圾
        /*
        for(int i = 0; i < 100000000; i++){
            Person p = new Person();
            p = null;
        }
        */
        
        for(int i = 0; i < 1000; i++){
            Person p = new Person();
            p = null;

            // 有一段代码可以建议垃圾回收器启动。
            if(i % 2 == 0){
                System.gc(); // 建议启动垃圾回收器。(只是建议,可能不启动,也可能启动。启动的概率高了一些。)
            }
        }        

    }
}

// 项目开发中有这样的业务需求:所有对象在JVM中被释放的时候,请记录一下释放时间!!!
// 记录对象被释放的时间点,这个负责记录的代码写到哪里?
// 写到finalize()方法中。
class Person{

    // 重写finalize()方法
    // Person类型的对象被垃圾回收器回收的时候,垃圾回收器负责调用:p.finalize();
    protected void finalize() throws Throwable {
        // this代表当前对象
        System.out.println(this + "即将被销毁!");
    }
}

Test07.java

/*
    hashCode方法:
        在Object中的hashCode方法是怎样的?
            public native int hashCode();

            这个方法不是抽象方法,带有native关键字,底层调用C++程序。
        
        hashCode()方法返回的是哈希码:
            实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值。
            所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址。
*/
public class Test07{
    public static void main(String[] args){
        Object o = new Object();
        int hashCodeValue = o.hashCode();

        // 对象内存地址经过哈希算法转换的一个数字。可以等同看做内存地址。
        System.out.println(hashCodeValue); //798154996

        MyClass mc = new MyClass();
        int hashCodeValue2 = mc.hashCode();
        System.out.println(hashCodeValue2); //1392838282

        MyClass mc2 = new MyClass();
        System.out.println(mc2.hashCode()); // 523429237
    }
}

class MyClass
{
}

匿名内部类

Test01.java

/*
    匿名内部类:

        1、什么是内部类?
            内部类:在类的内部又定义了一个新的类。被称为内部类。

        2、内部类的分类:
            静态内部类:类似于静态变量
            实例内部类:类似于实例变量
            局部内部类:类似于局部变量

        3、使用内部类编写的代码,可读性很差。能不用尽量不用。

        4、匿名内部类是局部内部类的一种。
            因为这个类没有名字而得名,叫做匿名内部类。
        
        5、学习匿名内部类主要是让大家以后在阅读别人代码的时候,能够理解。
        并不代表以后都要这样写。因为匿名内部类有两个缺点:
            缺点1:太复杂,太乱,可读性差。
            缺点2:类没有名字,以后想重复使用,不能用。
        
        6、不理解算了,你只要记住这种写法就行。
*/

class Test01{

    // 静态变量
    static String country;
    // 该类在类的内部,所以称为内部类
    // 由于前面有static,所以称为“静态内部类”
    static class Inner1{
    }
    
    // 实例变量
    int age;
    // 该类在类的内部,所以称为内部类
    // 没有static叫做实例内部类。
    class Inner2{
    }

    // 方法
    public void doSome(){
        // 局部变量
        int i = 100;
        // 该类在类的内部,所以称为内部类
        // 局部内部类。
        class Inner3{
        }
    }

    public void doOther(){
        // doSome()方法中的局部内部类Inner3,在doOther()中不能用。
    }

    // main方法,入口
    public static void main(String[] args){
        // 调用MyMath中的mySum方法。
        MyMath mm = new MyMath();
        /*
        Compute c = new ComputeImpl();
        mm.mySum(c, 100, 200);
        */
        
        //合并(这样写代码,表示这个类名是有的。类名是:ComputeImpl)
        //mm.mySum(new ComputeImpl(), 100, 200);
    
        // 使用匿名内部类,表示这个ComputeImpl这个类没名字了。
        // 这里表面看上去好像是接口可以直接new了,实际上并不是接口可以new了。
        // 后面的{} 代表了对接口的实现。
        // 不建议使用匿名内部类,为什么?
        // 因为一个类没有名字,没有办法重复使用。另外代码太乱,可读性太差。
        mm.mySum(new Compute(){
            public int sum(int a, int b){
                return a + b;
            }
        }, 200, 300);

    }

}

// 负责计算的接口
interface Compute{ 
    
    // 抽象方法
    int sum(int a, int b);
}

// 你自动会在这里编写一个Compute接口的实现类
/*
class ComputeImpl implements Compute{

    // 对方法的实现
    public int sum(int a, int b){
        return a + b;
    }
}
*/

// 数学类
class MyMath{
    // 数学求和方法
    public void mySum(Compute c, int x, int y){
        int retValue = c.sum(x, y);
        System.out.println(x + "+" + y + "=" + retValue);
    }    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值