常用类--Object类

Object类

程序示例

/*
        Object:Class Object是类Object结构的根。
                 每个班(class)都有Object作为超类。
                 所有对象(包括数组)都实现了这个类的方法。
                 每个类都直接或者间接的继承Object类

        Object类中的方法:
                 public int hashCode()返回对象的哈希码值。
                 支持这种方法是为了散列表,如HashMap提供的那样。
           注意:这里的哈希码值是根据哈希算法计算出来的一个值,这个值和地址有关系,但是并不是实际
                 的地址值。简单理解为地址值的另一种表现形式


                 public final 类 getClass()返回此Object的运行时类。
                 返回的类对象是被表示类的static synchronized方法锁定的对象。
                 
                 public String getName()返回由类对象表示的实体的名称
                (类,接口,数组类,原始类型或void),作为String 。
*/

public class Student2 extends Object{

}

public class StudentTest {
    public static void main(String[] args) {
      //创建Student2对象
        Student2 s = new Student2();
      //调用继承父类Object的hashCode()方法
        System.out.println(s.hashCode()); //输出:1163157884
      //了解了哈希算法是地址值的另一种表现形式,那我再创建一个对象
      //那么s1与s之间的哈希值是不是应该不一样
      //答案是不一定,因为它空间就那么大,你取模有可能发生不同的数值取模的结果是一样的。
        Student s1 = new Student();
        System.out.println(s1.hashCode()); //输出:1956725890
      
      //将s的地址值赋值给s2
        Student s2 = s;
        System.out.println(s2.hashCode()); //输出:1163157884

        System.out.println("*************************");
      
      //创建s3对象调用继承父类Object的getClass()方法
        Student s3 = new Student();
      //返回此Object的运行时类。
        System.out.println(s3.getClass()); //输出:class com.shujia.wyh.day18.Student

        Class c = s3.getClass();
        //public String getName()
        // 返回由类对象表示的实体的名称(类,接口,数组类,原始类型或void),作为String 。
        System.out.println(c.getName()); //输出:com.shujia.wyh.day18.Student

        System.out.println("****************************");
        //链式编程
        System.out.println(s3.getClass().getName());
    }
}

哈希算法图解:

/*
        public String toString()返回对象的字符串表示形式。
        一般来说, toString方法返回一个“textually代表”这个对象的字符串。
        结果应该是一个简明扼要的表达,容易让人阅读。 建议所有子类覆盖此方法。
        该toString类方法Object返回一个由其中的对象是一个实例,
        该符号字符`的类的名称的字符串@ ”和对象的哈希码的无符号的十六进制表示。
        换句话说,这个方法返回一个等于下列值的字符串:
                getClass().getName() + '@' + Integer.toHexString(hashCode())
                //Integer.toHexString(hashCode()):将hashCode()值反过来转成具体的地址值
                
        Integer类中有一个toHexString方法将哈希值转换成地址值
            public static String toHexString(int i)
            返回整数参数的字符串表示形式,作为16位中的无符号整数。


        我们虽然掌握了toString()的方法使用,但是呢打印的结果是一个地址值,我们拿到地址值是没有意义的

        我们正常打印一个对象,其实是想看该对象中的成员变量的值。
        又因为toString()方法的返回值是String类型,并且属于Object类中的
        而Object类是所有类的父类,那么我们自己定义类的时候,就可以重写该方法,重写里面的实现。
        将来调用toString()方法的时候,严格遵循编译看左,运行看右,所以调用的是重写后的方法。

        类最终写法:4.0版本:
            成员变量:private
            构造方法:无参,有参
            成员方法:getXxx()和setXxx(),..
            toString():自动生成即可
*/

public class Student3 {
    private String name;
    private int age;

    public Student3() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

  //自己重写的父类Object的toString()方法
//    @Override
//    public String toString() {
//        return  "姓名:" + name + ",年龄:" + age;
//    }

//自动生成的重写父类Object的toString()方法
    @Override
    public String toString() {
        return "Student3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class StudentTest2 {
    public static void main(String[] args) {
        Student3 s = new Student3();
      //调用继承自父类Object的toString()方法
      //返回对象的字符串表示形式。
        System.out.println(s.toString());//输出:com.shujia.wyh.day18.Student3@4554617c
      
        System.out.println("*************************");
        System.out.println(s.getClass().getName());
        System.out.println("*****************************");
      
        //toString()方法等价于以下内容
        //getClass().getName() + '@' + Integer.toHexString(hashCode())
        //s.getClass().getName() + "@" + Integer.toHexString(s.hashCode())
        //this.getClass().getName() + "@" + Integer.toHexString(this.hashCode())
        System.out.println(s.toString());
        System.out.println(s.getClass().getName()+"@"+Integer.toHexString(s.hashCode()));

        s.setName("小花");
        s.setAge(18);
      //这样重写后的toString()方法就代替了之前的show()方法
        System.out.println(s.toString());
    }
}
/*
        public boolean equals(Object obj)指示一些其他对象是否等于此。
        
        今后想要弄明白一个类中的方法是如何实现的时候,API也没告诉我们怎么办呢?
        
        看源码。将鼠标光标放在方法名上  ctrl+鼠标左键
        
        通过观察源码发现:Object类中的equals方法实现底层依旧是 ==
            public boolean equals(Object obj) {
                return (this == obj);
            }
        而==比较引用数据类型比较的是地址值,当地址值不一样的时候返回的是false

        ==:
          基本类型:比较的是值是否相同
          引用类型:比较的地址值是否相同

       equals:(为什么equals不能比较基本数据类型?因为调用equals方法的是一个对象,本身就不是基本数据类型了)
            引用数据类型:            
                不需要我们自己重写,自动生成即可
                重写之前,默认调用的是Object类中的equals方法,默认比较的是地址值
                重写之后,比较的是对象成员变量值
*/

import java.util.Objects;

public class Student4 {
    private String name;
    private int age;

