Java集合框架(2)

|--Set:元素是无序(存入和取出的顺序不一定一致)的,元素不可以重复

 |--HashSet:底层数据结构是哈希表,线程是非同步的。

 |--TreeSet:底层数据结构是二叉树。保证元素唯一性的依据compareTo()方法返回0;会自动对存入Set集合中的元素进行排序(自然排序)。

 

(1)Set集合的功能和Collection一致的,没有特有的方法。

(2)HashSet是如何保证元素唯一性的呢?是通过集合元素的两个方法,hashCode()和equals()。如果元素的哈希值相同,才会判断equals()是否为true。如果元素的哈希值不同,不会调用equals()方法。所以我们要根据特定条件来表示哈希值,从而覆写hashCode()方法。HashSet判断元素是否存在(contains())和删除(remove())的依据:也是通过集合元素的两个方法,hashCode()和equals()。这和ArrayList不一样,ArrayList只依赖equals()方法,这种区别跟底层的数据结构有关系。

(3)TreeSet排序的第一种排序方式:让元素自身具有比较性,元素需要实现Comparable接口,覆盖compareTo()方法,这种方式也叫做元素的自然顺序,即默认顺序。

        TreeSet排序的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是开发所需要的。这时就需要让集合自身具备比较性。在集合初始化时,就有了比较方式。我们可以定义了一个比较器,将比较器对象作为参数传递给TreeSet的构造函数。

        如果以上两种排序都存在时,以比较器(定义一个类,实现Comparator<T>接口,覆盖compare()方法)为主。

 

/* 需求:往TreeSet集合中存储自定义对象学生。想按照学生的年龄进行排序 
只要学生类实现接口 java.lang.Comparable<T>:此接口 强行对实现它的每个类的对象进行整体排序。 这种排序被称为类的自然排序 ,该接口强制让实现它的类具有比较性,该接口只有一个方法:int compareTo(T o) 排序时,当主要条件相同时,一定要判断一下次要条件。否则会出现一样的数据 */

/* TreeSet练习:按照字符串长度排序
字符串本身具有比较性,但是它的比较方式不是所需要的
这时候就需要定义一个比较器 */

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
    	TreeSet<String> mTreeSet = new TreeSet<String>(new StrlengthComparator());
    	mTreeSet.add("aaa");
    	mTreeSet.add("aaacd");
    	mTreeSet.add("abc");
    	mTreeSet.add("adddddd");
    	mTreeSet.add("adddddddd");
    	
    	for (String string: mTreeSet) {
    		System.out.println(string);
    	}
	}
}
// 如果主要条件相同,需要判断次要条件
class StrlengthComparator implements Comparator<String> {
    public int compare(String s1, String s2) {
	    // 将s1和s2互换位置时,可实现倒序(相对而言)排序
	    int result = new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if (result == 0) {
		    return s1.compareTo(s2);
		}		
		return result;
	}
}

 

 

/* 泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。
	优点:1.将运行时期出现问题ClassCastException,转移到了编译时期,方便程序员解决问题,让运行时期问题减少。2.避免了强制转换的麻烦。	
	当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。	
	泛型类。什么时候定义泛型类,当类中要操作的引用类型不确定的时候,早期定义Object来完成扩展。现在用泛型来完成扩展。
	泛型方法。泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
	为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。
	访问限定符 <T> 返回类型 方法名(T t)
	泛型静态方法。静态方法不可以访问类上定义的泛型。如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。*/
	
	//泛型接口:
	interface Inter<T> {
	    void show(T t);
	}
	
	class InterImpl1 implements Inter<String> {
	    public void show(String s) {
		    System.out.println("show: " + s);
		}
	}
	
	class InterImpl2<T> implements Inter<T> {
	    public void show(T t) {
		  //对t进行操作
		}
	}
	
/*泛型限定:?,通配符,也可以理解为占位符。 
<?>:可以接收任意类型 
<? extends E>:可以接收E类型或者E的子类型,限定了上限。
<? super E>:可以接收E类型或者E的父类型,限定了下限。*/  

你可能感兴趣的:(java,generics,set)