Java常用工具类---Java集合

集合框架的体系结构

List(列表)

  • List是元素有序并且可以重复的集合,称为刚列
  • List可以精确的控制每个元素的插入位置,或删除某个位置的元素
  • List的两个主要实现类是 ArrayList和 LinkedList

ArrayList

  • ArrayList底层是由数组实现的
  • 动态增长,以满足应用程序的需求
  • 在列表尾部插入或删除非常有效
  • 更适合查种更新元素
  • Array List中的元素可以为null

案例:用 ArrayList存储编程语言的名称,并输出。

名称包括”Java″、"c"、"C++“、"Go"和" Swift"。

package com.imooc.set;

import java.util.ArrayList;
import java.util.List;

public class ListDemo1 {

	public static void main(String[] args) {
		// 用ArrayList存储编程语言的名称,并输出
		List list=new ArrayList();
		list.add("Java");
		list.add("C");
		list.add("C++");
		list.add("Go");
		list.add("swift");
		//输出列表中元素的个数
		System.out.println("列表中元素的个数为:"+list.size());
		
		//遍历输出所有编程语言
		System.out.println("**************************************");
		for(int i=0;i<list.size();i++){
			System.out.print(list.get(i)+",");
		}
		
		//移除列表中的C++
		System.out.println();
		//list.remove(2);
		list.remove("C++");
		System.out.println("**************************************");
		System.out.println("移除C++以后的列表元素为:");
		for(int i=0;i<list.size();i++){
			System.out.print(list.get(i)+",");
		}
	}

}

 案例:公告管理

  • 需求

  1. 公告的加和显示

  2. 在定位置处插入公告

  3. 删除公告

  4. 修改公告

  • 公告类属性
  1. 编号id
  2. 标题title
  3. 创建人 creator
  4. 创建乐间 createTime
  • 公告类方法
  1. 构造方法
  2. 款取和设置属性值的方法
package com.imooc.set;

import java.util.Date;

public class Notice {
	private int id;//ID
	private String title;//标题
	private String creator;//创建人
	private Date createTime;//创建时间
	public Notice(int id, String title, String creator, Date createTime) {
		super();
		this.id = id;
		this.title = title;
		this.creator = creator;
		this.createTime = createTime;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCreator() {
		return creator;
	}
	public void setCreator(String creator) {
		this.creator = creator;
	}
	public Date getCreateTime() {
		return createTime;
	}
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}
	
	
}
package com.imooc.set;

import java.util.ArrayList;
import java.util.Date;

public class NoticeTest {

	public static void main(String[] args) {
		// 创建Notice类的对象,生成三条公告
		Notice notice1 = new Notice(1, "欢迎来到慕课网!", "管理员", new Date());
		Notice notice2 = new Notice(2, "请同学们按时提交作业!", "老师", new Date());
		Notice notice3 = new Notice(3, "考勤通知!", "老师", new Date());

		// 添加公告
		ArrayList noticeList = new ArrayList();
		noticeList.add(notice1);
		noticeList.add(notice2);
		noticeList.add(notice3);

		// 显示公告
		System.out.println("公告的内容为:");
		for (int i = 0; i < noticeList.size(); i++) {
			System.out.println(i + 1 + ":" + ((Notice) (noticeList.get(i))).getTitle());
		}

		System.out.println("**************************************");
		// 在第一条公告后面添加一条新公告
		Notice notice4 = new Notice(4, "在线编辑器可以使用啦!", "管理员", new Date());
		noticeList.add(1, notice4);

		// 显示公告
		System.out.println("公告的内容为:");
		for (int i = 0; i < noticeList.size(); i++) {
			System.out.println(i + 1 + ":" + ((Notice) (noticeList.get(i))).getTitle());
		}

		System.out.println("**************************************");
		// 删除按时提交作业的公告
		noticeList.remove(2);
		// 显示公告
		System.out.println("删除公告后的内容为:");
		for (int i = 0; i < noticeList.size(); i++) {
			System.out.println(i + 1 + ":" + ((Notice) (noticeList.get(i))).getTitle());
		}
		
		//将第二条公告改为:Java在线编辑器可以使用啦!
		System.out.println("**************************************");
		//修改第二条公告中title的值
		notice4.setTitle("Java在线编辑器可以使用啦!");
		noticeList.set(1, notice4);
		System.out.println("修改后公告的内容为:");
		for (int i = 0; i < noticeList.size(); i++) {
			System.out.println(i + 1 + ":" + ((Notice) (noticeList.get(i))).getTitle());
		}
	}

}

