集合主要技术
- 了解Collection和Map
- Collection接口
- ArrayList类
- HashSet类
- HashMap类
- Collections工具类
- 泛型
一 .Collection和Map
Collection集合继承关系图Map集合继承关系图线程安全:多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
Collection
Collection是对象集合,有两个子接口 List 和 Set,ArrayList、Vector 、LinkedList是List的实现类
ArrayList 是线程不安全的, Vector 是线程安全的,这两个类底层都是由数组实现的。
LinkedList是线程不安全的,底层是由链表实现的。
ArrayList和LinkedList的操作基本一致;HashSet和LinkedHashSet的操作基本一致。
Map是键值对集合
HashTable和HashMap是 Map 的实现类。
HashTable是线程安全的,不能存储 null 值;HashMap 不是线程安全的,可以存储 null 值。
HashTable的子类Properties类表示了一个持久的属性集,用于小型数据的持久化保存。
二.Collection接口
- 1.创建:由于接口不能用来实例化一个对象,所以我们实例化其子类,利用多态性接受来测试Collection接口的方法。创建的时候需要明确存放的内容是什么类型。
Collection<String> collection = new ArrayList();
- 2.添加:直接在末尾添加指定对象或者添加某个集合的内容
//末尾添加
boolean add(E e);
collection.add("Jack");
collection.add("Mary");
System.out.println(collection);
输出:[Jack, Mary]
//添加一个集合
boolean addAll(Collection<? extends E> c);
collection.clear();//清空
Collection<String> collectionTemp = new ArrayList();
collectionTemp.add("Jack");
collectionTemp.add("Mary");
collection.addAll(collectionTemp);
System.out.println(collection);
输出:[Jack, Mary]
- 3.移除:移除指定对象,移除指定集合内对象,除了指定集合内的元素外其余元素全部移除,按照指定条件移除
//移除指定对象
boolean remove(Object obj);
collection.remove("Jack");
System.out.println(collection);
输出:[Mary]
//移除指定集合对象
boolean removeAll(Collection<?> c);
Collection<Integer> collectionTemp1 = new ArrayList();
collectionTemp1.add(1);
collectionTemp1.add(2);
collectionTemp1.add(3);
Collection<Integer> temp = new ArrayList();
temp.add(1);
collectionTemp1.removeAll(temp);
System.out.println(collectionTemp1);
输出:[2, 3]
//除了指定集合内的元素外其余元素全部移除
boolean retainAll(Collection<?> c);
Collection<Integer> collectionTemp1 = new ArrayList();
collectionTemp1.add(1);
collectionTemp1.add(2);
collectionTemp1.add(3);
Collection<Integer> temp = new ArrayList();
temp.add(1);
collectionTemp1.retainAll(temp);
System.out.println(collectionTemp1);
输出:[1]
//按照指定条件移除
boolean removeIf(Predicate<? super E> p)
Collection<Integer> collectionTemp1 = new ArrayList();
collectionTemp1.add(1);
collectionTemp1.add(2);
collectionTemp1.add(3);
collectionTemp1.removeIf(obj -> obj > 2);
System.out.println(collectionTemp1);
输出:[1, 2]
- 4.获取元素个数
int size();
System.out.println(collection.size());
输出:1
- 5.判断一个元素是否包含另一个元素
boolean contains(Object obj);
if (collection.contains("Mary")) {
System.out.println("有Mary");
}else {
System.out.println("有Mary");
}
输出:有Mary
- 6.判断是否为空
boolean isEmpty();
//判断是否为空
if (collection.isEmpty()){
System.out.println("是空的");
}else{
System.out.println("不是空的");
}
输出:不是空的
- 7.判断两个集合是否相同
boolean equals(Object obj);
if (collection.equals(collectionTemp)){
System.out.println("相同");
}else{
System.out.println("不相同");
}
- 8.转化成不可变的普通数组
//转化成为Object类型的不可变数组
Object[] toArray();
Object[] array1 = collectionTemp.toArray();
for (Object obj : array1) {
System.out.print((String)obj);
}
输出:JackMary
//转化成为指定类型的不可变数组
<T> T[] toArray(T[] t);
Integer[] array2 = new Integer[collectionTemp.size()];
array2 = collectionTemp.toArray(array2);
for (String str : array2) {
System.out.print(str);
}
输出:JackMary
- 9.迭代器遍历:迭代器刚开始不指向第一个位置,下一个才是第一个位置
//获得当前集合的迭代器
Iterator<E> iterator();
//判断下一个位置是否有元素
boolean hasNext();
//指向下一个位置,并返回下一个位置的值
E next();
Iterator iterator = collectionTemp.iterator();
while (iterator.hasNext()){
System.out.print(iterator.next());
}
//输出:JackMary
- 10.清空集合
void clear();
collection.clear();
System.out.println(collection);
输出:[]
三.ArrayList
ArrayList实现了Collection接口,Collection有的方法ArrayList都有,并且在其基础上还有更多的方法。接下里说一下ArrayList比Collection多的方法。
1.创建
ArrayList<Integer> score = new ArrayList();
2.添加
- Collection接口提供的方法
//添加指定对象
boolean add(E e);
//添加一个集合
boolean addAll(Collection<? extends E> c);
- 新的方法:在指定索引位置添加对象
public void add(int offset, E e);
score.add(2);//末尾添加
score.add(0,3);//指定位置插入
System.out.println(score);
输出:[3, 2]
3.访问指定索引位置的元素
public E get(int offset);
System.out.println(score.get(0));
输出:3
4.修改指定索引位置元素
public E set(int offset, E e);
score.set(0,1);
System.out.println(score);
输出:[1, 2]
5.返回给定对象的索引值
//返回指定对象第一次出现的索引位置
public int indexOf(Object obj)
//返回指定对象最后一次出现的索引位置
public int lastIndexOf(Object obj)
6.返回给定集合某一块的子集合
public List<E> subList(int offset, int len)
System.out.println(score.subList(0,1));
输出:[1]
7.移除
- Collection接口提供的方法
//移除指定对象
boolean remove(Object obj);
//移除指定集合对象
boolean removeAll(Collection<?> c);
//除了指定集合内的元素外其余元素全部移除
boolean retainAll(Collection<?> c);
//按照指定条件移除
boolean removeIf(Predicate<? super E> p)
- 新的方法:移除指定索引位置对象
public E remove(int offset)
- 混淆问题:操作是对象,为什么我们可以对基本类型进行操作呢。因为Java内部有装盒(例如:int->Integer)和拆盒(例如:Integer->int)的操作。
//删除指定位置的元素
score.remove(0);
System.out.println(score);
输出:[2]
//删除指定对象
score.remove((Integer) 2);
System.out.println(score);
输出:[]
8.排序
public void sort(Comparator<? super E> c)
- 排序重点是创建一个比较器对象,首先说系统提供好的升序和降序比较器。
ArrayList<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
//降序
list.sort(Comparator.reverseOrder());
System.out.println(list);
//升序
list.sort(Comparator.naturalOrder());
System.out.println(list);
输出:
[6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6]
- 根据想要比较的对象创建
list.sort(Comparator.reverseOrder());
System.out.println(list);
//升序
list.sort(Comparator.comparing(Integer::intValue));
System.out.println(list);
输出:
[6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6]
- 自己创建一个类实现Comparator接口
class XLCompare implements Comparator{
@Override
public int compare(Object o1, Object o2) {
int mo1 = (int)o1;
int mo2 = (int)o2;
return mo1 - mo2;
}
}
list.sort(Comparator.reverseOrder());
System.out.println(list);
list.sort(new XLCompare());
System.out.println(list);
输出:
[6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6]
- 使用匿名类完成:什么时候需要自己手动创建比较器,如果系统默认提供的方法不能完成我们的比较
list.sort(Comparator.reverseOrder());
System.out.println(list);
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer integer, Integer t1) {
return integer-t1;
}
});
System.out.println(list);
输出:
[6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6]
- 使用Lambda 表达式
list.sort(Comparator.reverseOrder());
System.out.println(list);
list.sort((Integer i1,Integer i2)->i1-i2);
System.out.println(list);
- 例子:比较两个自定义的对象
public class Person {
String name;
int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
}
class XLCompare implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Public p1 = (Public)o1;
Public p2 = (Public)o2;
if(p1.age != p2.age){
return p1.age - p2.age;
}else{
return p1.name - p2.name;
}
}
}
ArrayList<Person> list = new ArrayList();
String[] names = {"张明","张杰","李明浩","李浩天","李隆基","李世明"};
for (int i = 0; i < names.length; i++) {
Person person = new Person(names[i],i+30);
list.add(person);
}
list.sort(new XLCompare());
四.HashSet
1.简述
Set里面元素不能重复,如果重复添加不进去;其内部使用HashMap来实现,键值对中键key不能重复。内部是通过计算每个key的hash值,是在对象的地址的基础上得到的值;Object类有一个方法
public native int hashCode();
用来返回hash值;切记重写类的equals方法一定要重写hashCode方法,hashCode和equals详解。Object类还有一个方法protected native Object clone() throws CloneNotSupportedException;
用于复制对象,clone详解。Set是无序的,添加的顺序和存储的顺序无关;而ArrayList添加的顺序和存储的顺序有关。
Hash大部分的操作可以参照Collection接口。
HashSet内部的顺序是按照默认的顺序排列的;TreeSet则可以使用我们给定的顺序排列。
2.HashSet代码例子
HashSet<String> hashSet = new HashSet<>();
hashSet.add("java");
hashSet.add("java");
hashSet.add("jack");
hashSet.add("Android");
System.out.println(hashSet);
//[java, jack, Android]
hashSet.removeIf(element->element.compareTo("c") > 0);
System.out.println(hashSet);
//[Android]
3.TreeSet代码例子
可以在TreeSet的构造方法中传入一个比较器Comparator,这又涉及到Comparator和Comparable两个接口的区别
Comparator 则是在外部制定排序规则,然后作为排序策略参数传递给某些类,例如ArrayList的sort方法,TreeSet的构造方法。
自然排序需要类实现 Comparable,并且在内部重写 comparaTo 方法。Object类有一个用于比较的方法
public boolean equals(Object var1) {return this == var1;}
,就需要类实现 Comparable。系统内部的类基本上都实现了Comparable接口,如果我们自定义的类需要比较,那么一定要实现 Comparable接口。
class Person implements Comparable{
String name;
int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//equals比较的是对象内部的内容
//所有的对象要能参加比较,必须实现Comparable
//接口compareTo方法
//在compareTo中做具体的比较
@Override
public int compareTo(Object o) {
//判断o对象是不是Person的一个对象
if (o instanceof Person){
//自己规定返回的策略
if (this.age != ((Person) o).age){
return this.age-((Person) o).age;
}else {
//年龄相同的情况下再比姓名
return this.name.compareTo(((Person) o).name);
}
}else {
return -1;
}
}
}
TreeSet<Integer> score = new TreeSet<>();
score.add(32);
score.add(45);
score.add(12);
System.out.println(score);
//[12, 32, 45]
//Lambda表达式方式
TreeSet<Person> persons = new TreeSet<>((Person p1,Person p2)->p1.compareTo(p2));
//匿名类方式
/*TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person person, Person t1) {
return person.compareTo(t1);
}
});*/
Person p1 = new Person("仙王",18);
Person p2 = new Person("武帝",18);
Person p3 = new Person("开天",18);
persons.add(p1);
persons.add(p2);
persons.add(p3);
System.out.println(persons);
输出:[Person{name='仙王', age=18}, Person{name='开天', age=18}, Person{name='武帝', age=18}]
五.HashMap
一.概述
HashMap集合存储数据的特点:键key-值value
key不能重复,可以是任意的对象类型,通常使用字符串
二.方法
- 1.创建对象:需要制定键和值得类型。
HashMap<String,Integer> score = new HashMap<>();
- 2.添加键值对:添加的键值相同的情况,后面的默认更改值。
public V put(K key, V value)
添加一个HashMap
public void putAll(Map<? extends K, ? extends V> m)
//添加对象:键值对
score.put("Chinese",90);
score.put("English",88);
score.put("Math",100);
//相同的情况,默认更改其值
score.put("Chinese",95);
System.out.println(score);
输出:{English=88, Chinese=95, Math=100}
- 3.获取键值对的个数
public int size()
System.out.println(score.size());
输出:3
- 4.获取所有的key
public Set<K> keySet()
System.out.println(score.keySet());
输出:[English, Chinese, Math]
- 5.获取所有的value
public Collection<V> values()
System.out.println(score.values());
输出:[88, 95, 100]
- 6.获取一个键对应的值,如果key不存在,返回null
public V get(Object obj)
System.out.println(score.get("Chinese"));
输出:95
- 7.返回包含映射的Set视图。
public Set<Entry<K, V>> entrySet()
System.out.println(score.entrySet());
输出:[English=88, Chinese=95, Math=100]
- 8.键值对的遍历
//1.通过遍历key得到每一个key对应的值
for (String key : score.keySet()) {
//通过key得到值
int value = score.get(key);
System.out.println("key:"+key+" "+"value;"+value);
}
输出:
key:English value;88
key:Chinese value;95
key:Math value;100
//2.通过entrySet 得到Entry对象的集合
//一个entry管理一个键值对 getKey getValue
Set<Map.Entry<String ,Integer>> entrys = score.entrySet();
for (Map.Entry entry : entrys) {
//得到entry对应的key
String key = (String)entry.getKey();
//得到entry对应的value
Integer value = (Integer)entry.getValue();
System.out.println("key:"+key+" "+"value;"+value);
}
输出:
key:English value;88
key:Chinese value;95
key:Math value;100
- 9.删除制定键对应的映射关系
public V remove(Object obj)
score.remove("Chinese");
System.out.println(score);
输出:{English=88, Math=100}
- 10.替换指定键对应的值
public V replace(K key, V value)
score.replace("English",90);
System.out.println(score);
输出:{English=90, Math=100}
- 11.判断是否为空
public boolean isEmpty()
- 12.清空所有映射关系
public void clear();
六.Collections工具类
- 1.获取List中的最小值
List<Integer> intList = Arrays.asList(33, 24, 18, 6, 9, 99);
// 6
System.out.println(java.util.Collections.min(intList));
- 2.获取List中的最大值
List<Integer> intList = Arrays.asList(33, 24, 18, 6, 9, 99);
// 99
System.out.println(java.util.Collections.max(intList));
- 3.Shuffle方法可以使一个集合的元素乱序化。
List<Integer> intList = Arrays.asList(33, 24, 18, 6, 9, 99);
Collections.shuffle(intList);
// 一次测试的结果
// [6, 18, 33, 24, 99, 9]
System.out.println(intList);
- 4. nCopies返回一个不可变列表组成的n个拷贝的指定对象。
// 生成一个由10个100组成的整数列表
List<Integer> nCopiesList = Collections.nCopies(10, 100);
//[100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
System.out.println(nCopiesList);
- 5.sort用于对集合排序。
List<Integer> intList = Arrays.asList(33, 24, 18, 6, 9, 99);
Collections.sort(intList);
- 6.binarySearch用于查找给定元素在给定数组的索引值。
List<Integer> intList = Arrays.asList(33, 24, 18, 6, 9, 99);
// 2
System.out.println(Collections.binarySearch(intList, 18));
- 7.frequency获取某个元素在集合出现的次数。
List<String> testList = Arrays.asList("A", "B", "C", "D");
int freq = Collections.frequency(testList, "A");
// 1
System.out.println(freq);
- 8.indexOfSubList返回指定源列表中第一次出现指定目标列表的起始位置。
int index = Collections.indexOfSubList(Arrays.asList("A", "B", "C"),
Arrays.asList("B"));
// Print 1
System.out.println(index);
- 9.lastIndexOfSubList返回指定源列表中最后一次出现指定目标列表的起始位置。
int lastIndex = Collections.lastIndexOfSubList(
Arrays.asList("A", "B", "C", "B"), Arrays.asList("B"));
// Print 3
System.out.println(lastIndex);
- 10.reverse反转列表中的元素顺序。
List<String> reverseCandidate = Arrays.asList("A", "B", "C");
Collections.reverse(reverseCandidate);
// [C, B, A]
System.out.println(reverseCandidate);
七.泛型
1.泛型方法
泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。
所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
public class GenericMethodTest{
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray ){
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
public static void main( String args[] ){
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
输出:
整型数组元素为:
1 2 3 4 5
双精度型数组元素为:
1.1 2.2 3.3 4.4
字符型数组元素为:
H E L L O
2.泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。
一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
public class MyClass {
public static void main(String[] args){
//创建类,明确指定T指定的类型
GenericTest<String> genericTest = new GenericTest<>();
genericTest.test("java","oc");
System.out.println(genericTest.a1);
}
}
class GenericTest<T>{
int age;
T a1;
T a2;
public void test(T a1,T a2){
this.a1 = a1;
this.a2 = a2;
System.out.println(a1.equals(a2));
}
}
3.类型通配符
类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
import java.util.*;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
getData(name);
getData(age);
getData(number);
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
}
输出:
data :icon
data :18
data :314