Collection 集合框架中用于存储一个个元素的容器,List 和 Set 是它的子类
List: 存储有序的,可重复的数据
- ArrayList(主要实现类)、LinkedList、Vector
Set: 存储无序的,不可重复的数据
- HashSet(主要实现类)、LinkedHashSet、TreeSet
Map 集合框架中用于存储 key 到 value 的键值映射的容器
Map:存储一对一对的数据
- HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties
Collections 用于操作集合框架的一个工具类
Collection 常用方法
Collection collection = new ArrayList(); Collection collection1 = new ArrayList(); collection.add("test"); collection.add("测试"); Person person = new Person(10, "xiaohua"); collection.add(person); collection1.addAll(collection); collection1.add("123");
|
前者用于添加对象元素,后者用于添加一整个集合比较常见
System.out.println(collection); System.out.println(collection1);
|
清除集合内的元素,用于查看集合是否为空,查看集合元素数量
collection1.clear(); System.out.println(collection1.isEmpty()); System.out.println(collection1.size());
|
前者是判断集合中是否含有某个对象,后者是判断一个集合是否包含另一个集合
System.out.println(collection); System.out.println(collection1); System.out.println(collection.contains(person)); System.out.println(collection.contains(new Person(10, "xiaohua"))); System.out.println(collection.contains("test"));
System.out.println(collection.containsAll(collection1)); System.out.println(collection1.containsAll(collection));
|
remove、removeAll、retainAll
删除指定元素,删除两个集合的交集,只保留两个集合的交集
System.out.println(collection); System.out.println(collection1); collection1.removeAll(collection); System.out.println(collection1);
System.out.println("******************");
collection1.add("test"); collection1.add("1234"); System.out.println(collection); System.out.println(collection1); collection1.retainAll(collection); System.out.println(collection1);
|
把集合转换成数组
@Test public void test4() { Collection collection = new ArrayList(); collection.add("test"); collection.add("测试"); collection.add(new Person(10, "xiaohua")); Object[] arr = collection.toArray(); System.out.println(Arrays.toString(arr)); System.out.println(arr[0]); System.out.println(arr[1]); }
|
Arrays中的asList 可以将数组转换成集合
public void test6() { String[] strings = new String[]{"a", "b", "c"}; Collection collection = Arrays.asList(strings); System.out.println(collection); }
|
迭代器是用来遍历元素的
next、hasNext
获取集合中下一个元素,hasNext 能够判断是否有下一个元素
next 两个作用,第一个是指针下移,第二个是获取当前的元素
@Test public void test1() { Collection collection = new ArrayList(); collection.add("test"); collection.add("测试"); Person person = new Person(10, "xiaohua"); collection.add(person);
System.out.println(collection); Iterator iterator = collection.iterator();
while (iterator.hasNext()) { System.out.println(iterator.next()); }
}
|
对于遍历元素还有一种方式,就是增强的 for 循环
使用增强 for 循环的时候,修改 for 循环中的临时变量,将不会修改原有的数据。因为增强 for 循环是将原有的数据赋值给临时变量。
for (Object obj : collection) { System.out.println(obj); }
|
List 常用方法
和 Collection 相同,大体上的方法作用是相同的。这里仅介绍 List 作为有序的集合,相比于 Collection 的不同。
List 不同类的区别
- ArrayList:List 主要实现类,线程不安全,效率高,底层使用 Object[] 数组储存
- LinkedList:底层使用双向链表的方式进行储存,适用于频繁插入删除的操作
- Vector:List 的古老实现类,线程安全,效率低,底层使用 Object[] 数组储存
List 的特殊方法
add 方法相对于 Collection 多了索引,所以可以在指定位置插入元素。同样,addAll也有这样的特性。
@Test public void test1() { List list = new ArrayList(); list.add("test"); list.add(123); Person person = new Person(10, "xiaohu"); list.add(person); System.out.println(list);
list.add(2, "321"); System.out.println(list);
List list1 = new ArrayList(); list1.add("test"); list1.add("test"); list1.add("test"); list1.addAll(1, list); System.out.println(list1);
}
|
方法删除的是索引位置的元素,如果要删除数据,用Integer的 valueof 赋值成一个对象即可
list1.remove(0); list1.remove(0); System.out.println(list1);
list1.remove(Integer.valueOf(123)); System.out.println(list1);
|
因为 List 有序,所以说对于某一个位置的元素获取变的更加容易
list.set(0, person); System.out.println(list.get(0));
|
indexOf,lastIndexOf,subList
第一个是获取指定元素的首次出现的位置,第二个是获取指定元素的最后出现的位置,subList 是获取从 start 到 end 的所有元素
@Test public void test2() { List list = new ArrayList(); for (int i = 0; i < 10; i ++){ list.add(i); list.add(i+1); } System.out.println(list); System.out.println(list.indexOf(1)); System.out.println(list.lastIndexOf(1)); System.out.println(list.subList(0, 10)); }
|
List 综合测试
综合测试一
public class StudentTest { public static void main(String[] args) { List student = new ArrayList(); Scanner scanner = new Scanner(System.in);
int flag = 1; while (flag == 1) { System.out.println("请输入学生的姓名:"); String name = scanner.next(); System.out.println("请输入学生的年龄:"); int age = scanner.nextInt(); student.add(new Student(name, age)); System.out.println("输入 1 继续录入,输入 0 停止录入"); flag = scanner.nextInt(); }
for (Object obj : student) { Student stu = (Student) obj; System.out.println(stu.toString()); }
scanner.close();
} }
|
综合测试二
对于这个题,list 中存的是 char 字符类型,有两种解决方法。
第一种,存入 list 中的时候在后边加一个 ""
list.add((char)number + "");
|
第二种,在比较的时候对 char 使用 String 的 valueOf 方法进行赋值
String c = String.valueOf(iterator.next()); String c = String.valueOf(obj);
|
public class StringTest { public static void main(String[] args) { ArrayList list = new ArrayList(); for (int i = 0; i < 30; i++) { int max = 122 - 97 + 1; int number = (int) (Math.random() * max + 97); list.add((char)number + ""); } System.out.println(list); int aCount = listTest1(list, "a"); int bCount = listTest1(list, "b"); int cCount = listTest1(list, "c"); int xCount = listTest1(list, "x"); System.out.printf("%d %d %d %d\n", aCount, bCount, cCount, xCount);
} public static int listTest2(Collection list, String s) { int count = 0; Iterator iterator = list.iterator(); while (iterator.hasNext()) { String c = String.valueOf(iterator.next()); if(c.equals(s)){ count++; } } return count; }
public static int listTest1(Collection list, String s) { int count = 0; for (Object obj : list) { String c = String.valueOf(obj); if (c.equals(s)) { count++; } } return count; } }
|
Set 常用方法
Set 声明的方法与 Collection 中声明的 15 个抽象方法相同
对于 Set 来说,我们更重要的是研究他的两个特性。
Set 的常见实现类
- HashSet:主要实现类,底层使用 HashMap,也就是使用了数组,单向链表,红黑树结构进行存储
- LinkedSet:HashSet 的子类,相比与父类,它在不同的元素之间增加了指针,实现了顺序遍历
- TreeSet:底层使用红黑树存储, 可以根据添加的元素对指定的属性大小进行遍历。
Set 的无序性
这里的无序性并不是随机性,对与 Set 来说,它保存是数据的方法是 HashMap,也就是对于将要保存的元素,计算它的哈希值,哈希值即为这个元素的保存位置,所以当添加完元素后,你输入的数据将不会按照顺序保存,而是根据自己的计算结果保存到不同位置,这就是 Set 的无序性。
按照 1-> 5 的顺序进行输入,经过哈希算法计算后排列的位置如下图所示
LinkedSet 相当于增加了一个指针,让 1 指向 2,2 指向 3,以此类推,最后遍历的时候便可以根据指针进行遍历。
Set 的不可重复性
比较的标准是首先判断 HashCode 得到的哈希值是否相同,如果相等则进行 euqals。只有两者都相同,则认为元素是相同的。
演示代码 HashSet
这里可能会有疑问,不是说 Set 中不存在重复的元素,难道对自定义的实体类不生效吗。
我们从Set 存入数据的过程看到,Set 首先要对元素进行哈希计算,这里我们 new 的两个 Person 对象,他们的实体类中没有重写 HashCode 方法,因此调用的是 Object 的方法,该方法并不会把这两个赋值相同的对象计算得到相同的哈希值,所以 Set 会把两个元素看做不同的元素。
为了避免这种问题,我们需要重写实体类中的 HashCode。
@Test public void test2() { Set set = new HashSet(); set.add("test"); set.add(123); set.add(new Person(10,"xiaohua")); set.add(new Person(10,"xiaohua"));
System.out.println(set); }
|
@Override public int hashCode() { int result = age; result = 31 * result + (name != null ? name.hashCode() : 0); return result; }
|
演示代码 LinkedSet
LinkedSet 的优势就是能按照输入顺序输出
@Test public void test1() { Set set = new LinkedHashSet(); Person person = new Person(10,"xiaohua"); set.add("test"); set.add(123); set.add(person); System.out.println(set); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }
|
演示代码 TreeSet
对于 TreeSet 来说,最主要的用处是对插入元素的排序。例如对字符串进行排序
@Test public void test3() { Set set = new TreeSet();
set.add("BB"); set.add("AA"); set.add("GG"); set.add("ZZ"); set.add("YY"); set.add(123);
System.out.println(set); }
|
对于 TreeSet 添加自定义的实体类,进行排序的时候如何进行的判断,实际上是使用了自然排序和自定义排序,compareTo 和 compare 的返回值
以下代码中我重写了 User 中 compareTo 的方法,使得元素按照年龄排序,由于 TreeSet 采用的是红黑树的数据结构,存入的数据不能重复,所以说在按照年龄进行排序的时候,还需要别的元素进行辅助排序。
@Test public void test4() { Set set = new TreeSet();
Person p1 = new Person(10,"xiaohua"); Person p2 = new Person(12,"xiaohua1"); Person p3 = new Person(12,"xiaohua2"); Person p4 = new Person(13,"xiaohua3"); Person p5 = new Person(14,"xiaohua4");
set.add(p1); set.add(p2); set.add(p3); set.add(p4); set.add(p5);
for (Object o : set) { System.out.println(o); } }
|
@Override public int compareTo(Object o) { if (this == o) { return 0; } if (o instanceof Person) { Person p = (Person) o; int number = this.age - p.age; if (number != 0){ return number; } else { return this.name.compareTo(p.name); } } throw new RuntimeException("类型不匹配"); }
|
对于不方便修改实体类中的比较方法的情况,可以直接给 TreeSet 一个 Comparator 方法
@Test public void test4() { Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Person && o2 instanceof Person) { Person p1 = (Person) o1; Person p2 = (Person) o2;
int value = p1.getName().compareTo(p2.getName()); if (value != 0) { return value; } else { return p1.getAge() - p2.getAge(); } } throw new RuntimeException("数据类型不匹配"); } };
Set set = new TreeSet(comparator);
Person p1 = new Person(10,"A1"); Person p2 = new Person(13,"A1"); Person p3 = new Person(10,"B"); Person p4 = new Person(13,"C"); Person p5 = new Person(13,"D");
set.add(p1); set.add(p2); set.add(p3); set.add(p4); set.add(p5);
for (Object o : set) { System.out.println(o); } }
|
Set 综合测试
综合测试一
@Test public void test5() { List list = new ArrayList();
list.add(11); list.add(11); list.add(11); list.add(11); list.add(22); list.add(22); list.add(22); list.add(22); list.add(33); list.add(33); list.add(33); list.add(33);
System.out.println(list); System.out.println(duplicateList(list)); }
public static List duplicateList(List list){ Set set = new LinkedHashSet(list); List new_list = new ArrayList(set); return new_list; }
|
综合测试二
@Test public void test7() { Set set = new HashSet(); while (set.size() < 10) { int randomNumber = (int)(Math.random() * 20) + 1; set.add(randomNumber); } System.out.println(set); }
|
Map 常用方法
Map 不同类的区别
java.util.Map:
存储一对一对的数据,也就是 key-value 键值对
- HashMap: 主要实现类,线程不安全的,效率高的。可以添加 null 的 key 与 value。底层使用数组,单向链表,红黑树的数据结构。
- LinkedMap:HashMap 的子类,添加了一对双向链表,记录添加的元素的先后顺序。
- TreeMap: 底层使用红黑树的数据结构,可以根据添加的 key 元素指定的属性大小进行遍历。
- Hashtable: 古老实现类,线程安全的,效率低的。不可以添加 null 的 key 和 value。底层使用数组,单向链表的数据结构。
演示代码 HashMap
在 HashMap 中,key 是不能够相同的,并且是无序的。而 value 是可以相同的,但由于 value 是 key 的映射,key 是无序的,value 也是无序的。
增删改查
put、putAll、remove、put、get
@Test public void test() { Map map = new HashMap(); Person p1 = new Person(10,"xiaoming");
map.put("AA", 123); map.put("BB", 13); map.put("CC", 23);
map.put(p1, 55);
System.out.println(map);
Map map1 = new HashMap(); map1.putAll(map);
System.out.println(map1); }
|
@Test public void test2() { Map map = new HashMap(); Person p1 = new Person(10,"xiaoming");
map.put("AA", 123); map.put("BB", 13); map.put("CC", 23);
map.put(p1, 55);
Object value = map.remove("BB"); System.out.println(value);
map.put("CC", 15);
System.out.println(map.get("CC"));
System.out.println(map);
}
|
长度 遍历
size、keySet、values、entrySet
@Test public void test3() { Map map = new HashMap(); Person p1 = new Person(10, "xiaoming");
map.put("AA", 123); map.put("BB", 13); map.put("CC", 23);
map.put(p1, 55);
System.out.println(map.size());
Set keySet = map.keySet();
for (Object o :keySet) { System.out.println(o); }
Collection values = map.values();
for (Object o : values) { System.out.println(o); }
Set entrySet = map.entrySet();
for (Object o :entrySet) { System.out.println(o); }
}
|
演示代码 TreeMap
对于 TreeMap 来说,和 TreeSet 一样,重要的是自然排序和定制排序的写法。
@Test public void test2() { Map map = new TreeMap(); Person p1 = new Person(10, "zeus"); Person p2 = new Person(14, "faker"); Person p3 = new Person(12, "jerry"); Person p4 = new Person(12, "tom");
map.put(p1, 12); map.put(p2, 63); map.put(p3, 42); map.put(p4, 31);
Set entry = map.entrySet(); for (Object o : entry) { System.out.println(o); } }
|
定制排序,TreeMap
同样可以传入一个 comparator,在这里 comparator 中我们可以自定义按照类的什么属性进行排序
@Test public void test1() {
Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Person && o2 instanceof Person) { Person p1 = (Person) o1; Person p2 = (Person) o2;
int value = p1.getName().compareTo(p2.getName()); if (value != 0) { return value; } else { return p1.getAge() - p2.getAge(); } } throw new RuntimeException("数据类型不匹配"); } };
Map map = new TreeMap(comparator); Person p1 = new Person(10, "zeus"); Person p2 = new Person(14, "faker"); Person p3 = new Person(12, "jerry"); Person p4 = new Person(12, "tom");
map.put(p1, 12); map.put(p2, 63); map.put(p3, 42); map.put(p4, 31);
Set entry = map.entrySet(); for (Object o : entry) { System.out.println(o); }
}
|
演示代码 Properties
Properties 多用于在文件的 IO 流中,使用 Properties 读取配置文件可以有效的提高代码的可维护性。
@Test public void test1() throws IOException { File file = new File("config.properties"); System.out.println(file.getAbsolutePath());
FileInputStream fileInputStream = new FileInputStream(file); Properties properties = new Properties(); properties.load(fileInputStream);
System.out.println(properties.get("name")); System.out.println(properties.get("password"));
fileInputStream.close();
}
|
Collections 工具类
排序操作
@Test public void test1() { List list = Arrays.asList(1,42,32,43,45,3,4,53,23,31,45,98); System.out.println(list);
Collections.reverse(list); System.out.println(list);
Collections.shuffle(list); System.out.println(list);
Collections.sort(list); System.out.println(list);
Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Integer && o2 instanceof Integer) { Integer i1 = (Integer) o1; Integer i2 = (Integer) o2; return -(i1.intValue() - i2.intValue()); } throw new RuntimeException("类型不匹配"); } }; Collections.sort(list, comparator); System.out.println(list);
}
|
查找操作
@Test public void test2() { List list = Arrays.asList(1, 42, 1, 43, 45, 1, 4, 53, 23, 31, 45, 98); System.out.println(list);
Object max = Collections.max(list); System.out.println(max);
Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Integer && o2 instanceof Integer) { Integer i1 = (Integer) o1; Integer i2 = (Integer) o2; return -(i1.intValue() - i2.intValue()); } throw new RuntimeException("类型不匹配"); } }; Object max1 = Collections.max(list, comparator); System.out.println(max1);
int number = Collections.frequency(list, 1); System.out.println(number); }
|
复制,替换操作
@Test public void test3() { List list = Arrays.asList(1, 42, 1, 43, 45, 1, 4, 53, 23, 31, 45, 98); System.out.println(list); List new_list = Arrays.asList(new Object[list.size()]); Collections.copy(new_list, list); System.out.println(new_list);
}
|
@Test public void test4() { List list = Arrays.asList(1, 42, 1, 43, 45, 1, 4, 53, 23, 31, 45, 98); System.out.println(list); List new_list = Collections.unmodifiableList(list);
new_list.add(12); }
|