栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java中的Object类

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java中的Object类

这里写目录标题
  • 1.Object是什么?
  • 2.Object的属性和方法
    • 方法1:getClass
    • 方法2:hashCode
    • 方法3:equals
    • 面试题:equals和==的区别
    • 面试题:重写 equals 时为什么一定要重写 hashCode?
    • 方法4: clone
    • 面试题:浅拷贝和深拷贝
    • 方法5:toString
    • 方法6:notify
    • 方法7:notifyAll
    • 方法8:wait(long timeout)
    • 拓展问题:什么是虚假唤醒?
    • 方法9:wait(long timeout, int nanos)
    • 方法10:wait
    • 方法11:finalize
  • 源码

1.Object是什么?

*Class {@code Object} is the root of the class hierarchy. Every class has{@code Object} as a superclass. All objects,including arrays, implement the methods of this class.

类Object是类层次结构的根。每个类都有Object作为超类。所有对象,包括数组,都实现了这个类的方法

2.Object的属性和方法 方法1:getClass

public final native Class getClass();

返回此Object的运行时类。返回的Class对象是被表示类的static synchronized方法锁定的对象。实际结果类型是Class其中|X|是调用getClass的表达式的静态类型的擦除。例如,此代码片段中不需要强制转换

方法2:hashCode

public native int hashCode();

返回对象的哈希码值。
支持此方法是为了有利于哈希表,例如java.util.HashMap提供的哈希表。
hashCode的一般合约是:
每当在 Java 应用程序执行期间对同一个对象多次调用它时, hashCode方法必须始终返回相同的整数,前提是没有修改对象上的equals比较中使用的信息。该整数不需要从应用程序的一次执行到同一应用程序的另一次执行保持一致。
如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须产生相同的整数结果。
如果根据equals(Object)方法,如果两个对象不相等,则不需要对两个对象中的每一个调用hashCode方法都必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
在合理可行的情况下,由Object类定义的 hashCode 方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但 Java™ 编程语言不需要这种实现技术。)

方法3:equals

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

指示其他对象是否“等于”这个对象。
equals方法在非空对象引用上实现等价关系:
它是自反的:对于任何非空引用值x , x.equals(x)应该返回true 。
它是对称的:对于任何非空引用值x和y ,当且仅当y.equals(x)返回true时, x.equals(y)才应该返回true 。
它是可传递的:对于任何非空引用值x 、 y和z ,如果x.equals(y)返回true并且y.equals(z)返回true ,则x.equals(z)应该返回true 。
它是一致的:对于任何非空引用值x和y , x.equals(y)的多次调用始终返回true或始终返回false ,前提是没有修改对象上的equals比较中使用的信息。
对于任何非空引用值x , x.equals(null)应该返回false 。
Object类的equals方法实现了对象上最有区别的可能等价关系;也就是说,对于任何非空引用值x和y ,当且仅当x和y引用同一个对象( x == y的值为true )时,此方法才返回true 。
请注意,每当重写该方法时,通常都需要重写hashCode方法,以维护hashCode方法的一般约定,即相等的对象必须具有相等的哈希码

面试题:equals和==的区别

==的判断
基本数据类型(byte,short,char,int,long,float,double,boolean)比较他们之间的值是否相等。
引用数据类型,比较的是他们在堆内存地址是否相等。每新new一个引用类型的对象,会重新分配堆内存空间,使用==比较返回false。

equals的判断
equals方法是Object类的一个方法,Java当中所有的类都是继承于Object这个超类。
JDK1.8 Object类equals方法源码如下,即返回结果取决于两个对象的使用==判断结果。

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

具体的情况判断还要看使用对象是否重写了equals方法,常用的String重写的方法,比较的是对应的字符串的值。

面试题:重写 equals 时为什么一定要重写 hashCode?

答:要查询某个值是否在集合中?如果不通过 hash 方式直接定位元素(的存储位置),那么就只能按照集合的前后顺序,一个一个的询问比对了。
当我们对比两个对象是否相等时,我们就可以先使用 hashCode 进行比较,如果比较的结果是 true,那么就可以使用 equals 再次确认两个对象是否相等,如果比较的结果是 true,那么这两个对象就是相等的,否则其他情况就认为两个对象不相等。这样就大大的提升了对象比较的效率,这也是为什么 Java 设计使用 hashCode 和 equals 协同的方式,来确认两个对象是否相等的原因。​

方法4: clone

protected native Object clone() throws CloneNotSupportedException;

