集合类下


1、Set接口

       Set 接口继承 Collection 接口,而且它不允许集合中存在重复项,每个具体的 Set 实现类依赖添加的对象的equals()方法来检查独一性。Set接口没有引入新方法,所以Set就是一个Collection,只不过其行为不同。

    简洁的说:Set集合的特点为无序并且不能重复。即无序性和唯一性


其中Set有两个常见的实现子类: HashSet 和   TreeSet

其中: HashSet底层的数据结构哈希表

           TreeSet底层的数据结构二叉树

【1】我拿HashSet来证明Set的 无序性和唯一性
(1)无序性和唯一性
public class HashSetDemo {

	public static void main(String[] args) {

		Set<String> hashSet = new HashSet<String>();

		System.out.println(hashSet.add("java1"));
		System.out.println(hashSet.add("java2"));
		System.out.println(hashSet.add("java3"));
		System.out.println(hashSet.add("java1"));

		System.out.println("最后结果:");
		System.out.println(hashSet);

	}

}
输出结果:

分析:当运行System.out.println("java1-" + hashSet.add("java1"));时,即hashSet向集合添加相同元素时,hashSet会调用String的equals方法判定结果是这两个对象的内容一样,不会向集合添加元素,所以它返回的值回事false。
【总结】由上面的代码例子,准确的反映了Set的无序性和唯一性。
下面我来详细说明HashSet是如何保证元素的唯一性重点
  HashSet在存储元素的时候,是查看两个对象的哈希值是否一样的,查看两个对象的内容是否一样
 仔细的说就是:
  1、通过重写自定义类hashCode()equals( )两个方法来达到元素的唯一性保证。
 2、当hashCode()值相同,才会调用equals( )方法;hashCode()值不会调用equals( )方法
 下面我举例子来说明上述结论:
