1. 堆栈用途简述
- 堆内存用来存放由new创建的对象(包括由基本类型包装起来的类:Integer、String、Double,实际上每个基本类型都有他的包装类)和数组(引用类型、包装类)。
- 栈内存存放对象在堆中的内存地址(基本类型直接存储在栈内存中)
2. == 与 Equals()
- 基本类型 '==' 比较值,不能使用equals
- 对于引用数据类型(对象)来说,'==' 和 'equals'都是用来比较两个变量的地址
- String类重写了equals方法,所以String.equals()可以比较两个字符串内容是否相等。
public static void main(String[] args) {
// integer 在常量区存储范围是[-128,127],超出这个范围的值会在堆内存中创建一个新对象来保存值
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // 基本类型 == 比较值 不能使用equals()
System.out.println(a.equals(b));
// 引用类型 == 比较内存地址 equals比较内容(String 类型除外)
//c、d是两个新对象,内存地址不同
Integer c = 150;
Integer d = 150;
System.out.println(c == d); // 比较内存地址
System.out.println(c.equals(d)); // 未重写equals方法,比较内容是否相同
String str = "aaa";
String str1 = "aaa";
System.out.println(str == str1); // 字面量方式创建字符串,值存储在栈内,地址相同
System.out.println(str.equals(str1));
String s = new String("bbb");
String s1 = new String("bbb");
System.out.println(s == s1); // new出来的对象重新分配内存地址,s与s1地址不同,故输出false 变量值存储在堆内,栈存储的是值最堆中的地址
System.out.println(s.equals(s1)); //String类型重写了equals方法 要判断对象的内存地址和值
}
输出结果:
Object类中的equals方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
String类型中重写后的equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
使用equals() 进行比较时方法时,我们还应了解hashcode。
hashcode方法返回对象的哈希码值。 * hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数, * 前提是对象上 equals 比较中所用的信息没有被修改。 * 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
package com.lxj.demoTest;
import org.junit.Test;
public class HashCodeTest {
/**
* hashcode() 获取哈希值
*/
@Test
public void testHash() {
Integer a = 10;
System.out.println(a.hashCode());
String str = "abc";
System.out.println(str.hashCode());
User user = new User();
System.out.println(user.hashCode());
}
}
结果分析:
- integer类型的数据,返回的hash值为数据本身;
- 对象类型的数据,返回的一串字符;
- String类型的数据,返回一串字符;
比较两个值是否相等时,先通过比较两个值的哈希值(hashcode),然后再重写equals()方法来判定两个值是否相等(hashcode不相同则两个值必定不相等,hashcode相同,两个值可能相等)
package com.lxj.boomFilter;
import java.util.HashSet;
import java.util.Set;
public class HashDemo {
private int i;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
/**
* @param object
* @return
*/
public boolean equals(Object object) {
if (object == null) {
return false;
}
if (object == this) {
return true;
}
if (!(object instanceof HashDemo)) {
return false;
}
HashDemo other = (HashDemo) object;
if (other.getI() == this.getI()) {
return true;
}
return false;
}
public int hashCode() {
return i % 10;
}
public final static void main(String[] args) {
HashDemo a = new HashDemo();
HashDemo b = new HashDemo();
a.setI(1);
b.setI(1);
Set<HashDemo> set = new HashSet<HashDemo>();
set.add(a);
set.add(b);
System.out.println(a.hashCode() == b.hashCode());
System.out.println(a.equals(b));
System.out.println(set);
}
}
未重写 equals方法时,输出结果为 true false [com.lxj.boomFilter.HashDemo@1][com.lxj.boomFilter.HashDemo@1],此时HashSet中存放两个对象。
重写equals 方法后,执行输出结果为 true true [com.lxj.boomFilter.HashDemo@1],HaseSet中存放一个对象
运行结果:
3. HashCode源码(转)
Object对hashCode()的方法实现
public native int hashCode();
String 对hashCode()的方法实现
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
Integer对hashCode()的实现
@Override
public int hashCode() {
return Integer.hashCode(value);
}
四、了解String对hashCode的计算
1、在String对象的创建,都是将String数据拆分为char类型 private final char value[];
2、对于计算hash值,为了区别"123"和"321"计算hash值一样的问题,对hash值计算时添加"权重"的思想;
所以对于Stirng类型的hash值计算思路:
public class Test {
public static void main(String[] args) {
String str = "ABC";
System.out.println(str.hashCode());
}
}
查询ascII码,我们知道A对应的十进制为65;B为66;C为67
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
计算过程为
1、(31*0+'A') 65
2、(31*0+'A')*31+'B' 65*31+66 = 2081
3、((31*0+'A')*31+'B')*31+'C' 2081*31+67=64578