Object 类的使用

1. 如何理解根父类

java.lang.Object是类层次结构的根类,即所有其它类的父类。每个类都使用 Object 作为超类。

image-20220503104750655

  • Object类型的变量与除Object以外的任意引用数据类型的对象都存在多态引用
    
    method(Object obj){…} //可以接收任何类作为其参数  
    ​  
    Person o = new Person();    
    method(o);  
  • 所有对象(包括数组)都实现这个类的方法。

  • 如果一个类没有特别指定父类,那么默认则继承自Object类。例如:

    public class Person {  
          ...  
      }  
      //等价于:  
      public class Person extends Object {  
          ...  
      }
    
### 2. Object类的方法

根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。这里我们主要关注其中的6个:

#### 1、(重点)equals()

- 基本类型比较值:只要两个变量的值相等,即为true。
```java
    
    int a=5;   
    if(a==6){…}
    
  • 引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,==才返回true。
    Person p1=new Person();           
    Person p2=new Person();  
    if (p1==p2){…}
    
- 用“==”进行比较时,符号两边的`数据类型必须兼容`(可自动转换的基本数据类型除外),否则编译出错

**equals():**所有类都继承了Object,也就获得了equals()方法。还可以重写。

  • 只能比较引用类型,Object类源码中equals()的作用与“==”相同:比较是否指向同一个对象。

    image-20220503104750655

  • 格式:obj1.equals(obj2)

  • 特例:当用equals()方法进行比较时,对类File、String、Date及包装类(Wrapper Class)来说,是比较类型及内容而不考虑引用的是否是同一个对象;

    • 原因:在这些类中重写了Object类的equals()方法。
  • 当自定义使用equals()时,可以重写。用于比较两个对象的“内容”是否都相等

  • 重写equals()方法的原则

    • 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

    • 自反性:x.equals(x)必须返回是“true”。

    • 传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。

    • 一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

    • 任何情况下,x.equals(null),永远返回是“false”;

      x.equals(和x不同类型的对象)永远返回是“false”。

  • 重写举例:

class User{  
    private String host;  
    private String username;  
    private String password;  
    public User(String host, String username, String password) {  
        super();  
        this.host = host;  
        this.username = username;  
        this.password = password;  
    }  
		......
    @Override  
    public String toString() {  
        return "User [host=" + host + ", username=" + username + ", password=" + password + "]";  
    }  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        User other = (User) obj;  
        if (host == null) {  
            if (other.host != null)  
                return false;  
        } else if (!host.equals(other.host))  
            return false;  
        if (password == null) {  
            if (other.password != null)  
                return false;  
        } else if (!password.equals(other.password))  
            return false;  
        if (username == null) {  
            if (other.username != null)  
                return false;  
        } else if (!username.equals(other.username))  
            return false;  
        return true;  
    }  
      
}

面试题:==和equals的区别

从我面试的反馈,85%的求职者“理直气壮”的回答错误…

  • == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型就是比较内存地址

  • equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。

  • 具体要看自定义类里有没有重写Object的equals方法来判断。

  • 通常情况下,重写equals方法,会比较类中的相应属性是否都相等。

2、(重点)toString()

方法签名:public String toString()

① 默认情况下,toString()返回的是“对象的运行时类型 @ 对象的hashCode值的十六进制形式"

② 在进行String与其它类型数据的连接操作时,自动调用toString()方法

Date now=new Date();  
System.out.println(“now=”+now);  //相当于  
System.out.println(“now=”+now.toString()); 

③ 如果我们直接System.out.println(对象),默认会自动调用这个对象的toString()

因为Java的引用数据类型的变量中存储的实际上时对象的内存地址,但是Java对程序员隐藏内存地址信息,所以不能直接将内存地址显示出来,所以当你打印对象时,JVM帮你调用了对象的toString()。

④ 可以根据需要在用户自定义类型中重写toString()方法 如String 类重写了toString()方法,返回字符串的值。

s1="hello";  
System.out.println(s1);//相当于System.out.println(s1.toString());

例如自定义的Person类:

public class Person {    
    private String name;  
    private int age;  
​  
    @Override  
    public String toString() {  
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';  
    }  
}

3、clone()

//Object类的clone()的使用  
public class CloneTest {  
    public static void main(String[] args) {  
        Animal a1 = new Animal("花花");  
        try {  
            Animal a2 = (Animal) a1.clone();  
            System.out.println("原始对象:" + a1);  
            a2.setName("毛毛");  
            System.out.println("clone之后的对象:" + a2);  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
    }  
}  
​  
class Animal implements Cloneable{  
    private String name;  
​  
    public Animal() {  
        super();  
    }  
​  
    public Animal(String name) {  
        super();  
        this.name = name;  
    }  
​  
    public String getName() {  
        return name;  
    }  
​  
    public void setName(String name) {  
        this.name = name;  
    }  
​  
    @Override  
    public String toString() {  
        return "Animal [name=" + name + "]";  
    }  
      
    @Override  
    protected Object clone() throws CloneNotSupportedException {  
        // TODO Auto-generated method stub  
        return super.clone();  
    }  
      
}

4、finalize()

  • 当对象被回收时,系统自动调用该对象的 finalize() 方法。(不是垃圾回收器调用的,是本类对象调用的)

    • 永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。
  • 什么时候被回收:当某个对象没有任何引用时,JVM就认为这个对象是垃圾对象,就会在之后不确定的时间使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize()方法。

  • 子类可以重写该方法,目的是在对象被清理之前执行必要的清理操作。比如,在方法内断开相关连接资源。

    • 如果重写该方法,让一个新的引用变量重新引用该对象,则会重新激活对象。
  • 在JDK 9中此方法已经被标记为过时的。

public class FinalizeTest {  
    public static void main(String[] args) {  
        Person p = new Person("Peter", 12);  
        System.out.println(p);  
        p = null;//此时对象实体就是垃圾对象,等待被回收。但时间不确定。  
        System.gc();//强制性释放空间  
    }  
}  
​  
class Person{  
    private String name;  
    private int age;  
​  
    public Person(String name, int age) {  
        super();  
        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  
    protected void finalize() throws Throwable {  
        System.out.println("对象被释放--->" + this);  
    }  
    @Override  
    public String toString() {  
        return "Person [name=" + name + ", age=" + age + "]";  
    }  
      
}

5、getClass()

public final Class<?> getClass():获取对象的运行时类型

因为Java有多态现象,所以一个引用数据类型的变量的编译时类型与运行时类型可能不一致,因此如果需要查看这个变量实际指向的对象的类型,需要用getClass()方法

public static void main(String[] args) {  
    Object obj = new Person();  
    System.out.println(obj.getClass());//运行时类型  
}

结果:

class com.atguigu.java.Person

6、hashCode()

public int hashCode():返回每个对象的hash值。(后续在集合框架章节重点讲解)

public static void main(String[] args) {  
    System.out.println("AA".hashCode());//2080  
    System.out.println("BB".hashCode());//2112  
}

2. native关键字的理解

使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++等非Java语言实现的,并且被编译成了DLL,由Java去调用。

  • 本地方法是有方法体的,用c语言编写。由于本地方法的方法体源码没有对我们开源,所以我们看不到方法体

  • 在Java中定义一个native方法时,并不提供实现体。

1. 为什么要用native方法

Java使用起来非常方便,然而有些层次的任务用java实现起来不容易,或者我们对程序的效率很在意时,例如:Java需要与一些底层操作系统或某些硬件交换信息时的情况。native方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解Java应用之外的繁琐的细节。

2. native声明的方法,对于调用者,可以当做和其他Java方法一样使用

native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的所有细节。

Java基础

子类对象实例化全过程

2025-8-8 20:09:40

Java基础

抽象类与抽象方法

2025-8-9 10:09:57

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索