浅谈Java Object
在Java
中,所有的类都继承自Object
类,因此万物皆对象
?也没错!
那有人会问,我的子类继承的是父类不是Object
,怎么说?
如果一个类没用显示的继承某一个类,那么他就会隐式的继承 Object
。
接下来说重点:我在进这家公司面试的时候问道,“Object
类包含了哪些方法?”,犹记得当时一脸懵逼的样子,倒不是说这道题多难,而是那时候弟弟刚大四,虽然是老师直接推荐过去的,但紧张呀。而且还有一些扩展问题,今天就统一总结一下。
-
protected Object clone() throws CloneNotSupportedException
创建并返回对象的副本(拷贝)《阿里巴巴Java开发手册》建议:慎用
Object
的clone()
方法来拷贝对象,因为Object
的clone()
方法默认是浅拷贝,即拷贝对象在内存中的地址的引用。如果需要深拷贝,需要重写clone()
方法。即:
x.clone() != x; x.clone().getClass() == x.getcalss(); x.clone.equals(x); // true
如果对象的类不支持
Cloneable
接口,重写clone()
方法则会报此异常。Object
类本身并不实现接口Cloneable
,因此在类别为Object
的对象上调用clone()
方法将导致运行时抛出异常. -
public String toString()
返回此对象的字符串表示形式。
《阿里巴巴 Java 开发手册》强制规定:POJO
类必须重写toString
方法;比如:public class QueryParamInfo { private Long startTime; private Long endTime; private String operator; private Integer currentPage; private Integer size; @Override public String toString() { return "QueryParamInfo{" + "startTime=" + startTime + ", endTime=" + endTime + ", operator='" + operator + '\'' + ", currentPage=" + currentPage + ", size=" + size + '}'; } }
这些代码都是插件或者编辑器可以快捷生成的,不用害怕,要养成习惯。那好处是什么呢?很简单,方便在抛出异常时调用
POJO
的toString()
打印其属性值,便于排查问题。POJO(Plain Ordinary Java Object)指简单的 Java 对象,也就是普通的 JavaBeans,包含一些成员变量及其 getter / setter ,没有业务逻辑。有时叫做 VO (value - object),有时叫做 DAO (Data Transform Object)。
-
public final Class<?> getClass()
返回Object
运行时类。
在运行时可以获取对象对应类的信息,详见反射
.A a = new A(); Class b = a.getClass(); System.out.pringtln(b.getName()); // 输出A
-
public int hashCode()
返回对象的哈希值。
hashCode()
是一个native
方法,返回值是整形。该方法将对象在内存中的地址作为哈希码返回,可以保证不同对象的返回值不同。
hashCode
通常在哈希表中起作用,比如hashMap
.native
方法顾名思义就是本地方法,不同平台上的方法不同,有JVM调用实现。比如Thread
中的start()
方法其实就是调用native
的start0()
.自己可以在IDE上点进代码看一下。 -
protected void finalize() throws Throwable
当垃圾回收机制确定该对象不再被调用时,垃圾回收器会调用此方法.
此方法在JDK9
中标注deprecated
,所以不多说。 -
public boolean equals(Object obj)
判断两个对象是否相等==
: 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==
比较的是值,引用数据类型==
比较的是内存地址)。equals()
也是判断两个对象是否相等,它有两种使用情况:- 类没有覆盖
equals()
方法。则通过equals()
比较该类的两个对象时,等价于通过“==”比较这两个对象。 - 类覆盖了
equals()
方法。一般,我们都覆盖equals()
方法来比较两个对象的内容是否相等;若它们的内容相等,则返回true
(即,认为这两个对象相等)。
- 类没有覆盖
举例:
public class test1 { public static void main(String[] args) { String a = new String("ab"); // a 为一个引用 String b = new String("ab"); // b为另一个引用,对象的内容一样 String aa = "ab"; // 放在常量池中 String bb = "ab"; // 从常量池中查找 if (aa == bb) // true System.out.println("aa==bb"); if (a == b) // false,非同一对象 System.out.println("a==b"); if (a.equals(b)) // true System.out.println("aEQb"); if (42 == 42.0) { // true System.out.println("true"); } } }
String
中的equals
方法是被重写过的,因为object
的equals
方法是比较的对象的内存地址,而String
的equals
方法比较的是对象的值。- 当创建
String
类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String
对象。
《阿里巴巴 Java 开发手册》上强调:由于
Object
的equals
方法容易抛出空指针异常,所以应该使用常量或者确定不为null
的对象来调用equals
。String a = null; "test".equals(a); //false a.equals("test"); // 抛出异常 // 推荐用法 Objects.equals(a,"test"); //false // 具体原因和使用看java.util.Objects#equals的源码
-
wait()
、notify()
、notifyAll()
这三个放在一起说是因为,大家都熟悉而且使用场景一致。就是在多线程加同步锁时等待、通知唤醒方法。没错他们不是Thread
中的方法是Object
的。
总结:
虽然终极父类是Object
,但那8个基本类型不在其列。
本篇文章主要就是让大家对Object
的印象更加深刻一点,并拓展了一些知识和自己的理解。如有不当之处,望批评指正。对大家有帮助的话点个赞,Wink~~