创建并返回此对象的副本。
“复制”的确切含义可能取决于对象的类别。一般意图是,对于任何对象x ,表达式: x.clone() != x
将是真实的,并且表达式: x.clone().getClass() == x.getClass()会是true ,但这些都不是绝对的要求。虽然通常是这样的: x.clone().equals(x)会是true ,这不是绝对的要求。
按照惯例,应该通过调用super.clone来获取返回的对象。如果一个类和它的所有超类(除了Object )都遵守这个约定,那么x.clone().getClass() == x.getClass()就是这种情况。
按照惯例,此方法返回的对象应独立于此对象(正在克隆)。为了实现这种独立性,可能需要在返回super.clone之前修改对象的一个​​或多个字段。通常,这意味着复制任何包含被克隆对象的内部“深层结构”的可变对象,并将对这些对象的引用替换为对副本的引用。如果一个类只包含原始字段或对不可变对象的引用,那么通常情况下super.clone返回的对象中不需要修改任何字段。
类Object的方法clone执行特定的克隆操作。首先,如果该对象的类没有实现接口Cloneable ,则抛出CloneNotSupportedException 。请注意,所有数组都被认为实现了接口Cloneable ,并且数组类型T[]的clone方法的返回类型是T[] ,其中 T 是任何引用或原始类型。否则,此方法会创建此对象的类的新实例,并使用此对象的相应字段的内容来初始化其所有字段,就像通过赋值一样;字段的内容本身不会被克隆。因此,此方法执行此对象的“浅拷贝”,而不是“深拷贝”操作。
类Object本身并不实现接口Cloneable ,因此在类为Object的对象上调用clone方法将导致在运行时引发异常。

面试题:浅拷贝和深拷贝

答:浅拷贝是对象的按位拷贝。该对象具有原始对象中值的精确副本。如果对象的任何字段是对其他对象的引用,则仅复制引用地址,即仅复制内存地址。
深拷贝副本 所有字段,并复制这些字段指向的动态分配的内存。当一个对象与其引用的对象一起被复制时,就会发生深度复制。

方法5:toString

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

返回对象的字符串表示形式。
通常, toString方法返回一个“以文本方式表示”该对象的字符串。结果应该是一个简洁但信息丰富的表示,易于人们阅读。建议所有子类重写此方法。
类Object的toString方法返回一个字符串,该字符串由对象作为其实例的类的名称、at 符号字符“ @ ”和对象哈希码的无符号十六进制表示形式组成。换句话说,此方法返回一个等于以下值的字符串:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())

方法6:notify

public final native void notify();

唤醒正在此对象的监视器上等待的单个线程。

如果有任何线程正在等待该对象,则选择其中一个被唤醒。该选择是任意的,并由实施自行决定。线程通过调用其中一个wait方法在对象的监视器上等待。在当前线程放弃对该对象的锁定之前,被唤醒的线程将无法继续。被唤醒的线程将以通常的方式与可能正在积极竞争以在此对象上同步的任何其他线程竞争;例如,被唤醒的线程在成为下一个锁定该对象的线程时不享有可靠的特权或劣势。

此方法只能由作为该对象监视器所有者的线程调用。线程通过以下三种方式之一成为对象监视器的所有者:
1.通过执行该对象的同步实例方法。
2.通过执行在对象上同步的synchronized语句的主体。
3.对于Class,通过执行该类的同步静态方法。
一次只有一个线程可以拥有一个对象的监视器。

方法7:notifyAll

public final native void notifyAll();

唤醒正在此对象的监视器上等待的所有线程。
线程通过调用其中一个wait方法在对象的监视器上等待。
在当前线程放弃对该对象的锁定之前,被唤醒的线程将无法继续。被唤醒的线程将以通常的方式与可能正在积极竞争以在该对象上同步的任何其他线程竞争;例如,被唤醒的线程在成为下一个锁定该对象的线程时不享有可靠的特权或劣势。
此方法只能由作为该对象监视器所有者的线程调用。

方法8:wait(long timeout)

public final native void wait(long timeout) throws InterruptedException;

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法,或者经过了指定的时间量。
当前线程必须拥有该对象的监视器。
此方法使当前线程(称为T )将自己置于该对象的等待集中,然后放弃对该对象的任何和所有同步声明。线程T出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一:
其他一些线程为此对象调用notify方法,而线程T恰好被任意选择为要被唤醒的线程。
其他一些线程为此对象调用notifyAll方法。
其他一些线程中断线程T 。
或多或少已经过了指定的实时时间。但是,如果timeout为零,则不考虑实时时间,线程只是等待直到收到通知。
然后将线程T从该对象的等待集中移除,并重新启用线程调度。然后它以通常的方式与其他线程竞争对象同步的权利;一旦它获得了对象的控制权,它对对象的所有同步声明都会恢复到之前的状态——即,恢复到调用wait方法时的状态。线程T然后从调用wait方法返回。因此,从wait方法返回时,对象和线程T的同步状态与调用wait方法时完全相同。
线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,如果条件不满足则继续等待。换句话说,等待应该总是在循环中发生,就像这样:
synchronized (obj) {
while ()
obj.wait(timeout);
… // Perform action appropriate to condition
}

