JDK源码解读:Object类

1. private static native void registerNatives();

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

为了加深对java本地方法的理解,在网上找到了该方法的C源码部分,如下:
static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

3.protected native Object clone() throws CloneNotSupportedException;

看,clone()方法又是一个被声明为native的方法,因此,我们知道了clone()方法并不是Java的原生方法,具体的实现是有C/C++完成的。clone英文翻译为"克隆",其目的是创建并返回此对象的一个副本。形象点理解,这有一辆科鲁兹,你看着不错,想要个一模一样的。你调用此方法即可像变魔术一样变出一辆一模一样的科鲁兹出来。配置一样,长相一样。但从此刻起,原来的那辆科鲁兹如果进行了新的装饰,与你克隆出来的这辆科鲁兹没有任何关系了。你克隆出来的对象变不变完全在于你对克隆出来的科鲁兹有没有进行过什么操作了。Java术语表述为:clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。

调用clone方法必须要实现Cloneable接口

4.public final native Class<?> getClass();

getClass()也是一个native方法,返回的是此Object对象的类对象/运行时类对象Class<?>。效果与Object.class相同。

首先解释下"类对象"的概念:在Java中,类是是对具有一组相同特征或行为的实例的抽象并进行描述,对象则是此类所描述的特征或行为的具体实例。作为概念层次的类,其本身也具有某些共同的特性,如都具有类名称、由类加载器去加载,都具有包,具有父类,属性和方法等。于是,Java中有专门定义了一个类,Class,去描述其他类所具有的这些特性,因此,从此角度去看,类本身也都是属于Class类的对象。为与经常意义上的对象相区分,在此称之为"类对象"。

此处主要大量涉及到Java中的反射知识,关于反射相关知识后续也会给出相关博文。

5.public boolean equals(Object obj);

与equals在Java中经常被使用,大家也都知道与equals的区别:

==表示的是变量值完成相同(对于基础类型,地址中存储的是值,引用类型则存储指向实际对象的地址);

equals表示的是对象的内容完全相同,此处的内容多指对象的特征/属性。

实际上,上面说法是不严谨的,更多的只是常见于String类中。首先看一下Object类中关于equals()方法的定义:

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

由此可见,Object原生的equals()方法内部调用的正是==,与==具有相同的含义。既然如此,为什么还要定义此equals()方法?

equlas()方法的正确理解应该是:判断两个对象是否相等。那么判断对象相等的标尺又是什么?

如上,在object类中,此标尺即为==。当然,这个标尺不是固定的,其他类中可以按照实际的需要对此标尺含义进行重定义。如String类中则是依据字符串内容是否相等来重定义了此标尺含义。如此可以增加类的功能型和实际编码的灵活性。当然了,如果自定义的类没有重写equals()方法来重新定义此标尺,那么默认的将是其父类的equals(),直到object基类。

如下场景的实际业务需求,对于User bean,由实际的业务需求可知当属性uid相同时,表示的是同一个User,即两个User对象相等。则可以重写equals以重定义User对象相等的标尺。

复制代码
1 package com.corn.objectsummary;
2
3 public class User {
4
5 private int uid;
6 private String name;
7 private int age;
8
9 public int getUid() {
10 return uid;
11 }
12
13 public void setUid(int uid) {
14 this.uid = uid;
15 }
16
17 protected String getName() {
18 return name;
19 }
20
21 public void setName(String name) {
22 this.name = name;
23 }
24
25 public int getAge() {
26 return age;
27 }
28
29 public void setAge(int age) {
30 this.age = age;
31 }
32
33 @Override
34 public boolean equals(Object obj) {
35 if (obj == null || !(obj instanceof User)) {
36 return false;
37 }
38 if (((User) obj).getUid() == this.getUid()) {
39 return true;
40 }
41 return false;
42 }
43 }
复制代码
复制代码
1 package com.corn.objectsummary;
2
3 public class ObjectTest implements Cloneable {
4
5 public static void main(String[] args) {
6 User u1 = new User();
7 u1.setUid(111);
8 u1.setName(“张三”);
9
10 User u2 = new User();
11 u2.setUid(111);
12 u2.setName(“张三丰”);
13
14 System.out.println(u1.equals(u2)); //返回true
15 }
16
17 }
复制代码
ObjectTest中打印出true,因为User类定义中重写了equals()方法,这很好理解,很可能张三是一个人小名,张三丰才是其大名,判断这两个人是不是同一个人,这时只用判断uid是否相同即可。

如上重写equals方法表面上看上去是可以了,实则不然。因为它破坏了Java中的约定:重写equals()方法必须重写hasCode()方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值