一、TreeSet
- 1.TreeSet集合特點
- 可以對
Set
集合中的元素進行自然排序。往TreeSet
裏面的對象,必須具有比較性,纔可以實現排序。- 2.TreeSet集合排序實現方式
- 1)元素實現Comparable接口
- 要獲得元素的比較性,需要進行存儲的對象可以實現
Comparable
接口,並複寫compareTo()
方法,自定義比較方式;這是通過讓元素獲得比較性的方法,完成TreeSet
排序功能。- 2)集合初始化Comparator
- 當元素自身不具備比較性時,或者具備的比較性不是所需要的,這時可以讓集合調用具備比較功能的構造方法,將比較器對象作爲參數傳給
TreeSet
集合的構造方法;這是讓集合自身具備比較功能,完成TreeSet
排序。注意:
-TreeSet集合保證元素唯一新的依據是comparteTo()方法的返回值爲0;
-當元素和集合都具備比較功能時,以集合的比較器爲主
- 3.TreeSet集合運用
- 1)繼承Comparable接口的方法實現元素的可比性
- 使用
TreeSet
集合存儲自定義對象。示例代碼:
package com.heisejiuhuche.Collection;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
/*
* 聲明TreeSet集合
*/
TreeSet ts = new TreeSet();
/*
* 添加Student對象
*/
ts.add(new Student("lisi01", 11));
ts.add(new Student("lisi08", 23));
ts.add(new Student("lisi07", 19));
ts.add(new Student("lisi09", 19));
ts.add(new Student("lisi02", 225));
/* 取出所有元素並打印 */
for(Iterator it = ts.iterator(); it.hasNext(); ) {
Student stu = (Student)it.next();
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
}
class Student implements Comparable {
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
/*
* 實現comparaTo接口,使Student對象具有可比性
*/
public int compareTo(Object obj) {
if(!(obj instanceof Student)) {
throw new RuntimeException("Not Student...");
}
Student stu = (Student)obj;
if(this.age > stu.age) {
return 1;
} else if(this.age == stu.age) {
//在主要條件相同時,要比較次要條件,完成排序
//避免不同名但同年齡的對象無法儲存的現象
return this.name.compareTo(stu.name);
}
return -1;
}
}
程序輸出結果:
lisi01...11
lisi07...19
lisi09...19
lisi08...23
lisi02...225
注意:
排序時,當主要條件相同時,一定要判斷次要條件
- 2)調用TreeSet具備比較器構造方法
示例代碼:
package com.heisejiuhuche.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
/*
* 將Comparator對象牀給TreeSet構造方法,讓TreeSet具備比較功能
*/
TreeSet ts = new TreeSet(new MyComparator());
ts.add(new Student("lisi01", 11));
ts.add(new Student("lisi01", 9));
ts.add(new Student("lisi08", 23));
ts.add(new Student("lisi007", 19));
ts.add(new Student("lisi09", 19));
ts.add(new Student("lisi09", 19));
ts.add(new Student("lisi02", 225));
ts.add(new Student("lisi04", 225));
for (Iterator it = ts.iterator(); it.hasNext();) {
Student stu = (Student) it.next();
System.out.println(stu.getName() + "..." + stu.getAge());
}
}
}
class Student {
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return age;
}
}
/*
* 實現Comparator接口
*/
class MyComparator implements Comparator {
public int compare(Object o1, Object o2) {
Student stu1 = (Student) o1;
Student stu2 = (Student) o2;
int num = stu1.getName().compareTo(stu2.getName());
/*
* 如果姓名相同,比較年齡
*/
if (num == 0) {
return new Integer(stu1.getAge()).compareTo(new Integer(stu2.getAge()));
}
return num;
}
}
程序輸出結果:
lisi007...19
lisi01...9
lisi01...11
lisi02...225
lisi04...225
lisi08...23
lisi09...19
- 4.二叉樹數據結構
- 1)定義
二叉樹數據結構的原則是將小的元素依次放在左邊,大的元素依次放在右邊。在取數據時,二叉樹從最小的元素開始,依次往上取到最大值。這樣的數據結構,可以減少比較次數,提高運行效率。
- 2)二叉樹運用
- 使用二叉樹原理實現數據存儲和取出順序一致。
示例代碼:
public int compareTo(Object obj) {
return 1;
}
要使存儲和取出的順序一致,只需在複寫的compareTo()
方法中,return 1;
即可;存儲與取出成倒序,只需return -1;
即可
- 5.TreeSet練習
- 1)按照字符串的長度排序
示例代碼:
package com.heisejiuhuche.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new StrLenComparator());
ts.add("abc");
ts.add("z");
ts.add("addbc");
ts.add("aaa");
ts.add("abdfsc");
ts.add("abcfsa3r");
for(Iterator it = ts.iterator(); it.hasNext(); ) {
String str = (String)it.next();
System.out.println(str);
}
}
}
class StrLenComparator implements Comparator {
public int compare(Object o1, Object o2) {
String str1 = (String)o1;
String str2 = (String)o2;
/*
* 比較字符串的長度
*/
int num = new Integer(str1.length()).compareTo(new Integer(str2.length()));
/*
* 如果字符串長度相等,比較字符串自然順序
*/
if(num == 0) {
return str1.compareTo(str2);
}
return num;
}
}
程序輸出結果:
z
aaa
abc
addbc
abdfsc
abcfsa3r
二、泛型
- 1.概述
由一個小例子引出泛型:
package com.heisejiuhuche.Collection;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericDemo {
public static void main(String[] args) {
ArrayList arr = new ArrayList();
/*
* 添加字符串
*/
arr.add("asdf");
arr.add("adfsdf");
arr.add("asdfgsf");
arr.add("as346ndfdf");
/*
* 添加整型數據4
*/
arr.add(4);
for(Iterator it = arr.iterator(); it.hasNext(); ) {
String str = (String)it.next();
/*
* 輸出字符串的長度
*/
System.out.println(str.length());
}
}
}
如果沒有泛型的支持,後添加的整型數據4
,在運行時會出現運行時期類型轉換異常,int
類型無法被轉換爲String
類型,但是這個異常在編譯時期,沒有任何提示。爲了避免這樣的情況,需要程序在編譯時期就給出異常,以便開發者解決問題,Java引入了泛型機制。
JDK5.0版本之後的新特性,用於解決集合存儲的安全問題。
泛型格式(以儲存
String
類型數據爲例):ArrayList<String> arrayList = new ArrayList();
聲明一個ArrayList容器,存儲String類型的元素。這樣,上述程序在編譯時期就會報出異常。
容器聲明加上了泛型,那麼迭代器的聲明也應加上泛型:Iterator<String> it = arrayList.iterator();
- 2.泛型的優點
- 1)將運行時期出現的
ClassCastException
轉移到編譯時期,方便開發者解決問題,更安全; 2)避免了迭代時期類型強制轉換的麻煩;
3)泛型類的出現優化了程序設計
- 3.泛型的應用
- 當在聲明容器的時候指定了泛型,後期實現
Comparator
接口和Comparable
接口的時候,可以指定Comparator
接口的泛型;這樣做,避免了比較時的類型轉換。Comparator接口泛型示例代碼:
/*
* 加上了泛型的Comparator接口
*/
class MyComparator implements Comparator<Student> {
public int compare(Student o1, Student o2) {
/*
* 不需要做類型轉換
*/
int num = o1.getName().compareTo(o2.getName());
/*
* 如果姓名相同,比較年齡
*/
if (num == 0) {
return new Integer(o1.getAge()).compareTo(new Integer(o2
.getAge()));
}
return num;
}
}
Comparable接口泛型示例代碼:
/*
* 加上了泛型的Comparable接口
*/
class Student implements Comparable<Student> {
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int compareTo(Student obj) {
/*
* 無須類型轉換
*/
if(this.age > obj.age) {
return 1;
} else if(this.age == obj.age) {
return this.name.compareTo(obj.name);
}
return -1;
}
}
注意:
複寫equals()方法的時候,傳的參數必須是Object obj;因爲Object類沒有泛型
- 4.泛型類
- 1)定義
- 泛型類是在一個類要操作對象,而對象類型又不明確時出現的。
- 2)泛型類格式
- 聲明泛型類,只需要在類名後加上
<T>
即可:class GenericClass<T>
- 3)泛型類應用
- 當一個類中要操作的引用數據類型不確定的時候,早期定義
Object
來完成擴展,現在定義泛型來完成擴展。例如,當一個工具類中要操作不同的對象Worker
和Student
時,早期通過接收Object
對象,然後通過類型轉換類完成操作;現在只需定義泛型,無需類型轉換。早期實現:
package com.heisejiuhuche.Collection;
public class GenericClassDemo {
public static void main(String[] args) {
Utils u = new Utils();
u.setObjcet(new Worker());
/*
* 需要類型轉換來完成操作
*/
Worker w = (Worker)u.getObject();
}
}
class Worker {}
class Student {}
class Utils {
private Object obj;
/*
* 接收Object爲參數
*/
public void setObjcet(Object obj) {
this.obj = obj;
}
public Object getObject() {
return obj;
}
}
如果現在要操作的是Worker
對象,而在setObject()
方法中誤傳入了Student
對象,編譯不會報錯,但是運行時會出現類型轉換異常。
泛型實現:
package com.heisejiuhuche.Collection;
public class GenericClassDemo {
public static void main(String[] args) {
Utils<Worker> u = new Utils<Worker>();
u.setObjcet(new Worker());
/*
* 不需要類型轉換來完成操作
*/
Worker w = u.getObject();
}
}
class Worker {}
class Student1 {}
class Utils<T> {
private T t;
/*
* 接收泛型T作爲參數
*/
public void setObjcet(T t) {
this.t = t;
}
public T getObject() {
return t;
}
}
如果現在要操作的是Worker
對象,而在setObject()
方法中誤傳入了Student
對象,編譯無法通過;並且泛型實現無須進行類型轉換,既簡化了代碼,又提升了安全性。
- 5.泛型方法
- 1)定義
- 泛型類在使用的過程中有其侷限性。例如一個泛型類被定義了只能操作
String
類型的對象,那麼該類中需要接收參數的方法,都只能操作String
對象;此時如果給該類中的方法傳遞了非String
類型數據,編譯就會出錯。爲了程序更加靈活,現在想實現一個類中不同的方法操作不同類型的對象,而要操作的對象不能確定,那麼就可以使用泛型方法。- 2)泛型方法格式
- 要聲明泛型方法,只需在方法修飾符後面,返回值的前面加上
<T>
即可: private <T> void genericMethod() {}
- 3)泛型方法應用
定義一個類,類中的兩個輸出方法可以輸出指定類型的對象。
示例代碼:
package com.heisejiuhuche.Collection;
public class GenericMethodDemo {
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
//打印字符串類型
gm.show("haha");
//打印Integer類型
gm.show(new Integer(3));
gm.print("heihei");
}
}
class GenericMethod {
/*
* 泛型方法show()
*/
public <T> void show(T t) {
System.out.println("show: " + t);
}
/*
* 泛型方法print()
*/
public <T> void print(T t) {
System.out.println("print: " + t);
}
}
程序輸出結果:
show: haha
show: 3
print: heihei
高能:
-可以在泛型類中定義泛型方法,互不影響;
-靜態方法不可以訪問類上定義的泛型;如果靜態方法操作的引用數據類型不確定,可以將其定義爲泛型方法
public static <T> void method() {}
三、泛型限定
- 1.“?”通配符
“?”
是一個通配符,也可以理解爲佔位符。在泛型的使用中,當無法確定接收對象是什麼類型的時候,先用“?”
佔位。例如,有存放Student
對象和Person
對象的兩個ArrayList
,定義一個方法,可以遍歷打印這兩個集合。代碼示例:
package com.heisejiuhuche.Collection;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericDemo3 {
public static void main(String[] args) {
ArrayList<Programmer> arr1 = new ArrayList<Programmer>();
ArrayList<Manager> arr2 = new ArrayList<Manager>();
arr1.add(new Programmer("aaa1"));
arr1.add(new Programmer("aaa2"));
arr1.add(new Programmer("aaa3"));
arr2.add(new Manager("bbb1"));
arr2.add(new Manager("bbb2"));
arr2.add(new Manager("bbb3"));
printArr(arr1);
printArr(arr2);
}
/* 用通配符 ? 接收任意集合並打印 */
private static void printArr(ArrayList<?> arrayList) {
for(Iterator<?> it = arrayList.iterator(); it.hasNext(); ) {
System.out.println(it.next().toString());
}
}
}
class Programmer {
private String name;
Programmer(String name) {
this.name = name;
}
/*
* 複寫toString()方法,輸出名字
*/
public String toString() {
return this.name;
}
}
class Manager {
private String name;
Manager(String name) {
this.name = name;
}
/*
* 複寫toString()方法,輸出名字
*/
public String toString() {
return this.name;
}
}
程序輸出結果:
aaa1
aaa2
aaa3
bbb1
bbb2
bbb3
- 2.泛型的限定:
- 1)? extends E:可以接收E類型或者E類型的子類型;限定了上限;
示例代碼:
package com.heisejiuhuche.Collection;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericDemo4 {
public static void main(String[] args) {
ArrayList<SalesManager> arr1 = new ArrayList<SalesManager>();
ArrayList<Salesman> arr2 = new ArrayList<Salesman>();
arr1.add(new SalesManager("kengdie09"));
arr1.add(new SalesManager("kengdie02"));
arr1.add(new SalesManager("kengdie06"));
arr2.add(new Salesman("kengdie04"));
arr2.add(new Salesman("kengdie08"));
arr2.add(new Salesman("kengdie10"));
printArr(arr1);
printArr(arr2);
}
/*
* 泛型限定,只爲Salesman和Salesman的子類提供打印服務
*/
private static void printArr(ArrayList<? extends Salesman> arr) {
for(Iterator<? extends Salesman> it = arr.iterator(); it.hasNext(); ) {
System.out.println(it.next().getName());
}
}
}
class Salesman {
private String name;
Salesman(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class SalesManager extends Salesman {
private String name;
SalesManager(String name) {
super(name);
}
}
程序輸出結果:
kengdie09
kengdie02
kengdie06
kengdie04
kengdie08
kengdie10
上述程序,可以在打印方法中使用“?”
通配符,但是如果需求是,要打印一個範圍內(Salesman
及Salesman
的子類)對象,那麼就使用“? extends E”
泛型限定。
- 2)? super E:可以接收E類型或者E類型的付類型;限定了下限;
示例代碼:
package com.heisejiuhuche.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class GenericDemo4 {
public static void main(String[] args) {
TreeSet<SalesManager> ts1 = new TreeSet<SalesManager>(new MyComp());
TreeSet<SalesAssist> ts2 = new TreeSet<SalesAssist>(new MyComp());
ts1.add(new SalesManager("kengdie09"));
ts1.add(new SalesManager("kengdie02"));
ts1.add(new SalesManager("kengdie06"));
ts2.add(new SalesAssist("kengdie04"));
ts2.add(new SalesAssist("kengdie08"));
ts2.add(new SalesAssist("kengdie10"));
printTs(ts1);
printTs(ts2);
}
/*
* 使用泛型限定打印Salesman及Salesman子類對象
*/
private static void printTs(TreeSet<? extends Salesman> ts) {
for(Iterator<? extends Salesman> it = ts.iterator(); it.hasNext(); ) {
System.out.println(it.next().getName());
}
}
}
/*
* 使用泛型限定,此比較器可以比較Salesman及其子類
* 也就是說,在Comparator<>的尖括號內限定父類,那麼
* 該比較器就可以比較父類,及其子類,無須定義多個比較器
*/
class MyComp implements Comparator<Salesman> {
public int compare(Salesman s1, Salesman s2) {
return s1.getName().compareTo(s2.getName());
}
}
class Salesman {
private String name;
Salesman(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class SalesAssist extends Salesman {
private String name;
SalesAssist(String name) {
super(name);
}
}
class SalesManager extends Salesman {
private String name;
SalesManager(String name) {
super(name);
}
}
程序輸出結果:
kengdie02
kengdie06
kengdie09
kengdie04
kengdie08
kengdie10
泛型限定,用於泛型擴展,讓程序更加靈活。