Set

Set是元素无序并且不可以重复的集合,被称为集。

 

HashSet

  • HashSet是Set的一个重要实现类,称为哈希集
  • HasSet的元素无序并且不可以重复
  • HashSet中只允许一个null元素
  • 具有良好的存取和查找性能

案例:用Hashset惴多个表示颜色的英文单词,并输出。
单词包括:"blue"、“"red"、" black"" yellow"和" white"

package com.imooc.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class WordDemo {

	public static void main(String[] args) {
		// 将英文单词添加到HashSet中
		Set set = new HashSet();
		// 向集合中添加元素
		set.add("blue");
		set.add("red");
		set.add("black");
		set.add("yellow");
		set.add("white");
		// 显示集合的内容
		System.out.println("集合中的元素为:");
		Iterator it = set.iterator();
		// 遍历迭代器并输出元素
		while (it.hasNext()) {
			System.out.print(it.next() + "   ");
		}
		System.out.println();
		// 在集合中插入一个新的单词
		// set.add("green");
		set.add("white");
		it = set.iterator();
		// 遍历迭代器并输出元素
		System.out.println("**************************");
		System.out.println("插入重复元素后的输出结果为:");
		while (it.hasNext()) {
			System.out.print(it.next() + "   ");
		}
		//插入失败,但是不会报错
	}

}

 案例:物猫信息管理

  • 需求

  1. 添加和显示物猫信息

  2. 查找某只宠物猫的信息并输出

  3. 修改物猫的信息

  4. 删除宠物猫信息

package com.imooc.set;

public class Cat {
	private String name; //名字
	private int month; //年龄
	private String species;//品种
	
	//构造方法
	public Cat(String name, int month, String species) {
		super();
		this.name = name;
		this.month = month;
		this.species = species;
	}
    //getter与setter方法
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public String getSpecies() {
		return species;
	}

	public void setSpecies(String species) {
		this.species = species;
	}
	@Override
	public String toString() {
		return "[姓名:" + name + ", 年龄:" + month + ", 品种:" + species + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + month;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((species == null) ? 0 : species.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		//判断对象是否相等,相等则返回true,不用继续比较属性了
		if(this==obj)
			return true;
		//判断obj是否是Cat类的对象
		if(obj.getClass()==Cat.class){
			Cat cat=(Cat)obj;
			return cat.getName().equals(name)&&(cat.getMonth()==month)&&(cat.getSpecies().equals(species));
		}
		
		return false;
	}
	
	
}
package com.imooc.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class CatTest {

	public static void main(String[] args) {
		// 定义宠物猫对象
		Cat huahua = new Cat("花花", 12, "英国短毛猫");
		Cat fanfan = new Cat("凡凡", 3, "中华田园猫");
		// 将宠物猫对象放入HashSet中
		Set<Cat> set = new HashSet<Cat>();
		set.add(huahua);
		set.add(fanfan);
		// 显示宠物猫信息
		Iterator<Cat> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

		// 再添加一个与花花属性一样的猫
		Cat huahua01 = new Cat("花花", 12, "英国短毛猫");
		set.add(huahua01);
		System.out.println("**********************************");
		System.out.println("添加重复数据后的宠物猫信息:");
		it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

		System.out.println("**********************************");
		// 重新插入一个新宠物猫
		Cat huahua02 = new Cat("花花二代", 2, "英国短毛猫");
		set.add(huahua02);
		System.out.println("添加花花二代后的宠物猫信息:");
		it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}

		System.out.println("**********************************");
		// 在集合中查找花花的信息并输出
		if (set.contains(huahua)) {
			System.out.println("花花找到了!");
			System.out.println(huahua);
		} else {
			System.out.println("花花没找到!");
		}
		// 在集合中使用名字查找花花的信息
		System.out.println("**********************************");
		System.out.println("通过名字查找花花信息");
		boolean flag = false;
		Cat c = null;
		it = set.iterator();
		while (it.hasNext()) {
			c = it.next();
			if (c.getName().equals("花花")) {
				flag = true;// 找到了
				break;
			}
		}
		if (flag) {
			System.out.println("花花找到了");
			System.out.println(c);
		} else {
			System.out.println("花花没找到");
		}

		// 删除花花二代的信息并重新输出
		for (Cat cat : set) {
			if ("花花二代".equals(cat.getName())) {
				set.remove(cat);
				break;
			}
		}
		System.out.println("**********************************");

		System.out.println("删除花花二代后的数据");
		for (Cat cat : set) {
			System.out.println(cat);
		}
		// 删除集合中的所有宠物猫信息
		System.out.println("**********************************");
		boolean flag1 = set.removeAll(set);
		if (set.isEmpty()) {
			System.out.println("猫都不见了。。。");
		} else {
			System.out.println("猫还在。。。");
		}
	}
}

 