如果当前线程在等待之前或期间被任何线程中断,则抛出InterruptedException 。在此对象的锁定状态已按上述恢复之前,不会引发此异常。
请注意, wait方法将当前线程放入该对象的等待集中,仅解锁该对象;当前线程可能同步的任何其他对象在线程等待时保持锁定。
此方法只能由作为该对象监视器所有者的线程调用。

拓展问题:什么是虚假唤醒?

wait方法的作用是将线程停止执行并送入到阻塞队列中,但是wait方法还有一个操作就是释放锁。因此当生产者A执行wait方法时,该线程就会把它持有的对象锁释放,这样生产者B就可以拿到锁进入synchronized修饰的方法中,即使它被卡在if判断,但被唤醒后它就会又添加一个产品了,因此需要将if判断修改为while循环判断。

方法9:wait(long timeout, int nanos)
public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
        if (nanos > 0) {
            timeout++;
        }
        wait(timeout);
    }

导致当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法,或者某个其他线程中断当前线程,或者已经过了一定的实时时间。
此方法类似于一个参数的wait方法,但它允许更好地控制在放弃之前等待通知的时间量。以纳秒为单位测量的实时量由下式给出:
1000000*timeout+nanos
在所有其他方面,此方法与一个参数的方法wait(long)执行相同的操作。特别是, wait(0, 0)与wait(0) ) 的含义相同。
当前线程必须拥有该对象的监视器。线程释放此监视器的所有权并等待,直到发生以下两种情况之一:
1.另一个线程通过调用notify方法或notifyAll方法通知在该对象的监视器上等待唤醒的线程。
2.由timeout毫秒加上nanos纳秒参数指定的超时期限已经过去。
然后线程等待直到它可以重新获得监视器的所有权并恢复执行。
与单参数版本一样,中断和虚假唤醒是可能的,并且应该始终在循环中使用此方法:
synchronized (obj) {
while ()
obj.wait(timeout, nanos);
… // Perform action appropriate to condition
}

此方法只能由作为该对象监视器所有者的线程调用。

方法10:wait
 public final void wait() throws InterruptedException {
        wait(0);
 }

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。
换句话说,这个方法的行为就像它只是执行调用wait(0)一样。
当前线程必须拥有该对象的监视器。线程释放此监视器的所有权并等待,直到另一个线程通过调用notify方法或notifyAll方法通知在此对象的监视器上等待的线程唤醒。然后线程等待直到它可以重新获得监视器的所有权并恢复执行。
与单参数版本一样,中断和虚假唤醒是可能的,并且应该始终在循环中使用此方法:
synchronized (obj) {
while ()
obj.wait();
… // Perform action appropriate to condition
}

此方法只能由作为该对象监视器所有者的线程调用。

方法11:finalize

protected void finalize() throws Throwable { }

当垃圾收集确定不再有对该对象的引用时,由对象上的垃圾收集器调用。子类覆盖finalize方法以释放系统资源或执行其他清理。

finalize的一般约定是,当 Java™ 虚拟机确定不再有任何方法可以让任何尚未终止的线程访问此对象时调用它,除非是由于某个操作由准备完成的其他对象或类的完成所采取。 finalize方法可以采取任何行动,包括使该对象再次可供其他线程使用;然而, finalize的通常目的是在对象被不可撤销地丢弃之前执行清理操作。例如,代表输入/输出连接的对象的 finalize 方法可能会执行显式 I/O 事务以在对象被永久丢弃之前中断连接。
Object类的finalize方法不执行任何特殊操作;它只是正常返回。 Object的子类可以覆盖这个定义。
Java 编程语言不保证哪个线程将为任何给定对象调用finalize方法。但是,可以保证调用 finalize 的线程在调用 finalize 时不会持有任何用户可见的同步锁。如果 finalize 方法抛出未捕获的异常,则忽略该异常并终止该对象的终结。
在为一个对象调用finalize方法之后,不会采取进一步的行动,直到 Java 虚拟机再次确定没有任何方法可以让任何尚未终止的线程访问该对象,包括可能的行动由其他准备完成的对象或类,此时该对象可能被丢弃。
对于任何给定的对象,Java 虚拟机永远不会多次调用finalize方法。
finalize方法抛出的任何异常都会导致该对象的终结被暂停,否则会被忽略。

源码

package java.lang;


public class Object {

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

    
    public final native Class getClass();

    
    public native int hashCode();

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

    
    protected native Object clone() throws CloneNotSupportedException;

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

    
    public final native void notify();

    
    public final native void notifyAll();

    
    public final native void wait(long timeout) throws InterruptedException;

    
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos > 0) {
            timeout++;
        }

        wait(timeout);
    }

    
    public final void wait() throws InterruptedException {
        wait(0);
    }

    
    protected void finalize() throws Throwable { }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/924306.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号