------- 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掉。