Java Object类方法解析

Java Object类方法解析

在Java中Object是全部类的父类,任何类都默认继承Object,其提供的方法主要有如下几种:java

  • registerNatives()算法

  • hashCode和equale函数用来判断对象是否相同,数组

  • wait(),wait(long),wait(long,int),notify(),notifyAll()函数

  • toString()和getClass性能

  • clone()this

  • finalize()用于在垃圾回收编码

下面介绍下各个方法:操作系统

registerNatives()

registerNatives函数前面有native关键字修饰,Java中,用native关键字修饰的函数代表该方法的实现并非在Java中去完成,而是由C/C++ 去完成,并被编译成了.dll,由Java去调用。方法的具体实现体在dll文件中,对于不一样平台,其具体实现应该有所不一样。用native修饰,即表示操做系统,须要提供此方法,Java自己须要使用。具体到registerNatives()方法自己,其主要做用是将C/C++中的方法映射到Java中的native方法,实现方法命名的解耦。
在Java源码中,此方法在静态代码块中被调用:线程

private static native void registerNatives ();
  static {
     registerNatives();
 }

equales

equales常常跟“= =”作比较,二者区别是:
“= =”表示的是变量值彻底相同(对于基础类型,地址中存储的是值,引用类型则存储指向实际对象的地址,因此基本数据类型:“= =”比较的是他们的值。引用类型(类、接口、数组) :用 “= =” 进行比较的时候,比较的是他们在内存中的存放地址,除非是同一个new出来的对象,他们的比较后的结果为true,不然比较后结果为false。)
咱们知道对象在JVM中是存放放在Java堆中的,Java虚拟机栈中存放的是对象的引用(地址)。因而可知 “= =” 是对Java虚拟机栈中的值进行比较的。若是要比较Java堆中对象的内容是否相同,那么就须要使用equals方法了。
equals表示的是对象的内容彻底相同,此处的内容多指对象的特征/属性。 Object类中关于equals()方法的定义以下:翻译

public boolean equals(Object var1) {
        return this == var1;
    }

Object原生的equals()方法内部调用的正是= =,与= =具备相同的含义。既然如此,为何还要定义此equals()方法?
equlas()方法的正确理解应该是:判断两个对象是否相等。那么判断对象相等的标尺又是什么?
如上,在object类中,此标尺即为==。固然,这个标尺不是固定的,其余类中能够按照实际的须要对此标尺含义进行重定义。如String类中则是依据字符串内容是否相等来重定义了此标尺含义。如此能够增长类的功能性和实际编码的灵活性。固然了,若是自定义的类没有重写equals()方法来从新定义此标尺,那么默认的将是其父类的equals(),直到object基类。
String 类的equals方法:

public boolean equals(Object var1) {
        if (this == var1) {
            return true;
        } else {
            if (var1 instanceof String) {
                String var2 = (String)var1;
                int var3 = this.value.length;
                if (var3 == var2.value.length) {
                    char[] var4 = this.value;
                    char[] var5 = var2.value;

                    for(int var6 = 0; var3-- != 0; ++var6) {
                        if (var4[var6] != var5[var6]) {
                            return false;
                        }
                    }

                    return true;
                }
            }

            return false;
        }
    }

String中equals方法判断相等的步骤是:
1).若A==B 便是同一个String对象 返回true
2).若对比对象是String类型则继续,不然返回false
3).判断A、B长度是否同样,不同的话返回false
4).逐个字符比较,如有不相等字符,返回false
注:Java中约定重写equals()方法必须重写hasCode()方法。

最后总结下:

==比较的是“值”(引用数据类型是比较其内存地址值,基本数据类型是比较变量值)

equals比较的是对象的内容,对内容比较的标尺能够由子类本身定义。

hashCode

