Java API:Object class

Java API:Object class

    首先简单的介绍一下Object类。

    java.lang.Object

java.lang包子使用的时候,不用显示导入,由编译器自动导入。

    Objec(即对象类)是JDK1.0就出现的,是类层次结构的根,是Java中的顶级父类,Java中所有的类都默认直接或者间接的继承Object类。Objec是Java中唯一没有父类的类,任何一个类的对象都可以用Object对象接收。如下:

//如下操作都是可以的。
Object o1=new Object();
Object o2=new String();
Object o3=new ArrayList<>();
Object o4=new HashSet<>();
Object o5=new HashMap<>();
Object o6=new Integer(1);

    然后我们看一下,Object这个类的整体结构。

    如上图,我使用的是1.8的jdk,总共13个方法,本博文将参照API文档以及源码进行介绍。

1、构造方法

    API文档中构造方法中提供的所有构造方法默认是public修饰的。

    API文档中提供了:pulbic Object()的构造方法,在实际代码中,没有写出,使用的是JVM提供的默认构造。

2、重要方法

1.clone();

    此方法用来克隆对象。克隆完成之后会产生一个新的对象,这个新对象和原对象的地址不同但是属性值是一样的。

    此方法说的通俗一点,就是一间房子完全仿照另外一间房子建造,不同的只是位置,其他的全部一样。

    一个对象要想被克隆,那么这个对象对应的类必须实现Cloneable接口,Cloneable接口中没有任何的方法和属性,仅仅用于标识这个类产生的对象可以被克隆。

    源码如下:

//方法源码
protected native Object clone() throws CloneNotSupportedException;

//接口源码
public interface Cloneable {
}

    此方法是一个受保护的本地方法。native关键字修饰的是本地方法,底层是用c/c++语言实现的,Java源码中看不到其具体实现。

    下面提供一个示例:

public class T1 implements Cloneable {
	int i;
	public static void main(String[] args) throws CloneNotSupportedException {
		T1 t = new T1();
		t.i = 5;
		T1 t1 = (T1) t.clone();
		System.out.println(t);
		System.out.println(t1);
	}
}

2.equals(Object obj)

    此方法用于判断两个对象是否一致。

    如下是源码:

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

    从源码中可以看出,默认使用的是==运算符,比较的是对象的地址,也可以得出另外一个结论,Object类中的equals方法等价于==。在开发中一般都要重写这个方法。Eclipse中右键Sourec中有自动生成。

equals方法的特点

    其实这些特点都是我们很早就学过的数学上的相等的特点。以下提及的都是非空和不是NAN的情况。

    自反性:a.equals(a)结果为true。即自己等于自己,数学上的1=1。

    对称性:a.equals(b)结果为true,那么在a和b都不发生改变的情况下,b.equals(a)结果也为true。即数学上的a=b,那么b=a。

    一致性:a.equals(b)结果为true,那么在a和b没有发生过改变的情况下a.equals(b)结果一直为true。即a永远和b相等,也就是1=1永远都是这样。

    约定:a.equals(null)为false,即非空a永远不等于null。

==和equals有什么区别

    只有当继承Object的类重写了equals方法之后,此类中的equals方法才和==才有可能不同,但这两个比较的使用的本质上还是有一些不同。

    抛开重写不说,当比较的是基本类型的时候,==判断的是实际数据,并且基本类型身上也没有equals方法可以调用。对于引用类型而言==判断的是地址,equals则默认和==是一样的。equals只能作用于引用类型,默认比较的是两个对象的地址。

    当重写来equals的时候,按照重写之后的逻辑进行比较。此时比较的逻辑才和==有很大的不同。

    所以仅使用==是无法彻底判断两个对象是否相等,我们需要针对equals方法进行重写,步骤如下:

书写步骤:

    1.判断地址是否一样,即直接使用==运算符。

    2.判断对象是否为空。

    3.判断对象的创建类型是否一致。

    4.判断属性值是否一致。判断之前要将对象强转为顶级父类。判断属性值的时候注意String类型的判断。

    示例:

