一、Collection常用的方法:
Java 集合可分为 Set、List 和 Map 三种体系:
Set:无序、不可重复的集合。
List:有序,可重复的集合。
Map:具有映射关系的集合。
Collection 接口是 List、Set 和 Queue 接口的父接口,
该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合:
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class TestCollections { public static void main(String[] args) { //1. 创建一个 Collection 接口的对象. Collection collection = new ArrayList(); //2. Collection 重要方法说明: /** * 2.1 用于添加元素的: * add() * addAll() */ Person p1 = new Person(); collection.add(p1); collection.add(new Person()); Collection collection2 = new ArrayList(); collection2.add(new Person()); collection2.add(new Person()); collection.addAll(collection2); System.out.println(collection.size()); /** * 2.2 用于访问集合的方法: * 获取集合的长度: size() * 对集合进行遍历的方法: iterator() 可以得到对应的 Iterator 接口对象. * * Iterator: 迭代器 * ①. 获取 Iterator 接口对象: * ②. 使用 while 循环和 Iterator 对象遍历集合中的每一个元素. 具体使用 Iterator 接口的 * hasNext() 和 next() 方法. */ Iterator iterator = collection.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } /** * 2.3 移除集合中的元素: * remove(): 移除某一个指定的对象. 通过 equals() 方法来判断要移除的那个元素在集合中是否存在. 以及是否能够成功移除. * removeAll() * clear(): 使集合中的元素置空. */ // collection.clear(); // boolean result = collection.remove(p1); // System.out.println(result); // // result = collection.removeAll(collection2); // // System.out.println(collection.size()); /** * 2.4 用于检测集合的方法 * retains() * retainsAll() * isEmpty() */ System.out.println(collection.contains(new Person()));//false System.out.println(collection.contains(p1));//true System.out.println(collection.containsAll(collection2));//true System.out.println(collection.isEmpty()); //false // collection.clear(); System.out.println(collection.isEmpty()); //true /** * 2.5 其他方法 * toArray(): * **T [] toArray(T[]): 涉及到泛型, 后面再说. * * equals(): 比较两个集合是否相等. * hasCode(): */ Object [] objs = collection.toArray(); System.out.println(objs.length); //4 Person p2 = new Person(); Collection collection3 = new HashSet();//可换ArrayList()试试 collection3.add(p1); collection3.add(p2); Collection collection4 = new HashSet(); collection4.add(p2); collection4.add(p1); System.out.println(collection3.equals(collection4)); /** * 使用增强 for 循环的方式来对集合进行遍历 */ for(Object obj: collection){ System.out.println(obj); } } } class Person(){}
二、Set、HashSet、LinkedHashSet:
Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法。
注意:
1、当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的
hashCode 值, 然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
2、如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会
把它们存储在不同的位置,但依然可以添加成功。
3、HashSet 集合判断两个元素相等的标准:两个对象通过 equals() 方法比较相等,并且两个对象的
hashCode() 方法返回值也相等。即:如果两个对象通过 equals() 方法返回 true,这两个对象的
hashCode 值也应该相同。
重写 hashCode() 方法的基本原则:
1、在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值。
2、当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等。
3、对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
另外:
1、LinkedHashSet 是 HashSet 的子类。
2、LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,
这使得元素看起来是以插入顺序保存的。
3、LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
4、LinkedHashSet 有序但不允许集合元素重复。
import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; /** * 1. Set 是 Collection 的子接口 * 2. Set 中不允许存放相同的元素. 判定相同元素的标准是, 两个对象各调用 equals() 方法, 返回 true * 3. HashSet * 3.1 基本特征: * ①. 不能保证元素的排列顺序 * ②. HashSet 不是线程安全的 * ③. 集合元素可以使 null * ④. 对于 HashSet: 如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。 * * 4. LinkedHashSet: * 4.1 LinkedHashSet 是 HashSet 的子类 * 4.2 使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的 * 4.3 LinkedHashSet 不允许集合元素重复 */ public class TestSet { public static void main(String[] args) { Set set = new LinkedHashSet(); //new HashSet(); set.add(null); System.out.println(set.size()); //1 Person p1 = new Person(); set.add(p1); set.add(p1); System.out.println(set.size()); //2 set.add(new Person("AA", 12)); set.add(new Person("AA", 12)); System.out.println(set.size()); //3 set.add(new Person("FF", 13)); Iterator it = set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } class Person { // @Override // public boolean equals(Object obj) { // return false; // } private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person() { // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } // private static int init = 0; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; // return init++; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
三、TreeSet:
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
排序:
1、TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,
然后将集合元素按升序排列。
2、如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
3、实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过
compareTo(Object obj)方法的返回值来比较大小。
Comparable 的典型实现:
BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较。
Character: 按字符的 UNICODE 值来进行比较。
Boolean: true 对应的包装类实例大于 false 对应的包装类实例。
String: 按字符串中字符的 UNICODE 值进行比较。
Date、Time: 后边的时间、日期比前面的时间、日期大。
注意:
因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象,
当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与
compareTo(Object obj) 方法有一致的结果:即如果两个对象通过 equals() 方法比较返回 true,
则通过 compareTo(Object obj) 方法比较应返回 0.
import java.util.*; /* Set:无序,不可以重复元素。 |--HashSet:数据结构是哈希表。线程是非同步的。 保证元素唯一性的原理:判断元素的hashCode值是否相同。 如果相同,还会继续判断元素的equals方法,是否为true。 |--TreeSet:可以对Set集合中的元素进行排序。 底层数据结构是二叉树。 保证元素唯一性的依据: compareTo方法return 0. TreeSet排序的第一种方式:让元素自身具备比较性。 元素需要实现Comparable接口,覆盖compareTo方法。 也种方式也成为元素的自然顺序,或者叫做默认顺序。 TreeSet的第二种排序方式。 当元素自身不具备比较性时,或者具备的比较性不是所需要的。 这时就需要让集合自身具备比较性。 在集合初始化时,就有了比较方式。 需求: 往TreeSet集合中存储自定义对象学生。 想按照学生的年龄进行排序。 记住,排序时,当主要条件相同时,一定判断一下次要条件。 */ class TreeSetDemo { 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("lisi007",20)); //ts.add(new Student("lisi01",40)); Iterator it = ts.iterator(); while(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 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; } }
import java.util.*; /* 当元素自身不具备比较性,或者具备的比较性不是所需要的。 这时需要让容器自身具备比较性。 定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。 当两种排序都存在时,以比较器为主。 定义一个类,实现Comparator接口,覆盖compare方法。 */ 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; } } class TreeSetDemo2 { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Student("lisi02",22)); ts.add(new Student("lisi02",21)); ts.add(new Student("lisi007",20)); ts.add(new Student("lisi09",19)); ts.add(new Student("lisi06",18)); ts.add(new Student("lisi06",18)); ts.add(new Student("lisi007",29)); //ts.add(new Student("lisi007",20)); //ts.add(new Student("lisi01",40)); Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } } } class MyCompare implements Comparator { public int compare(Object o1,Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int num = s1.getName().compareTo(s2.getName()); if(num==0) { return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); /* if(s1.getAge()>s2.getAge()) return 1; if(s1.getAge()==s2.getAge()) return 0; return -1; */ } return num; } }
比较推荐的定制排序做法:
1、首先,定义一个Person类
public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public Person(){} }
(附加的练习:Student类)
public class Student implements Comparable{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(String name, int age) { super(); this.name = name; this.age = age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @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 (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Object o) { int result; if(o instanceof Student){ Student stu = (Student)o; result = this.age-stu.age; if(result==0){ return this.getName().compareTo(stu.getName()); } }else{ throw new ClassCastException("不是一个学生对象!"); } return result; } public Student(){} @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
2、然后写主程序类
import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; public class TestTreeSet { public static void main(String []args){ /* Set set = new TreeSet(); // set.add("123"); // set.add(123); // set.add(null); // set.add(new Student()); set.add(new Student("lisi07",22)); set.add(new Student("lisi02",16)); set.add(new Student("lisi008",22)); set.add(new Student("lisi10",19)); Iterator iterator = set.iterator(); while(iterator.hasNext()){ Student stu = (Student) iterator.next(); System.out.println(stu.getName()+"...."+stu.getAge()); } for(Object obj:set){ System.out.println(obj); }*/ Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { int result; if(o1 instanceof Person&& o2 instanceof Person){ Person p1 = (Person) o1; Person p2 = (Person) o2; result = p1.getAge() - p2.getAge(); if(result == 0){ return p1.getName().compareTo(p2.getName()); } }else{ throw new ClassCastException("不能转换为Person"); } return result; } }; Set set2 = new TreeSet(comparator); set2.add(new Person("lisi006",12)); set2.add(new Person("lisi002",6)); set2.add(new Person("lisi015",20)); set2.add(new Person("lisi013",20)); Iterator iterator = set2.iterator(); while(iterator.hasNext()){ Person p = (Person) iterator.next(); System.out.println(p.getName()+" "+p.getAge()+" "); } } }