    public Student4() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
  
 //重写的equals()方法
    @Override
    public boolean equals(Object o) { //s3.equals(s4)
        //this -- s3
        //o -- s4
      
      //先判断两者地址值是否相同
        if (this == o) return true;
      //在判断这个对象是不是null || 这两个对象的class文件是不是一样的
        if (o == null || getClass() != o.getClass()) return false;
      //然后o向下转型获取age和name,再去判断
        Student4 student4 = (Student4) o;
        return age == student4.age &&
                Objects.equals(name, student4.name);
    }
}


public class StudentTest3 {
    public static void main(String[] args) {
        Student4 s1 = new Student4("阿伟", 18);
        Student4 s2 = new Student4("阿伟", 18);
     //    new了两次
        System.out.println(s1==s2);//结果为false
      //将s1的地址值赋给了s3
        Student4 s3 = s1;
        System.out.println(s1==s3);//结果为true
      
        System.out.println("***************************");

        System.out.println(s1.equals(s2)); //false    equals()方法重写之后//结果为:true
        System.out.println(s1.equals(s3)); //true
        System.out.println(s1.equals(s1)); //true

        //但是,我们两个对象的成员变量值都一样,从现实生活角度出发,我们应该创建的是同一个学生
       // 所以我们想要重写继承自父类Object的equals()方法,让重写之后,比较的是对象成员变量值
        Student4 s4 = new Student4("小朱", 18);
        System.out.println(s3.equals(s4)); //输出结果:false
    }
}
/*
    protected void finalize()
                 throws Throwable当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。
                 一个子类覆盖了处理系统资源或执行其他清理的finalize方法。
                 这个方法简单理解为就是用来垃圾回收的,什么时候回收呢?
                 不确定。这里涉及到了GC机制

    protected Object clone()
            创建并返回此对象的副本。

    clone的方法Object执行特定的克隆操作。
    首先,如果此对象的类不实现接口Cloneable ,则抛出CloneNotSupportedException 。
    将想要调用克隆方法的类实现Cloneable接口
    通过观察API发现,Cloneable接口中没有成员变量也没有成员方法
    今后看到类似于Cloneable接口里面什么都没有的接口,我们称之为标记接口

    拷贝在IT行业中常见两种:
        浅拷贝
            拷贝的时候,重新创建一个对象,成员变量值和被拷贝的一样,但是后续修改与原先的没有关系
        深拷贝
            拷贝的时候,没有创建新的对象,只是改个名字,地址值都一样,修改拷贝后的连带影响到原先的
*/

import java.util.Objects;

public class Student5 implements Cloneable{//加上了实现克隆的接口
    private String name;
    private int age;

    public Student5() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student5 student5 = (Student5) o;
        return age == student5.age &&
                Objects.equals(name, student5.name);
    }

  //重写了继承自父类Object的clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class StudentTest4 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student5 s1 = new Student5("华根", 18);
      
        System.out.println(s1.toString());

        //CloneNotSupportedException//克隆不支持异常
       //当想要被克隆的类加上了实现克隆的接口,就可以被克隆
        //这里其实隐含了多态
      //Student5对象s1,克隆出来的还是Student5的对象
      //所以父类的引用指向子类的对象
        Object obj = s1.clone();

        System.out.println(obj.toString());//克隆过后发现 s1.toString() 和 obj.toString()输出结果一样
      
      //那我克隆有什么意义呢?现在我直接将s1赋给s2
        Student5 s2 = s1;
        System.out.println(s2.toString());//输出结果和 s1.toString() 一样
      //这样 s1.toString() 和 s2.toString()输出结果不还是一样的吗?

        System.out.println("**************************");
      //现在我将s2的年龄改为20岁
        s2.setAge(20);

        System.out.println(s1.toString());//我们发现当我们改了s2之后s1也跟着变了
        System.out.println(s2.toString());//s1与s2这样的拷贝方式是深拷贝
        System.out.println(obj.toString());//但是克隆出来的没有影响,所以克隆是浅拷贝
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值