ArrayList、HashSet的比较及Hashcode分析

本文探讨了Java中内存泄露的现象及其原因,并通过实例详细解释了hashCode方法的作用及其实现原理,展示了如何避免因对象修改而导致的内存泄露。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------- android培训、java培训、期待与您交流! ----------

java中有内存泄露吗?为什么?

有,所谓的内存泄露就是这个对象不用了,结果这个对象一直占用内存空间没有被释放,这就叫内存泄露。有个对象一直不用了,一直往下运行,占用空间。当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下的时候,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。

hashCode方法的作用?

加入一个集合中存入了一万个元素,现在想要向集合中放进去一个元素,如果有相同的就放不进去,如果没有就可以放进去,取出第一个比较是否相等,取出第二个,第三个,依次比较直到取出第一万个进行比较。显然,这样必须得找一万遍才可以。所以为了提高效率,产生了hashCode这种算法,它把集合分成了若干个区域,每一个要存进来的对象可以算出来一个值,根据算出来的值,就把其放入相应的区域,假设将集合分成32个区域,此时要放入一个对象,算出对象的值(哈希值)为区域1中,现在要查找某个对象,这时可以先算出这个对象的hashCode值,看他属于第几个区域,如果属于第二个区域,就在第二个区域中判断是否有相等的对象,这样查找的性能提高了。这就是hashCode的作用。要想让hashCode有作用的话,前提必须是对象存到HashSet集合中。

代码演示:

public class ReflectTest2 {


	public static void main(String[] args) {
		//ArrayList可以放置重复的对象的应用。
		//HashSet放入之前判断有没有重复的,如果有就不放进入;并不是覆盖
		
		
		//面向接口编程或者面向父类编程
		//Collection collections = new ArrayList();这种
		
		Collection collections = new HashSet();//面向接口编程或者面向父类编程
		ReflectPoint pt1 = new ReflectPoint(3, 3);
		ReflectPoint pt2 = new ReflectPoint(5, 5);
		ReflectPoint pt3 = new ReflectPoint(3, 3);
		collections.add(pt1);
		collections.add(pt2);
		collections.add(pt3);
		collections.add(pt1);
		/*
		如果希望以上的p1和p3相等,那么就必须自己写equals和hashCode方法,否则,默认的
		equals方法比较的是hashCode的值,通常hashCode的值是根据内存地址换算出来的。
		所以就在ReflectPoint中产生这两个方法,覆盖后hashCode值就是根据x和y了,而不是根据内存引用地址产生的。、
		所以输出的长度就为2。
		*/
		
		//存进去后改y的值,这种情况下会发生内存泄漏。
		pt1.y = 7;
		collections.remove(pt1);//输出2,删除不掉的
		
		System.out.println(collections.size());
	}

}

public class ReflectPoint {

	private int x;
	public int y;
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "itcast";
	
	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}

	//如果将这个方法干掉,显示的结果有可能是3(也有可能是2)
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReflectPoint other = (ReflectPoint) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}



	@Override
	public String toString(){
		return str1 + ":" + str2+":"+str3;
	}
}

以上代码分析:

不覆写hashCode()和equals方法时候,new ArrayList的时候输出的长度为4?

new HashSet时候输出长度为3。由此引发的一个问题:ArrayList和HashSet存储的区别?对于ArrayList它是一种有顺序的集合,就相当于一个数组,当放入一个对象的时候,首先找到第一个空位置,将对象的应用放进去。依次进行,放入对象的应用,如果遇到相同的引用时,还会依次放进去。其中有多个引用变量指向的是同一个变量,也没有关系。按照先后顺序依次放入。

 

没有实现equals、hashCode方法为什么就等于3呢?

因为这两个对象的hashCode的值是按照内存地址算出来的。这两个本来认为该相同的对象,分别被存放到了不同的区域,当要找这个对象的时候,我在我的区域中找,不在那个区域找。那个区域也有一个相同的。但是不去那个区域找就被放进去了。为了让这个相等的对象也放在相等的区域,如果两个对象equals相等的话,应该让它们的hashCode也相等。如果对象不存放到hashSet集合中,就不用hashCode了。

注意:hashSet放入之前先比较有没有相等的对象,如果有就不会放进去,注意,不是覆盖,而是不放进去,如果想覆盖原来的对象,必须将原有的remove掉。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值