hashCode()方法返回一个整形数值,表示该对象的哈希码值。
hashCode()具备以下约定:
1).在Java应用程序程序执行期间,对于同一对象屡次调用hashCode()方法时,其返回的哈希码是相同的,前提是将对象进行equals比较时所用的标尺信息未作修改。在Java应用程序的一次执行到另一次执行,同一对象的hashCode()返回的哈希码无须保持一致;
2).若是两个对象相等(依据:调用equals()方法),那么这两个对象调用hashCode()返回的哈希码也必须相等;
3).反之,两个对象调用hasCode()返回的哈希码相等,这两个对象不必定相等。
即严格的数学逻辑表示为: 两个对象相等 <=> equals()相等 => hashCode()相等。所以,重写equlas()方法必须重写hashCode()方法,以保证此逻辑严格成立,同时能够推理出:hasCode()不相等 => equals()不相等 <=> 两个对象不相等。
可能有人在此产生疑问:既然比较两个对象是否相等的惟一条件(也是充要条件)是equals,那么为何还要弄出一个hashCode(),而且进行如此约定,弄得这么麻烦?
其实,这主要体如今hashCode()方法的做用上,其主要用于加强哈希表的性能。
以集合类中的Set为例,当新加一个对象时,须要判断现有集合中是否已经存在与此对象相等的对象,若是没有hashCode()方法,须要将Set进行一次遍历,并逐一用equals()方法判断两个对象是否相等,此种算法时间复杂度为o(n)。经过借助于hasCode方法,先计算出即将新加入对象的哈希码,而后根据哈希算法计算出此对象的位置,直接判断此位置上是否已有对象便可。(注:Set的底层用的是Map的原理实现)
在此须要纠正一个理解上的误区:对象的hashCode()返回的不必定是对象所在的物理内存地址。甚至也不必定是对象的逻辑地址,hashCode()相同的两个对象,不必定相等,换言之,不相等的两个对象,hashCode()返回的哈希码可能相同。
小结:
1).若是两个对象equals,Java运行时环境会认为他们的hashcode必定相等。
2).若是两个对象不equals,他们的hashcode有可能相等。
3).若是两个对象hashcode相等,他们不必定equals。
4).若是两个对象hashcode不相等,他们必定不equals。
为了比较两个对象时更高效,判断两个对象是否相等能够采用如下规则:
第一步,若是hashCode()相等,则查看第二步,不然不相等;
第二步,查看equals()是否相等,若是相等,则两obj相等,不然仍是不相等。

wait(),wait(long),wait(long,int),notify(),notifyAll()

一说到wait(…) / notify() /notifyAll()这几个方法,首先想到的是线程。确实,这几个方法主要用于java线程之间的通讯协做。先具体看下这几个方法的主要含义:
一、wait(…)方法调用后当前线程将当即阻塞,且释放其所持有的同步代码块中的锁,直到被唤醒或超时或打断后且从新获取到锁后才能继续执行;
二、notify()/notifyAll()方法调用后,其所在线程不会当即释放所持有的锁,直到其所在同步代码块中的代码执行完毕,此时释放锁,所以,若是其同步代码块后还有代码,其执行则依赖于JVM的线程调度。

注:wait(…) / notify() / notifyAll()通常状况下都是配套使用。且wait(…)/notify()|notifyAll()方法只能在同步代码块中才能使用。

为何Object这个基类会提供这类方法?由于定义在Object中就能够实现将任何对象视为线程同步中的监听器。

对于wait和notify方法咱们在Java线程部分还会再次分析。

toString()

toString()方法返回该对象的字符串表示。先看一下Object中的具体方法体:

public String toString() {
        return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
    }

toString()方法相信你们都常常用到,即便没有显式调用,但当咱们使用System.out.println(obj)时,其内部也是经过toString()来实现的。

Object类的toString()方法返回的是对象的类型和其哈希码,子类能够重写该方法以打印本身想要打印的内容。

getClass

getClass()是一个native方法,返回的是此Object对象的类对象/运行时类对象Class<?>。
首先解释下”类对象”的概念:在Java中,类是是对具备一组相同特征或行为的实例的抽象描述,对象则是此类所描述的特征或行为的具体实例。做为概念层次的类,其自己也具备某些共同的特性,如都具备类名称、由类加载器去加载,都具备包,具备父类,属性和方法等。因而,Java中有专门定义了一个类,Class类,去描述其余类所具备的这些特性,今后角度去看,类自己是属于Class类的对象,咱们称之为”类对象”。

clone()

clone()方法一样是native方法,所以,咱们知道了clone()方法并非Java的原生方法,具体的实现是有C/C++完成的。clone英文翻译为”克隆”,其目的是建立并返回此对象的一个副本。Java术语表述为:clone函数返回的是一个引用,该引用指向的是新的clone出来的对象,此对象与原对象分别占用不一样的堆空间。
同时Java中的语法规定:
clone()的正确调用是须要实现Cloneable接口,若是没有实现Cloneable接口,而且子类直接调用Object类的clone()方法,会抛出CloneNotSupportedException异常。
Cloneable接口仅是一个表示接口,接口自己不包含任何方法,用来指示Object.clone()能够合法的被子类引用所调用。

finalize()

finalize方法主要与Java垃圾回收机制有关。首先咱们看一下finalized方法在Object中的具体定义:

protected void finalize() throws Throwable {
    }

咱们发现Object类中finalize方法被定义成一个空方法,为何要如此定义呢?finalize方法的调用时机是怎么样的呢? 首先,Object中定义finalize方法代表Java中每个对象都将具备finalize这种行为,其具体调用时机在:JVM准备对此对象所占用的内存空间进行垃圾回收前,将会调用其finalize。由此能够看出,此方法并非由咱们主动去调用的。

相关文章
相关标签/搜索