Object类

基本概念

  • java.lang.Object类是Java语言中类层次结构的根类,任何一个类都是该类的直接或者间接子类
    • java.lang包下的类不用import导包
  • 如果定义一个Java类时没有使用extends关键字声明其父类,则其父类为 java.lang.Object 类
  • Object类定义了“对象”的基本行为, 被子类默认继承

常用方法

  • Object() :使用无参方式构造对象

  • boolean equals(Object obj):

    • 该方法默认比较两个对象的地址是否相等,与 == 运算符的结果一致

      • 源码

        public boolean equals(Object obj) {
        	return (this == obj); 
        }
        	// this 当前正在调用的对象
            // obj 	形式参数 传的实际参数
            // boolean b1 = s1.equals(s2); 
            // this = s1 obj = s2
        
      • 编程实现Student类的封装,特征:学号(id)和姓名,要求提供打印所有特征的方法

        public class Student extends Object {
            private int id; // 用于描述学号的成员变量
            private String name; // 用于描述姓名的成员变量
        
            public Student() {
            }
        
            public Student(int id, String name) {
                setId(id);
                setName(name);
            }
        
            public int getId() {
                return id;
            }
        
            public void setId(int id) {
                if (id > 0) {
                    this.id = id;
                } else {
                    System.out.println("学号不合理哦!!!");
                }
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        }
        
      • 编程实现StudentTest类,在main方法中使用有参方式构造两个Student类型的对象并打印特征

        public class StudentTest {
        
            public static void main(String[] args) {
        
                // 使用有参方式构造Student类型的两个对象并判断是否相等
                Student s1 = new Student(1001, "zhangfei");
                Student s2 = new Student(1002, "guanyu");
                //Student s2 = s1;  // 表示s2和s1都指向了同一个对象,地址相同了
                
                // 下面调用从Object类中继承下来的equals方法,该方法默认比较两个对象的地址,可以查看源码验证
                boolean b1 = s1.equals(s2);
                System.out.println("b1 = " + b1); // false true
                System.out.println("s1 == s2" + s1 == s2); // 比较地址 false true
            }
        }
        
    • 若希望比较两个对象的内容,则需要重写该方法

      public class Student extends Object {
          // 在get set方法下方重写equals方法
      	
          /**
           * 为了比较两个对象的内容(也就是学号信息)需要重写该方法
           */
          // Student this = s1;
          // Object obj = s2;
      
          @Override
          public boolean equals(Object obj) {
              // 当调用对象和参数对象指向同一个对象时,则内容一定相同
              if (this == obj) return true;
              // 当调用对象为不为空而参数对象为空时,则内容一定不相同
              if (null == obj) return false;
              // 判断obj指向的对象是否为Student类型的对象,若是则条件成立,否则条件不成立
              if (obj instanceof Student) {
                  Student ts = (Student) obj; // 强制类型转换
                  return this.getId() == ts.getId(); // 比较ID内容
              }
              // 否则类型不一致没有可比性,则内容一定不相同
              return false;
          }
      }
      
      public class StudentTest {
      
          public static void main(String[] args) {
      
              Student s1 = new Student(1001, "zhangfei");
              Student s2 = new Student(1001, "zhangfei");
      
              // 当Student类中重写equals方法后,则调用重写以后的版本,比较内容
              
              //Student s3 = null;
              //Student s3 = s1;
              //boolean b1 = s1.equals(s3);
              
              boolean b1 = s1.equals(s2);
              System.out.println("b1 = " + b1); // 比较内容 true
              System.out.println("s1 == s2" + s1 == s2); // 比较地址 false
          }
      }
      
    • 若该方法被重写后,则应该重写hashCode方法来保证结果的一致性

  • int hashCode():

    • 用于获取调用对象的哈希码值(内存地址的编号)

    • 若两个对象调用equals方法相等,则各自调用该方法的结果必须相同;若两个调用对象equals方法不相等,则各自调用该方法的结果应该不相同

      public class StudentTest {
      
          public static void main(String[] args) {
      
              Student s1 = new Student(1001, "zhangfei");
              //Student s2 = new Student(1002, "guanyu");
              Student s2 = s1;  // s2和s1都指向同一个对象,地址相同,内容也一定相同
              
              boolean b1 = s1.equals(s2);
              System.out.println("b1 = " + b1); // 比较内容 true 
              
              // 下面调用从Object类中继承下来的hashCode方法,获取调用对象的哈希码值(内存地址的编号)
              int ia = s1.hashCode();
              int ib = s2.hashCode();
              System.out.println("ia = " + ia); // ia = 123(举例)
              System.out.println("ib = " + ib); // ib = 1234
              // 上一步equals方法结果为true,hashCode方法返回值应该相同
              // ia ib结果不同,因为没重写hashCode方法
          }
      }
      
    • 为了使得该方法与equals方法保持一致,需要重写该方法

      public class Student extends Object {
          // 在equals方法下方重写hashCode方法
          
      	/**
           * 为了使得该方法的结果与equals方法的结果保持一致,从而满足Java官方的常规协定,需要重写该方法
           */
      
          @Override
          public int hashCode() {
              //return getId(); // 不再代表内存地址的编号了
              final int type = 12;
              return type*31 + getId();
              // 随便想的12和31,但结果是固定的,最终还是依赖于Id值
              // 可以和直接获取学号加以区分
          }
      }
      
      public class StudentTest {
      
          public static void main(String[] args) {
      
              Student s1 = new Student(1001, "zhangfei");
              //Student s2 = new Student(1002, "guanyu");
              Student s2 = s1;  // s2和s1都指向同一个对象,地址相同,内容也一定相同
              
              boolean b1 = s1.equals(s2);
              System.out.println("b1 = " + b1); // 比较内容 true 
              
              // 当Student类中重写hashCode方法后,则调用重写以后的版本
              
              int ia = s1.hashCode();
              int ib = s2.hashCode();
              System.out.println("ia = " + ia); // ia = 1373
              System.out.println("ib = " + ib); // ib = 1373
              // ia ib结果相同
          }
      }
      
  • String toString():

    • 用于获取调用对象的字符串形式

    • 该方法默认返回的字符串为:包名.类名@哈希码值的十六进制

    • 为了返回更有意义的数据,需要重写该方法

    • 使用print或println打印引用 或 字符串拼接引用都会自动调用该方法

      public class Student extends Object {
          // 在hashCode方法下方重写toString方法
          
          /**
           * 为了返回更有意义的字符串数据,则需要重写该方法
           */ 
          
          @Override
          public String toString() {
              return "Student[id = " + getId() + ", name = " + getName() + "]";
          }
      }
      
      package com.lagou.task11;
      
      public class StudentTest {
      
          public static void main(String[] args) {
              // 下面调用从Object类中继承下来的toString方法,获取调用对象的字符串形式:包名.类名@哈希码值的十六进制
              String str1 = s1.toString();
              System.out.println("str1 = " + str1); // com.lagou.task11.Student@55d
              
              // 当Student类中重写toString方法后,则调用重写以后的版本:Student[id = 1001, name = zhangfei]
              
              // 当打印一个引用变量时会自动调用toString方法
              System.out.println(s1); // Student[id = 1001, name = zhangfei]
              String str2 = "hello" + s1;
              System.out.println("str2 = " + str2);// str2 = helloStudent[id = 1001, name = zhangfei]
          }
      }
      
  • Classs<?> getClass() :

    • 用于返回调用对象执行时的Class实例,反射机制使用
题目扩展

如何实现以姓名作为基准判断两个对象是否相等?以及以学号和姓名同时作为基准判断两个对象是否相等?

基础知识:

  • int是基本数据类型,内存空间中放的就是数据本身,使用 == 可以判断数据是否相同
  • String是引用数据类型,内存空间中放的是地址,使用 == 判断地址是否相同
  • 查询 java.lang包,发现String类型已经重写equals和hashCode方法

手写版:

public class Student extends Object {  

    @Override
    public boolean equals(Object obj) {
        
        if (this == obj) return true;
        if (null == obj) return false;
        if (obj instanceof Student) {
            Student ts = (Student) obj;
            // 以学号作为基准判断两个对象是否相等  int是基本数据类型,内存空间中放的就是数据本身,使用 == 可以判断数据是否相同
            //return this.getId() == ts.getId();
            // 以姓名作为基准判断两个对象是否相等  String是引用数据类型,内存空间中放的是地址,使用 == 判断地址是否相同
            // 也就是判断两个对象中姓名字符串的地址是否相同,不够完美
            //return this.getName() == ts.getName();
            
            return this.getName().equals(ts.getName()); // 比较姓名字符串的内容是否相同
        }
        return false;
    }

    @Override
    public int hashCode() {
        final int type = 12;
        //return type*31 + getName(); // getName()是String类型,拼接后结果为String类型,而函数返回值要求int类型
        return type*31 + getName().hashCode();
    }
}

生成版:

IntelliJ Deafault:

	@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (id != student.id) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }

Template:java.util.Objects.equals and hashCode(java 7+):

import java.util.Objects;

public class Student extends Object {
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id == student.id &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

个人理解:

假设在抽屉A里放了一个苹果,两张纸条上都写着“抽屉X”字样(X表示未知)。抽屉A相当于内存地址,苹果相当于所存数据,两张纸条其中一条拿在手上,相当于调用对象,另一条放在桌子上,相当于参数对象。

if (this == o) return true;:两张纸条上都写着“抽屉A”字样,同一个抽屉,同一个苹果

if (o == null || getClass() != o.getClass()) return false;:放在桌子上的纸条没写字 / 拿在手上的纸条写着“抽屉A”,放在桌子上的纸条写着“书包A”(类型不同,没有可比性)

Student student = (Student) o;:强制向下转型(小转大可自动,大转小需手动)

return id == student.id && Objects.equals(name, student.name);:id匹配成功才会继续匹配名字

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值