Iterator(迭代器)

  • Iterator接口可以以统一的方式对各种集合元素进行遍历
  • hasNext()方法检测集合中是否还有下—个元素
  • next()方法返回集合中的下一个元素
Iterator<String> it =set.iterator();
while(it.hasNext()){
    System.out.println(it.next()+" ");
}

Map

  • Map中的数据是以键值对(key-value)的形式存储的
  • key-value以 Entry类型的对象实例在
  • 可以通过key值快速地查找value
  • 个映射不能包含重复的键
  • 每个键最多只能映射到个值

HashMap

  • 基于哈希表的Map接口的实现
  • 允许使用null值和null键
  • key值不允许重复
  • HashMap中的Entry对象是无序排列的

完成一个类似字典的功能

  • 将单词以及单词的注释存储到 HashMap中
  • 显示 HashMap中的内容
  • 查某个单词的注释并显示
package com.imooc.set;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;

public class DictionaryDemo {

	public static void main(String[] args) {
		Map<String,String> animal=new HashMap<String,String>();
		System.out.println("请输入三组单词对应的注释,并存放到HashMap中");
		Scanner console=new Scanner(System.in);
		//添加数据
		int i=0;
		while(i<3){
			System.out.println("请输入key值(单词):");
			String key=console.next();
			System.out.println("请输入value值(注释):");
			String value=console.next();
			animal.put(key, value);
			i++;
		}
		//打印输出value的值(直接使用迭代器)
		System.out.println("*****************************************");
		System.out.println("使用迭代器输出所有的value:");
		Iterator<String> it=animal.values().iterator();
		while(it.hasNext()){
			System.out.print(it.next()+"    ");
		}
		System.out.println();
		System.out.println("*****************************************");
		//打印输出key和value的值
		//通过entrySet方法
		System.out.println("通过entrySet方法得到key-value:");
		Set<Entry<String, String>> entrySet=animal.entrySet();
		for(Entry<String, String> entry:entrySet){
			System.out.print(entry.getKey()+"-");;
			System.out.println(entry.getValue());
		}
		System.out.println();
		System.out.println("*****************************************");
		
		//通过单词找到注释并输出
		//使用keySet方法
		System.out.println("请输入要查找的单词:");
		String strSearch=console.next();
		//1.取得keySet
		Set<String> keySet=animal.keySet();
		//2.遍历keySet
		for(String key:keySet){
			if(strSearch.equals(key)){
				System.out.println("找到了!"+"键值对为:"+key+"-"+animal.get(key));
				break;
			}
		}
	}

}

案例2:商品信息管理

  • 使用 HashMap对商品信息进行管理
  • 其中key为商品编号,value为商品对象
  • 对 HashMap中的商品信息进行增、删、改、查操作
package com.imooc.set;

public class Goods {
	private String id;//商品编号
	private String name;//商品名称
	private double price;//商品价格
	//构造方法
	public Goods(String id,String name,double price){
		this.id=id;
		this.name=name;
		this.price=price;
	}

	//getter和setter方法
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}
	public String toString(){
		return "商品编号:"+id+",商品名称:"+name+",商品价格:"+price;
	}
}
package com.imooc.set;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class GoodsTest {

	public static void main(String[] args) {

		Scanner console = new Scanner(System.in);
		// 定义HashMap对象
		Map<String, Goods> goodsMap = new HashMap<String, Goods>();
		System.out.println("请输入三条商品信息:");
		int i = 0;
		while (i < 3) {
			System.out.println("请输入第" + (i + 1) + "条商品信息:");
			System.out.println("请输入商品编号:");
			String goodsId = console.next();
			// 判断商品编号id是否存在
			if (goodsMap.containsKey(goodsId)) {
				System.out.println("该商品编号已经存在!请重新输入!");
				continue;
			}
			System.out.println("请输入商品名称:");
			String goodsName = console.next();
			System.out.println("请输入商品价格:");
			double goodsPrice = 0;
			try {
				goodsPrice = console.nextDouble();
			} catch (java.util.InputMismatchException e) {
				System.out.println("商品价格的格式不正确,请输入数值型数据!");
				console.next();
				continue;
			}
			Goods goods = new Goods(goodsId, goodsName, goodsPrice);
			// 将商品信息添加到HashMap中
			goodsMap.put(goodsId, goods);
			i++;
		}
		// 遍历Map,输出商品信息
		System.out.println("商品的全部信息为:");
		Iterator<Goods> itGoods = goodsMap.values().iterator();
		while (itGoods.hasNext()) {
			System.out.println(itGoods.next());
		}
				
	}

}

