Java Object类方法解析

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

  • registerNatives()

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

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

  • toString()和getClass

  • clone()

  • 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线程之间的通信协作。先具体看下这几个方法的主要含义:

1、wait(…)方法调用后当前线程将立即阻塞,且释放其所持有的同步代码块中的锁,直到被唤醒或超时或打断后且重新获取到锁后才能继续执行;

2、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。由此可以看出,此方法并不是由我们主动去调用的。

Java Object类方法解析的更多相关文章

  1. JAVA Object类方法

    目录 Object类详解 一.==和equals的对比 1.1 ==是一个比较运算符 1.2 equals方法 二.hashCode方法 三.toString方法 四.finalize方法 Objec ...

  2. Java菜鸟学习笔记--面向对象篇(十六):Object类方法

    Object类 什么是Object类? Object类是所有Java类的祖先,每个类都使用 Object 作为超类,所有对象(包括数组)都实现这个类的方法Object类是类层次结构的根,Object类 ...

  3. java Object解析

    java Object是所有对象的根父类,所有对象都直接或间接集成自该类. java 的Object类也比较简单,有equals(Object).toString().finalize() java方 ...

  4. Java 面试知识点解析(三)——JVM篇

    前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...

  5. JAVA使用SAX解析XML文件

    在我的另一篇文章(http://www.cnblogs.com/anivia/p/5849712.html)中,通过一个例子介绍了使用DOM来解析XML文件,那么本篇文章通过相同的XML文件介绍如何使 ...

  6. 【Java】XML解析之DOM

    DOM介绍 DOM(Document Object Model)解析是官方提供的XML解析方式之一,使用时无需引入第三方包,代码编写简单,方便修改树结构,但是由于DOM解析时是将整个XML文件加载到内 ...

  7. Java构造和解析Json数据的两种方法详解二

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...

  8. java集合框架之java HashMap代码解析

     java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...

  9. Java注解全面解析(转)

    1.基本语法 注解定义看起来很像接口的定义.事实上,与其他任何接口一样,注解也将会编译成class文件. @Target(ElementType.Method) @Retention(Retentio ...

随机推荐

  1. 实战开发,使用 Spring Session 与 Spring security 完成网站登录改造!!

    上次小黑在文章中介绍了四种分布式一致性 Session 的实现方式,在这四种中最常用的就是后端集中存储方案,这样即使 web 应用重启或者扩容,Session 都没有丢失的风险. 今天我们就使用这种方 ...

  2. C# WebAPI项目,不支持HttpPut请求!!!

    有点标题党了,这个异常的现象是这样的: 我有一个正在跑的项目,要对接第三方厂家的设备.  对方给的接口文档,里面有一个接口是需要我这边实现的,要求必须是PUT请求方式. 所以我在项目基础上,新增一个W ...

  3. linux 基本命令整理--转

      推荐:http://www.cnblogs.com/lingiu/p/3446647.html 1. 查看目录文件:ls2. 查看目前路径:psw3. 查看文件内容:cat 文件名4. 打开编辑器 ...

  4. 实用教程!SPSSAU验证性因子分析思路总结

    验证性因子分析,是用于测量因子与测量项(量表题项)之间的对应关系是否与研究者预测保持一致的一种研究方法.尽管因子分析适合任何学科使用,但以社会科学居多. 目前有很多软件都可以非常便利地实现验证性因子分 ...

  5. 2、Entity Framework Core 3.1入门教程-创建数据库和迁移

    本文章是根据 微软MVP solenovex(杨旭)老师的视频教程编写而来,再加上自己的一些理解. 视频教程地址:https://www.bilibili.com/video/BV1xa4y1v7rR ...

  6. java父类子类代码

    import java.util.Scanner;import java.util.*; class PersonF{ public void print(String ID,String Workc ...

  7. 全局api 2020/8/14

    // 注意:每次调用 $.get() 或 $.post() 或 $.ajax() 的时候, // 会先调用 ajaxPrefilter 这个函数 // 在这个函数中,可以拿到我们给Ajax提供的配置对 ...

  8. JVM系列.历史上出现过的Java虚拟机

    HotSpot绝对是当今商用虚拟机的王者,但是在Java历史上出现过很多Java虚拟机,这篇文章就来整理下历史上出现过的Java虚拟机以及他们的特性. Sun Classic Sun Classic虚 ...

  9. e3mall商城的归纳总结8之solr集群、activemq的搭建和使用

    由于本节内容比较分散,因此专门为这两个技术进行开展了帖子. solr集群的搭建 solr集群solrJ的测试 activemq的搭建 activemq的使用 引入activemq.jar包 我们先来说 ...

  10. [ASP.NET Core开发实战]基础篇06 配置

    配置,是应用程序很重要的组成部分,常常用于提供信息,像第三方应用登录钥匙.上传格式与大小限制等等. ASP.NET Core提供一系列配置提供程序读取配置文件或配置项信息. ASP.NET Core项 ...