java中的HashSet和TreeSet的区别,以及HashSet导致的内存泄漏详解
来源:互联网 发布:软件系统质量指标 编辑:程序博客网 时间:2024/06/16 11:04
Set集合中的元素是无序的,不可重复的。这个接口下有两个常用集合的实现,HashSet和TreeSet。
HashSet
HashSet底层用的是哈希表,它把对象根据其哈希值存放到对应的区域里。由于这种特性,两个在不同区域的对象会被认为不相同的。
所以如果对象要存放到Hash集合里面,则需要重写对象的hashCode方法,让相等的对象的hashCode的值也相等。
TreeSet
TreeSet采用的数据结构是红黑树,我们可以让它按指定规则对其中的元素进行排序。它又是如何判断两个元素是否相同呢?除了用equals方法检查两个元素是否相同外,还要检查compareTo方法是否返回为0。
所以如果对象要存放到Tree集合里,需要在重写compareTo时,把相同的对象的比较值定为0,防止相同的元素被重复添加进集合中。
面试分享:
HashSet在源代码内是如何实现不add相同的元素的?
理论上我们都知道,它的内部是根据equals()返回值和hashCode()的值是否相同两个方法来判断两个对象是否相同的。而源代码上,HashSet内部用了一个HashMap作存储,add()方法内是调用了map的put()方法,map的put()方法会检查这个键是否已存在,若是则返回该键之前的值,并更新成新值,若不是则返回null,但这个键是不会发生改变的。所以,在源代码里,HashSet的add()方法是根据map的put返回值来判断添加元素是否成功的。
public boolean add(E e ) { return map.put(e, PRESENT)== null; }
HashSet导致的内存泄漏
延伸一下,hash集合在操作不当的情况下,有可能造成内存泄漏。
考虑这样的情况,把一个对象存储进hashSet集合后,修改这个对象中参与计算hash的变量的值,这时这个对象的hash值也会随之改变,那么这么对象可以正常地被删除吗?下面用代码试一下:
先自定一个MPoint类,其中有两个变量,x和y,其中x参与计算hash值
public class MPoint { private int x; private int y; public MPoint() { } public MPoint( int x, int y) { this. x = x; this. y = y; } public int getX() { return x; } public void setX(int x) { this. x = x; } public int getY() { return y; } public void setY(int y) { this. y = y; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; //x参与计算hash值 return result; } @Override public boolean equals(Object obj) { if ( this == obj) return true; if ( obj == null) return false; if (getClass() != obj.getClass()) return false; MPoint other = (MPoint) obj; if ( x != other. x) return false; if ( y != other. y) return false; return true; }}
public class HashSetTest { public static void main(String[] args) { HashSet<MPoint> set = new HashSet<MPoint>(); MPoint mp1 = new MPoint(1, 6); MPoint mp2 = new MPoint(2, 7); MPoint mp3 = new MPoint(1, 6); set.add( mp1); set.add( mp2); set.add( mp3); set.add( mp1); System. out.println( set.size()); // 结果为2 mp1.setX(3); set.remove( mp1); System. out.println( set.size()); // 结果还是为2,说明没有删除成功 System. out.println( set.contains( mp1)); // 结果为false,修改了参与计算hash值的变量,其对象不能再被找到 System. out.println( set.remove( mp1)); // 结果为false,修改了参与计算hash值的变量,其对象不能被删除 mp2.setY(2); System. out.println( set.contains( mp2)); // 结果为true,没有修改关键属性的对象可以被找到 System. out.println( set.remove( mp2)); // 结果为true,没有修改关键属性的对象可以被删除 System. out.println( set.size()); // 结果还是为1 }}
输出结果如下:
22falsefalsetruetrue1
可以看出已经发生了内存泄漏了,mp1对象不能被正常删除。
总结:Java中也有内存泄漏发生,这个知识点或许在面试中会很有用,一定要能说出内存泄漏发生的场景这样的代码细节,才算是真正碰到过。。
1 0
- java中的HashSet和TreeSet的区别,以及HashSet导致的内存泄漏详解
- Java HashSet和TreeSet的区别
- Java中HashSet和TreeSet的区别
- Java中HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet和TreeSet的区别
- HashSet,和TreeSet的区别
- HashSet 和 TreeSet 的区别
- HashSet和TreeSet的区别
- Java中HashSet、TreeSet的区别
- Java中的HashSet和TreeSet
- HashSet,TreeSet和LinkedHashSet的区别
- ThreadGroup线程组使用
- Android Media显示的层次
- sql语句添加主键
- elasticsearch环境搭建与使用
- QGIS使用栅格图层
- java中的HashSet和TreeSet的区别,以及HashSet导致的内存泄漏详解
- Android中EditText中的InputType类型含义与如何定义
- Android Studio如何在项目中使用jni以及OpenCV库
- Cocos2dxActivity cannot be resolved to a type解决方案
- QT5入门之26 -QLabel
- Hadoop的map获取当前spilt文件名
- ORACLE存储过程的应用(1流水号)
- android sdk版本版本与ADT版本不兼容的处理办法
- 利用SpannableString实现标签TAG效果(可加圆角)