hashCode和equals方法的区别与联系

转:https://blog.csdn.net/lijiecao0226/article/details/24609559

先来试想一个场景,如果你想查找一个集合中是否包含某个对象,那么程序应该怎么写呢?通常的做法是逐一取出每个元素与要查找的对象一一比较,当发现两者进行equals比较结果相等时,则停止查找并返回true,否则,返回false。但是这个做法的一个缺点是当集合中的元素很多时,譬如有一万个元素,那么逐一的比较效率势必下降很快。于是有人发明了一种哈希算法来提高从该集合中查找元素的效率,这种方式将集合分成若干个存储区域(可以看成一个个桶),每个对象可以计算出一个哈希码,可以根据哈希码分组,每组分别对应某个存储区域,这样一个对象根据它的哈希码就可以分到不同的存储区域(不同的桶中)。如下图所示:

 实际的使用中,一个对象一般有key和value,可以根据key来计算它的hashCode。假设现在全部的对象都已经根据自己的hashCode值存储在不同的存储区域中了,那么现在查找某个对象(根据对象的key来查找),不需要遍历整个集合了,现在只需要计算要查找对象的key的hashCode,然后找到该hashCode对应的存储区域,在该存储区域中来查找就可以了,这样效率也就提升了很多。说了这么多相信你对hashCode的作用有了一定的了解,下面就来看看hashCode和equals的区别和联系。

       在研究这个问题之前,首先说明一下JDK对equals(Object obj)和hashCode()这两个方法的定义和规范:在Java中任何一个对象都具备equals(Object obj)和hashCode()这两个方法,因为他们是在Object类中定义的。 equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。 hashCode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。 

下面是官方文档给出的一些说明:

  1. hashCode 的常规协定是:     
  2. 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。     
  3. 如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。     
  4. 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。     
  5. 实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)     
  6.     
  7. 当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

下面是我查阅了相关资料之后对以上的说明做的归纳总结:

1.若重写了equals(Object obj)方法,则有必要重写hashCode()方法。

2.若两个对象equals(Object obj)返回true,则hashCode()有必要也返回相同的int数。

3.若两个对象equals(Object obj)返回false,则hashCode()不一定返回不同的int数。

4.若两个对象hashCode()返回相同int数,则equals(Object obj)不一定返回true。

5.若两个对象hashCode()返回不同int数,则equals(Object obj)一定返回false。

6.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。

       想要弄清楚以上六点,先要知道什么时候需要重写equals和hashCode。一般来说涉及到对象之间的比较大小就需要重写equals方法,但是为什么第一点说重写了equals就需要重写hashCode呢?实际上这只是一条规范,如果不这样做程序也可以执行,只不过会隐藏bug。一般一个类的对象如果会存储在HashTable,HashSet,HashMap等散列存储结构中,那么重写equals后最好也重写hashCode,否则会导致存储数据的不唯一性(存储了两个equals相等的数据)。而如果确定不会存储在这些散列结构中,则可以不重写hashCode。但是个人觉得还是重写比较好一点,谁能保证后期不会存储在这些结构中呢,况且重写了hashCode也不会降低性能,因为在线性结构(如ArrayList)中是不会调用hashCode,所以重写了也不要紧,也为后期的修改打了补丁。

下面来看一张对象放入散列集合的流程图:

从上面的图中可以清晰地看到在存储一个对象时,先进行hashCode值的比较,然后进行equals的比较。可能现在你已经对上面的6点归纳有了一些认识。我们还可以通过JDK中得源码来认识一下具体hashCode和equals在代码中是如何调用的。

测试一:覆盖equals(Object obj)但不覆盖hashCode(),导致数据不唯一性

public class HashCodeTest {
    public static void main(String[] args) {
        Collection set = new HashSet();
        Point p1 = new Point(1, 1);
        Point p2 = new Point(1, 1);
 
        System.out.println(p1.equals(p2));
        set.add(p1); // (1)
        set.add(p2); // (2)
        set.add(p1); // (3)
 
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            System.out.println(object);
        }
    }
}
 
class Point {
    private int x;
    private int y;
 
    public Point(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
 
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Point other = (Point) obj;
        if (x != other.x) {
            return false;
        }
        if (y != other.y) {
            return false;
        }
        return true;
    }
 