Public boolean equals(Object obj){
		if (this == obj)						//1.判断地址是否一致
			return true;
		if (obj == null)						//2.判断参数是否为空
			return false;
		if (getClass() != obj.getClass())		//3.判断类型是否一致
			return false;
		Person other = (Person) obj;			//4.强制转换类别
		if (age != other.age)					//5.判断属性是否一致
			return false;
		if (gender != other.gender)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

3.finalize()

    通知gc回收垃圾对象,但是垃圾回收器不一定执行。

    源码如下:

protected void finalize() throws Throwable { }

    你没有看错,源码是个空方法,即使gc开始运行,也只回收当前对象而不回收其他对象。

    首先,Object中定义finalize方法表明Java中每一个对象都将具有finalize这种行为,其具体调用时机在:JVM准备对此对形象所占用的内存空间进行垃圾回收前,将被调用。由此可以看出,此方法并不是由我们主动去调用的(虽然可以主动去调用,此时与其他自定义方法无异)。

    相似的:System.gc();通知gc回收对象,不限制范围。

4.getClass();获取类型

    获取对象的实际类型(创建类型)。

Object o1=new Object();
o1.getClass();
//上面等同于下面
Object.class

    视具体场景而定,使用哪种方法实现获取类型。

    源码如下:

public final native Class<?> getClass();

    由源码可以看出,此方法也使用native修饰。

5.hashCode();返回哈希码

    返回对象的哈希码值的十进制。哈希码是一串32位的二进制数据,由于出现相同的数值的概率非常低,所以可以认为是唯一的。

    源码如下:

public native int hashCode();

    由源码可以看出,此方法也使用native修饰。一般重写equals方法的同时都会重写这个方法。但是不建议手动重写,使用IDE生成即可。

    重写hashCode的时候,当equals值为true的时候,哈希码必须一致。但是哈希码一致equals不一定为true。

6.toString();返回对象的字符串形式

    返回该对象的字符串表示。当打印对象的时候默认是调用了这个对象的toString方法。一般会重写。

    源码如下:

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

    该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串。所以切记不要搞混了,这里默认返回的不是对象的内存地址。

7.registerNatives()

    registerNatives函数前面有native关键字修饰,Java中,用native关键字修饰的函数表明该方法的实现并不是在Java中去完成,而是由C/C++去完成,并被编译成了.dll,由Java去调用。方法的具体实现体在dll文件中,对于不同平台,其具体实现应该有所不同。用native修饰,即表示操作系统,需要提供此方法,Java本身需要使用。具体到registerNatives()方法本身,其主要作用是将C/C++中的方法映射到Java中的native方法,实现方法命名的解耦。

    既然如此,可能有人会问,registerNatives()修饰符为private,且并没有执行,作用何以达到?其实,在Java源码中,此方法的声明后有紧接着一段静态代码块,如下:

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

8.多线程相关的方法

    如下是这几个方法的源码:

//唤醒在此对象监听器上的单个等待的线程
public final native void notify();
//唤醒再次对象监听器上的所有等待的线程
public final native void notifyAll();
//线程处于等待timeout的时长,使用以上两个方法可以提前唤醒,也可以到时自己醒。
public final native void wait(long timeout) throws InterruptedException;
//线程处于等待状态,只能被notify()/notifyAll()方法唤醒。
public final void wait() throws InterruptedException {
    //调用的wait方法,但是没有时长。
    wait(0);
}
//timeout - 要等待的最长时间(以毫秒为单位)。
//nanos - 额外时间(以毫微秒为单位,范围是 0-999999)。 
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");
    }
    //如果额外的时间大于500000毫微秒或者额外的时间不等于0等待时间为0
    if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
        //等待时间增加
        timeout++;
    }
    //调用本地方法
    wait(timeout);
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏wannshan(javaer,RPC)

spring里MethodInvokingFactoryBean和MethodInvokingBean工具类

最近翻代码,看到两个工具类,可以通过配置灵活的创建,修改你的bean实例。 (InvoKeTestCls类代码在文章最后) MethodInvokingFac...

3447
来自专栏GreenLeaves

C# this关键字(给底层类库扩展成员方法)

本文参考自唔愛吃蘋果的C#原始类型扩展方法—this参数修饰符,并在其基础上做了一些细节上的解释 1、this作为参数关键字的作用 使用this关键字,可以向t...

1787
来自专栏开心的学习之路

JavaScript概览

近日的项目需要用JavaScript完成,于是决定通读《JavaScript高级程序设计第三版》,书是2012年的,比较老了,但是可以用来快速了解JavaScr...

2854
来自专栏从流域到海域

《笨办法学Python》 第30课手记

《笨办法学Python》 第30课手记 本节课讲if语句的嵌套,和c的差别仅仅是将else if简写成elif,其余类似。 原代码如下: people = 30...

1727
来自专栏Crossin的编程教室

​Python 3 新特性:类型注解

我们知道 Python 是一种动态语言,变量以及函数的参数是不区分类型。因此我们定义函数只需要这样写就可以了:

1322
来自专栏Ryan Miao

String的按值传递,java传参都是传值

java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? String和int参数传递是按值传递还是引用传递? 一道面试题目,String的传递: p...

3066
来自专栏九彩拼盘的叨叨叨

JavaScript 之 this

在 JavaScript 中,this 的值是动态的,即一个函数中在不同的情况下被调用,this 的值可能是不同的。

822
来自专栏Python数据科学

Python爬虫之快速入门正则表达式

当完成了网页html的download之后,下一步当然是从网页中解析我们想要的数据了。那如何解析这些网页呢?Python中有许多种操作简单且高效的工具可以协助我...

983
来自专栏iOS开发攻城狮的集散地

浅谈iOS内存管理机制

1929
来自专栏测试开发架构之路

C++之new/delete/malloc/free详解

主要内容: 1.  C语言中的函数malloc和free 2.  C++中的运算符new和delete 3.  new/delete与malloc/free之间...

2915

扫码关注云+社区