示例代码:[1]Student(没有重写equals方法和HashCode()方法
public class Student {
	private String name;// 名字
	private int score;// 分数
	public Student(String name, int score) {
		this.name = name;
		this.score = score;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", score=" + score + "]";
	}
}
向HashSet集合添加元素:
public class HashSetDemo2 {

	public static void main(String[] args) {

		Set<Student> hashSet = new HashSet<Student>();

		hashSet.add(new Student("lisi", 20));
		hashSet.add(new Student("wangwu", 25));
		hashSet.add(new Student("lisi", 20));
		hashSet.add(new Student("xss", 24));

		Iterator<Student> it = hashSet.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
输出结果:

[2]为Student 重写equals()方法 判定两个对象的内容是否一致
@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (score != other.score)
			return false;
		return true;
	}
注意:重写equals方法时public boolean equals(Object obj) 中括号内只能为Object obj,不能为自定义对象,否则不能对equals进行重写。
输出结果:

[2]为Student类重写hashCode()方法,使得它们的哈希值相同
@Override
	public int hashCode() {
		return 11;
	}
输出结果:

注意:之前我一直疑惑的一个地方,先上代码:
public static void main(String[] args) {

		Set<String> hashSet = new HashSet<String>();

		hashSet.add(new String("lisi"));
		hashSet.add(new String("wangwu"));
		hashSet.add(new String("lisi"));
		hashSet.add(new String("xss"));

		Iterator<String> it = hashSet.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
输出结果:
wangwu
lisi
xss

疑惑:两个new String("lisi")不是对象么?他们的hashCode不是应该不一样么,就不会比较equals了啊?输出的应该是添加的四个,为什么是三个?
分析:查看String的hashCode方法的源码
public int hashCode() {
	int h = hash;
	if (h == 0) {
	    int off = offset;
	    char val[] = value;
	    int len = count;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }
其中h = 31*h + val[off++]可以看出,它们比较不是地址值两者的值是相等的,会得到一样的结果,因此哈希值也就相同了。
结论:
HashSet判断删除添加元素等操作依据的是被操作元素所在的类的hashCode()equals( )这两个方法。
【2】TreeSet
TreeSet的优点:可以对元素进行排序
TreeSet添加元素时应该注意:TreeSet本身能够进行排序,而如果自己定义的类没有给出排序的规则,会报错。

如何使TreeSet添加的元素具有比较性,我们通过为需要排序的类实现Comparable或者Comparator接口来实现。
只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序
 Comparable 接口只提供了int   compareTo(T   o)方法,当实现Comparable接口的类的对象小于等于或者大于指定对象,就返回一个负数0或者一个正数。
Comparator定义了俩个方法,分别是int   compare(T   o1,   T   o2)和   boolean   equals(Object   obj),用于比较两个Comparator是否相等。
有时在实现Comparator接口时,并没有实现equals方法,可程序并没有报错,原因是实现该接口的类也是Object类的子类,而Object类已经实现了equals方法。
(1)Student类实现Comparable接口
public class Student implements Comparable<Student> {

	private String name;// 名字
	private int score;// 分数

	public Student(String name, int score) {
		this.name = name;
		this.score = score;
	}

	public String getName() {
		return name;
	}

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

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", score=" + score + "]";
	}
	@Override
	public int compareTo(Student o) {
		// TODO Auto-generated method stub
		if (this.score > o.score)
			return 1;
		else if (this.score == o.score)
			return this.name.compareTo(o.name);
		return -1;
	}
}
public class TreeSetDemo {

	public static void main(String[] args) {

		Set<Student> set = new TreeSet<Student>();

		set.add(new Student("lisi", 80));

		set.add(new Student("lisi33", 68));

		set.add(new Student("wangwu", 95));

		Iterator<Student> it = set.iterator();

		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
输出结果:
Student [name=lisi33, score=68]
Student [name=lisi, score=80]
Student [name=wangwu, score=95]

(2) 实现Comparator接口
public class TreeSetDemo {

	public static void main(String[] args) {

		Set<Student> set = new TreeSet<Student>(new MyComparator());

		set.add(new Student("lisi", 80));

		set.add(new Student("lisi33", 68));

		set.add(new Student("wangwu", 80));

		Iterator<Student> it = set.iterator();

		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
class MyComparator implements Comparator<Student> {
	@Override
	public int compare(Student o1, Student o2) {
		// TODO Auto-generated method stub
		if (o1.getScore() > o2.getScore())
			return 1;
		else if (o1.getScore() == o2.getScore())
			return o1.getName().compareTo(o2.getName());
		return -1;
	}
}
其中:this.name.compareTo(o.name);与o1.getName().compareTo(o2.getName());最主要用于当比较分数相同时,如果直接返回0,则不会显示数据,这显然是不合理的,所有才要继续比较名字是否相同。
Comparator和Comparable总结:

相同点:

    1、二者都可以实现对象的排序,不论用Arrays的方法还是用Collections的sort()方法。

不同点:

    1、实现Comparable接口的类,似乎是预先知道该类将要进行排序,需要排序的类实现Comparable接口,是一种“静态绑定排序”。

    2、实现Comparator的类不需要,设计者无需事先为需要排序的类实现任何接口

    3、Comparator接口里有两个抽象方法compare()和equals(),而Comparable接口里只有一个方法:compareTo()

    4、Comparator接口无需改变排序类的内部,也就是说实现算法和数据分离,是一个良好的设计,是一种“动态绑定排序”

    5、Comparator接口可以使用多种排序标准,比如升序、降序等。

1、Map接口

Map接口不是Collection接口的继承。Map接口用于维护键/值对(key/value pairs)。该接口描述了从不重复的键到值的映射


 Map有三个常见的实现子类: HashMap,  HashTable 和TreeMap

  HashMap和HashTable底层的数据结构哈希表

 其中:HashMap线程不同步,效率高,不安全;可以存入nullkeynullvalue

      HashTable线程同步,效率低,安全;不可以存入nullkeynullvalue

  TreeMap底层的数据结构二叉树(可对map中的key进行排序,跟TreeSet类似)

(1)HashMap

HashMap添加数据:

public class HashMapDemo {

	public static void main(String[] args) {

		Map<String, String> map = new HashMap<String, String>();

		System.out.println(map.put("01", "lisi"));
		System.out.println(map.put("01", "lisi2"));
		System.out.println(map.put("02", "wangwu"));
		System.out.println(map.put("02", "wangwu2"));
		System.out.println(map.put("03", "xss"));

		System.out.println(map);
	}
}
输出结果:

(2)获取Map中的key_value方式

     List,Set通过迭代器对元素进行遍历,而Map本身没有迭代器。它是通过将Map集合转换成Set集合,通过SetIterator对Set进行迭代,从而获取key和value。

【1】通过KeySet获取

Map<String, String> map = new HashMap<String, String>();
		map.put("01", "lisi");
		map.put("02", "wangwu");
		map.put("03", "xss");

		Iterator<String> it = map.keySet().iterator();

		while (it.hasNext()) {
			String key = it.next();
			System.out.println(key + "..." + map.get(key));
		}
【2】通过 entrySet获取

Map<String, String> map = new HashMap<String, String>();
		map.put("01", "lisi");
		map.put("02", "wangwu");
		map.put("03", "xss");

		Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();

		while (it.hasNext()) {
			Map.Entry<String, String> entry = it.next();
			System.out.println(entry.getKey() + "..." + entry.getValue());
		}

其中keySet()方法返回值是Map中key值的集合entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry

Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。

打个比方说明keySet()与entrySet()区别:有很多对夫妻。一种方式是先取得(遍历得到)所有丈夫,然后便知道了所有妻子。一种方式就是直接取得(遍历得到)所有的结婚证。直接读结婚证夫是谁,妻是谁。




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值