    @Override
    public String toString() {
        return "x:" + x + ",y:" + y;
    }
 
}

//结果:
true
x:1,y:1
x:1,y:1

原因分析:

(1)当执行set.add(p1)时集合为空,直接存入集合;

(2)当执行set.add(p2)时首先判断该对象(p2)的hashCode值所在的存储区域是否有相同的hashCode,因为没有覆盖hashCode方法,所以jdk使用默认Object的hashCode方法,返回内存地址转换后的整数,因为不同对象的地址值不同,所以这里不存在与p2相同hashCode值的对象,因此jdk默认不同hashCode值,equals一定返回false,所以直接存入集合。

 (3)当执行set.add(p1)时,时,因为p1已经存入集合,同一对象返回的hashCode值是一样的,继续判断equals是否返回true,因为是同一对象所以返回true。此时jdk认为该对象已经存在于集合中,所以舍弃。

测试二:覆盖hashCode方法,但不覆盖equals方法,仍然会导致数据的不唯一性

public class HashCodeTest {
    public static void main(String[] args) {
        Collection set = new HashSet();
        Point p1 = new Point(1, 1);
        Point p2 = new Point(1, 1);
 
        System.out.println(p1.equals(p2));
        set.add(p1); // (1)
        set.add(p2); // (2)
        set.add(p1); // (3)
 
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            System.out.println(object);
        }
    }
}
 
class Point {
    private int x;
    private int y;
 
    public Point(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
 
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }
 
    @Override
    public String toString() {
        return "x:" + x + ",y:" + y;
    }
 
}
//结果
false
x:1,y:1
x:1,y:1

原因分析:

(1)当执行set.add(p1)时(1),集合为空,直接存入集合;

(2)当执行set.add(p2)时(2),首先判断该对象(p2)的hashCode值所在的存储区域是否有相同的hashCode,这里覆盖了hashCode方法,p1和p2的hashCode相等,所以继续判断equals是否相等,因为这里没有覆盖equals,默认使用'=='来判断,所以这里equals返回false,jdk认为是不同的对象,所以将p2存入集合。

 (3)当执行set.add(p1)时(3),时,因为p1已经存入集合,同一对象返回的hashCode值是一样的,并且equals返回true。此时jdk认为该对象已经存在于集合中,所以舍弃。

综合上述两个测试,要想保证元素的唯一性,必须同时覆盖hashCode和equals才行。

(注意:在HashSet中插入同一个元素(hashCode和equals均相等)时,会被舍弃,而在HashMap中插入同一个Key(Value 不同)时,原来的元素会被覆盖。)

测试三:在内存泄露问题

public class HashCodeTest {
    public static void main(String[] args) {
        Collection set = new HashSet();
        Point p1 = new Point(1, 1);
        Point p2 = new Point(1, 2);
 
        set.add(p1);
        set.add(p2);
 
        p2.setX(10);
        p2.setY(10);
 
        set.remove(p2);
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();
            System.out.println(object);
        }
    }
}
 
class Point {
    private int x;
    private int y;
 
    public Point(int x, int y) {
        super();
        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;
        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;
        }
        Point other = (Point) obj;
        if (x != other.x) {
            return false;
        }
        if (y != other.y) {
            return false;
        }
        return true;
    }
 
    @Override
    public String toString() {
        return "x:" + x + ",y:" + y;
    }
 
}

x:1,y:1
x:10,y:10

原因分析:

       假设p1的hashCode为1,p2的hashCode为2,在存储时p1被分配在1号桶中,p2被分配在2号筒中。这时修改了p2中与计算hashCode有关的信息(x和y),当调用remove(Object obj)时,首先会查找该hashCode值得对象是否在集合中。假设修改后的hashCode值为10(仍存在2号桶中),这时查找结果空,jdk认为该对象不在集合中,所以不会进行删除操作。然而用户以为该对象已经被删除,导致该对象长时间不能被释放,造成内存泄露。解决该问题的办法是不要在执行期间修改与hashCode值有关的对象信息,如果非要修改,则必须先从集合中删除,更新信息后再加入集合中。

总结:

       1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。

       2.equals和hashCode需要同时覆盖。

       3.若两个对象equals返回true,则hashCode有必要也返回相同的int数。

       4.若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的对象生成不同hashCode值可以提高哈希表的性能。

       5.若两个对象hashCode返回相同int数,则equals不一定返回true。

       6.若两个对象hashCode返回不同int数,则equals一定返回false。

       7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值