Set
Set:无序,不可以重复元素。
|--------HashSet:数据结构是哈希表。
线程是非同步的。保证元素唯一性的原理是:判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals方法,是否为true
|--------TreeSet:可以对Set集合中元素进行排序。
底层数据结构是二叉树(也叫红黑树),保证元素唯一性的依据是:compareTo()方法return 0。
TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo()方法。这种方式也称为元素的自然顺序,或者也叫默认顺序。
TreeSet排序的第二种方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这是就需要让集合自身具备比较性。在集合一初始化时,就具备比较方式。
例,需求:往TreeSet集合中存储自定义对象学生。想按照学生的年龄进行排序。
int compareTo(T o):比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
代码如下:
import java.util.Iterator; import java.util.TreeSet; public class TreeSetDemo { public static void sop(Object obj) { System.out.println(obj); } public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Student("lisi02", 22)); ts.add(new Student("lisi007", 20)); ts.add(new Student("lisi09", 19)); ts.add(new Student("lisi08", 19)); //ts.add(new Student("lisi02", 22)); Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); sop(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 int compareTo(Object obj) { //return 0; if(!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); Student s = (Student)obj; System.out.println(this.name+"....compareTo...."+s.name); if(this.age > s.age) return 1; if(this.age == s.age) return this.name.compareTo(s.name); return -1; } public String getName() { return name; } public int getAge() { return age; } }
记住,排序时,当主要条件相同时,一定判断一下次要条件。
当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让容器自身具备比较性。定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。定义一个类实现Comparator接口,覆盖compare()方法。
当两种排序都存在时,以比较器为主。
int compare(T o1, T o2):比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。
示例代码如下:
import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; public class TreeSetDemo1 { public static void sop(Object obj) { System.out.println(obj); } public static void main(String[] args) { TreeSet ts = new TreeSet(new MyCompare()); ts.add(new Student1("lisi02", 22)); ts.add(new Student1("lisi007", 20)); ts.add(new Student1("lisi09", 19)); ts.add(new Student1("lisi06", 18)); ts.add(new Student1("lisi007", 29)); ts.add(new Student1("lisi06", 18)); //ts.add(new Student("lisi02", 22)); Iterator it = ts.iterator(); while(it.hasNext()) { Student1 stu = (Student1)it.next(); sop(stu.getName()+"...."+stu.getAge()); } } } class MyCompare implements Comparator { @Override public int compare(Object o1, Object o2) { Student1 s1 = (Student1)o1; Student1 s2 = (Student1)o2; int num = s1.getName().compareTo(s2.getName()); if(num == 0) { /* if(s1.getAge() > s2.getAge()) { return 1; } if(s1.getAge() == s2.getAge()) { return 0; } return -1; */ return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); } return num; } } class Student1 implements Comparable {//该接口强制让学生具备比较性 private String name; private int age; Student1(String name, int age) { this.name = name; this.age = age; } public int compareTo(Object obj) { //return 0; if(!(obj instanceof Student1)) throw new RuntimeException("不是学生对象"); Student1 s = (Student1)obj; System.out.println(this.name+"....compareTo...."+s.name); if(this.age > s.age) return 1; if(this.age == s.age) return this.name.compareTo(s.name); return -1; } public String getName() { return name; } public int getAge() { return age; } }
练习:按照字符串长度排序。
分析:字符串本身具备比较性,但是它的比较方式不是所需要的,这时就只能使用比较器。
示例代码如下:
import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; class StringLengthComparator implements Comparator { @Override public int compare(Object o1, Object o2) { String s1 = (String) o1; String s2 = (String) o2; /* if(s1.length() > s2.length()) { return 1; } if(s1.length() == s2.length()) { return 0; } */ int num = new Integer(s1.length()).compareTo(new Integer(s2.length())); if(num == 0) { return s1.compareTo(s2); //如果两个字符串的长度相同,再按他俩的字典顺序排序。 } return num; } } public class TreeSetTest { public static void main(String[] args) { TreeSet ts = new TreeSet(new StringLengthComparator()); ts.add("abcd"); ts.add("cc"); ts.add("cba"); ts.add("aaa"); ts.add("z"); ts.add("hahaha"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } }
泛型
泛型:JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。
泛型的好处:
- 将运行时期出现的问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时期问题减少,安全。
- 避免了强制转换的麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
问:在使用java提供的对象时,什么时候写泛型呢?
答:通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的。当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
示例代码如下:
import java.util.ArrayList; import java.util.Iterator; public class GenericDemo { public static void main(String[] args) { ArrayList<String> al = new ArrayList<String>(); al.add("abc01"); al.add("abc0991"); al.add("abc014"); //al.add(4);//al.add(new Integer(4)); Iterator<String> it = al.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s + ":" + s.length()); } } }
练习:按照字符串长度排序。
代码:
import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; class LenComparator implements Comparator<String> { @Override public int compare(String arg0, String arg1) { int num = new Integer(arg0.length()).compareTo(new Integer(arg1.length())); if(num == 0) return arg0.compareTo(arg1);//如果两个字符串的长度相同,再按他俩的字典顺序排序。 return num; } } public class GenericDemo1 { public static void main(String[] args) { TreeSet<String> ts = new TreeSet<String>(new LenComparator()); ts.add("abcd"); ts.add("cc"); ts.add("cba"); ts.add("aaa"); ts.add("z"); ts.add("hahaha"); Iterator<String> it = ts.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); } } }
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。现在定义泛型来完成扩展。
如:
class Worker { } class Stud { } //泛型前做法 class Tool { private Object object; public void setObject(Object object) { this.object = object; } public Object getObject() { return object; } } //什么时候定义泛型类? //当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。 //现在定义泛型来完成扩展。 class Utils<QQ> { private QQ q; public void setObject(QQ q) { this.q = q; } public QQ getObject() { return q; } } public class GenericDemo2 { public static void main(String[] args) { Utils<Worker> u = new Utils<Worker>(); u.setObject(new Worker()); Worker w = u.getObject(); /* Tool t = new Tool(); t.setObject(new Stud()); Worker w = (Worker)t.getObject(); */ } }
泛型方法
泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
特殊之处:静态方法不可以访问类上定义的泛型。
如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。
示例代码:
/* class DemoG<T> { public void show(T t) { System.out.println("show:" + t); } public void print(T t) { System.out.println("print:" + t); } } */ //泛型类定义的泛型,在整个类中有效。如果被方法使用, //那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。 //为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。 /* 特殊之处:静态方法不可以访问类上定义的泛型。 如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。 */ class DemoG<T> { public void show(T t) { System.out.println("show:" + t); } //泛型方法 public <Q> void print(Q q) { System.out.println("print:" + q); } //静态泛型方法 public static <W> void method(W t) { System.out.println("method:" + t); } } public class GenericDemo3 { public static void main(String[] args) { DemoG<String> d1 = new DemoG<String>(); d1.show("haha"); //d1.show(4); d1.print(4); d1.print("hello"); DemoG.method("hahahha"); /* DemoG d = new DemoG(); d.show("haha"); d.show(new Integer(4)); d.print("heihei"); */ /* DemoG<Integer> d = new DemoG<Integer>(); d.show(new Integer(4)); d.print("haha"); DemoG<String> d1 = new DemoG<String>(); d1.print("haha"); d1.show(5); */ } }
泛型接口
示例代码:
//泛型定义在接口上 interface Inter<T> { void show(T t); } /* 泛型接口的第一种实现方式: class InterImpl implements Inter<String> { public void show(String t) { System.out.println("show:" + t); } } */ /* 泛型接口的第二种实现方式: */ class InterImpl<T> implements Inter<T> { @Override public void show(T t) { System.out.println("show:" + t); } } public class GenericDemo4 { public static void main(String[] args) { InterImpl<Integer> i = new InterImpl<Integer>(); i.show(4); //InterImpl i = new InterImpl(); //i.show("haha"); } }
泛型的限定
?:通配符,也可以理解为占位符。
泛型的限定:
- ? extends E:可以接收E类型或者E类型的子类型,上限。
- ? super E:可以接收E类型或者E的父类型,下限。
示例代码如下:
import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; class PersonG { private String name; public PersonG(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class StudentG extends PersonG { public StudentG(String name) { super(name); } } public class GenericDemo5 { public static void main(String[] args) { /* ArrayList<String> al = new ArrayList<String>(); al.add("abc1"); al.add("abc2"); al.add("abc3"); ArrayList<Integer> al1 = new ArrayList<Integer>(); al1.add(4); al1.add(7); al1.add(1); printColl(al); printColl(al1); */ ArrayList<PersonG> al = new ArrayList<PersonG>(); al.add(new PersonG("abc1")); al.add(new PersonG("abc2")); al.add(new PersonG("abc3")); //printColl(al); ArrayList<StudentG> al1 = new ArrayList<StudentG>(); al1.add(new StudentG("abc---1")); al1.add(new StudentG("abc---2")); al1.add(new StudentG("abc---3")); printColl(al1);// ArrayList<PersonG> al = new ArrayList<StudentG>();error----泛型中无法向上转型 } public static void printColl(ArrayList<? extends PersonG> al) {//ArrayList<String> al = new ArrayList<Integer>(); error Iterator<? extends PersonG> it = al.iterator(); while(it.hasNext()) { System.out.println(it.next().getName()); } } /* public static <T> void printColl_1(ArrayList<T> al) {//ArrayList<String> al = new ArrayList<Integer>(); error Iterator<T> it = al.iterator(); while(it.hasNext()) { T t = it.next();//可以接收T类型并操作 System.out.println(t); } } public static void printColl(ArrayList<?> al) {//ArrayList<String> al = new ArrayList<Integer>(); error Iterator<?> it = al.iterator(); while(it.hasNext()) { System.out.println(it.next()); //System.out.println(it.next().length());//不能使用类型特有方法:length() } } */ }
现在重点讲解泛型的下限。通过如下代码示例说之:
泛型的下限的应用举例:
TreeSet(Comparator<? super E> comparator)
//伪代码:class PersonG { private String name; public PersonG(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class StudentG extends PersonG { public StudentG(String name) { super(name); } } class StudentG implements Comparable<PersonG> {//<? super E> @Override public int compareTo(PersonG arg0) { return 0; } } class Comp implements Comparator<PersonG> {//可以接收StudentG,也可以接收StudentG的父类型PersonG @Override public int compare(PersonG arg0, PersonG arg1) { PersonG arg0 = new StudentG("abc---1"); return arg0.getName().compareTo(arg1.getName()); } } TreeSet<StudentG> ts = new TreeSet<StudentG>(new Comp()); ts.add(new StudentG("abc---1")); ts.add(new StudentG("abc---2")); ts.add(new StudentG("abc---3"));
现示例说明:
import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; class PersonGe { private String name; public PersonGe(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class StudentGe extends PersonGe { public StudentGe(String name) { super(name); } } class WorkerGe extends PersonGe { public WorkerGe(String name) { super(name); } } /* class StuComp implements Comparator<StudentGe> { @Override public int compare(StudentGe s1, StudentGe s2) { return s1.getName().compareTo(s2.getName()); } } class WorkerComp implements Comparator<WorkerGe> { @Override public int compare(WorkerGe s1, WorkerGe s2) { return s1.getName().compareTo(s2.getName()); } } */ class Comp implements Comparator<PersonGe> { @Override public int compare(PersonGe p1, PersonGe p2) { return p2.getName().compareTo(p1.getName());//局限性:只能用父类型的方法 } } public class GenericDemo6 { public static void main(String[] args) { TreeSet<StudentGe> ts = new TreeSet<StudentGe>(new Comp()); ts.add(new StudentGe("abc03")); ts.add(new StudentGe("abc02")); ts.add(new StudentGe("abc06")); ts.add(new StudentGe("abc01")); Iterator<StudentGe> it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next().getName()); } TreeSet<WorkerGe> ts1 = new TreeSet<WorkerGe>(new Comp()); ts1.add(new WorkerGe("wabc--03")); ts1.add(new WorkerGe("wabc--02")); ts1.add(new WorkerGe("wabc--06")); ts1.add(new WorkerGe("wabc--01")); Iterator<WorkerGe> it1 = ts1.iterator(); while(it1.hasNext()) { System.out.println(it1.next().getName()); } } }