
Object是所有类的父类,任何类都默认继承Object。
Object是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的所有方法。
//Object
public class Object {
}
1构造方法
源码中并没有Object的构造方法,但是,同样的,编译器在编译期间会给Object(事实上,所有的Java类,只要类中没有构造方法,编译器都会默认的给一个空构造方法,若已有构造方法,则不会添加)一个默认的空的构造方法。
2equals
equals() 的作用是 用来判断两个对象是否相等。
equals() 定义在JDK的Objectjava中。
通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
既然Objectjava中定义了equals()方法,这就意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。
但是,使用默认的“equals()”方法,等价于“==”方法。因此,我们通常会重写equals()方法:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。
原则上或者说语义上,设计上目的,equals的作用意义,是用来比较两个对象是否相等,这里是我们通常理解的相等:即两个对象其内容是否相等(相同)。
而程序上来看,这里的作用是判断两个对象是否是同一个对象,即比较其内存地址;
如果想比较两个对象是否是同一个对象(这里是说两个引用是否指向同一个对象),直接用==比较即可(==比较的就是对象的内存地址)。
默认的equals实现,比较的是两对象内存地址,即,若子类不重写equals方法,其作用等同于==。
根据“类是否覆盖equals()方法”,将它分为2类。
(01) 若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过“==”去比较这两个对象。
(02) 我们可以覆盖类的equals()方法,来让equals()通过其它方式比较两个对象是否相等。通常的做法是:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。
我们很大部分时间都是进行两个对象的比较,这个时候Object的equals()方法就局限了,所以才会有String这些类对equals方法的改写,依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。
3hashCode
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode() 定义在JDK的Objectjava中,这就意味着Java中的任何类都包含有hashCode() 函数。
虽然,每个Java类都包含hashCode() 函数。但是,仅仅当创建并某个“类的散列表”(关于“散列表”见下面说明)时,该类的hashCode() 才有用(作用是:确定该类的每一个对象在散列表中的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),类的hashCode() 没有作用。
上面的散列表,指的是:Java集合中本质是散列表的类,如HashMap,Hashtable,HashSet。
也就是说:hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
hashCode()和equal()
hashCode()方法和equal()方法的作用其实一样,在 Java 里都是用来对比两个对象是否相等一致,那么equal()既然已经能实现对比的功能了,为什么还要hashCode()呢?
因为重写的equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高,那么hashCode()既然效率这么高为什么还要equal()呢?
因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:
1equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
2hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
所有对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
这种大量的并且快速的对象对比一般使用的hash容器中,比如hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。
然而hashCode()和equal()一样都是基本类Object里的方法,而和equal()一样,Object里hashCode()里面只是返回当前对象的地址,如果是这样的话,那么我们相同的一个类,new两个对象,由于他们在内存里的地址不同,则他们的hashCode()不同,所以这显然不是我们想要的,所以我们必须重写我们类的hashCode()方法,即一个类,在hashCode()里面返回唯一的一个hash值。
Systemoutpringln(Object); 首先它打印的是Object的toString()方法的返回值。
问题1如你所说的那样。
问题2,打印出来 什么 那要看你tt的toString() 方法是怎么实现的,如果没有toString()方法,那tt会默认继承Object的toString()方法,而Object的toString()方法的实现就是返回对象的地址值。
问题3,String类同样也继承了Object,但是String类重写了Object的toString()方法,重写的目的就是返回字符串值本身,而非地址值。
问题4,同问题3
ahashCode()返回的是哈希值(一个int类型的数),Systemoutprintln(int类型)的时候打印的也是int值本身
问题5,比较的是地址值。
总结: 打印出来什么是看对象类有没有实现toString()方法,如果没有那就打印对象的地址值,如果对象类重写了toString()方法,那就要看方法是怎么实现的了。
亲:希望对你有所帮助,如果觉得还不错,请采纳!
对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable。
为什么这么说呢?考虑一种情况,当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?(注意:集合中不允许重复的元素存在)
也许大多数人都会想到调用equals方法来逐个进行比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了,说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。下面这段代码是javautilHashMap的中put方法的具体实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(keyhashCode());
int i = indexFor(hash, tablelength);
for (Entry<K,V> e = table[i]; e != null; e = enext) {
Object k;
if (ehash == hash && ((k = ekey) == key || keyequals(k))) {
V oldValue = evalue;
evalue = value;
erecordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
put方法是用来向HashMap中添加新的元素,从put方法的具体实现可知,会先调用hashCode方法得到该元素的hashCode值,然后查看table中是否存在该hashCode值,如果存在则调用equals方法重新确定是否存在该元素,如果存在,则更新value值,否则将新的元素添加到HashMap中。从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。
如果对于hash表这个数据结构的朋友不清楚,可以参考这几篇博文;
>
hashCode()返回的是JVM中地址的哈希码,而不是JVM中的地址,要想得到str在物理内存中的真实地存,那只有用JNI技术调用c/c++去实现,否则无能为力,因为java超不出JVM,而JVM对物理内存地址是“不可见”的,否则java中不就有了指针,而去直接 *** 作内存了,当然这是与java语言相违背的。这些只是我个人见解,说不定还真有高手直接用java语言得到了物理内存中的地址了呢。
嗯,是的,你可以简单的将 hashCode 的值理解为内存地址值,但这不是绝对物理地址,它是经过哈希算法转成的 int 值;
“两个对象的hashCode一样的,引用怎么指向啊?”
这个,跟你简单的说一下 java 中内存是怎么管理的你就明白了:
eg:Object obj = new Integer(80);
当一个对象被创建时,将在 JVM 运行空间的堆内存中被分配一块内存,来存放 Integer(80) 这个实例对象,这里的 obj 不是一个对象,而是一个对象(Integer对象)的引用类型变量,引用类型变量 JVM 会在栈内存中给它分配一块内存空间,它的值(obj 的值)其实就是它指向的对象引用的值(hashCode 的值);
很明显,两个对象的 hashCode 值一样,说明它是同一个实例对象,不管有多少个引用类型变量指向这个对象,其实这些引用变量所引用的对象是一样的。
以上就是关于Object类详解全部的内容,包括:Object类详解、关于java中String的地址和值的问题、hashCode方法怎么用等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)