Java集合可分为 Collection 和 Map 两种体系
1、Collection接口:单列数据,定义了存取一组对象的方法的集合
- List:元素有序、可重复的集合
- Set:元素无序、不可重复的集合
2、Map接口:双列数据,保存具有映射关系 ”key-value对“ 的集合
一、Collection接口
说明:
- Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法 既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
- JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)
实现。 - 在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都 当成 Object 类型处理;从 JDK 5.0 增加了泛型以后,Java 集合可以记住容器中对象的数据类型。
1、常用方法
import org.junit.Test;
import java.util.*;
/**
* 要求:
* 想Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()
*/
public class test01 {
@Test
public void testCollection1(){
Collection coll = new ArrayList();
//1.add(Object e):将元素e添加到集合coll中
coll.add("AA");
coll.add("BB");
coll.add(new String("LaLa"));
coll.add(123);
coll.add(new Date());
//2.size():获取添加的元素的个数
System.out.println(coll.size());//5
//3.addAll(Collection coll1):将coll1集合中的元素添加到当前的集合中
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add("CC");
coll1.addAll(coll);
System.out.println(coll1.size());//7
//4.clear():清空集合元素
coll.clear();
//5.isEmpty():判断当前集合是否为空
System.out.println(coll.isEmpty());//true
}
@Test
public void testCollection2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("LaLa"));
//6.contains(Object obj):判断当前集合中是否包含obj
//判断时会调用obj对象所在类的equals()
System.out.println(coll.contains(new String("LaLa")));//true
//containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中
Collection coll1 = Arrays.asList(123, 456);
System.out.println(coll.containsAll(coll1));//true
}
@Test
public void testCollection3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(false);
//7.remove(Object obj):从当前集合中移除obj元素
coll.remove(123);
System.out.println(coll);//[456, Tom, false]
//8.removeAll(Collection coll1):从当前集合中移除coll1中所有的元素(差集)
Collection coll1 = Arrays.asList(456, 1234);
coll.removeAll(coll1);
System.out.println(coll);//[Tom, false]
}
@Test
public void testCollection4(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(false);
//9.retainAll(Collection coll1):获取当前集合和coll1集合的交集,并返回给当前集合
Collection coll1 = Arrays.asList(123, 456, 789);
coll.retainAll(coll1);
System.out.println(coll);//[123, 456]
}
@Test
public void testCollection5(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(false);
Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add(456);
coll1.add(new String("Tom"));
coll1.add(false);
//10.equals(Object obj):不仅要相等,还要有序
System.out.println(coll.equals(coll1));//true
}
@Test
public void testCollection6(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(false);
//11.hashCode():返回当前对象的哈希值
System.out.println(coll.hashCode());
}
@Test
public void testCollection7(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new String("Tom"));
coll.add(false);
//12.集合 ---> 数组:toArray()
Object[] arr = coll.toArray();
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
//拓展:数组 ---> 集合:调用Arrays类的静态方法asList()
List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
System.out.println(list);
//但是要注意
List arr2 = Arrays.asList(new int[]{123, 456});
System.out.println(arr2.size());//1
List arr3 = Arrays.asList(new Integer[]{123, 456});
System.out.println(arr3.size());//2
}
}
二、Collection子接口之一: List接口
说明:
- List集合类中元素有序、且可重复。
- JDK API中List接口的实现类常用的有:ArrayList、LinkedList和Vector。
1、常用方法
List除了从Collection集合继承的方法外,List 集合里添加了一些根据索引来 操作集合元素的方法。
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* void add(int index, Object ele):在index位置插入ele元素
* boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
* Object get(int index):获取指定index位置的元素
* int indexOf(Object obj):返回obj在集合中首次出现的位置
* int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
* Object remove(int index):移除指定index位置的元素,并返回此元素
* Object set(int index, Object ele):设置指定index位置的元素为ele
* List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
*/
public class test05 {
@Test
public void testList(){
List list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");
list.add(new String("BB"));
list.add(789);
//1.void add(int index, Object ele):在index位置插入ele元素
list.add(1, "BB");
//2.boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list1 = Arrays.asList(1, 2, 3);
list.addAll(list1);
//3.Object get(int index):获取指定index位置的元素
System.out.println(list.get(1));
//4.int indexOf(Object obj):返回obj在集合中首次出现的位置。如果不存在,返回-1。
int index = list.indexOf(456);
System.out.println(index);
//5.int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
System.out.println(list.lastIndexOf(456));
//6.Object remove(int index):移除指定index位置的元素,并返回此元素
Object obj = list.remove(0);
//7.Object set(int index, Object ele):设置指定index位置的元素为ele
list.set(1, "CC");
//8.List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置左闭右开区间的子集合
List subList = list.subList(2, 4);
}
}
2、List实现类之一:ArrayList
说明:
- ArrayList 是 List 接口的典型实现类、主要实现类
- ArrayList的JDK1.8之前与之后的实现区别?
- JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组
- JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元 素时再创建一个始容量为10的数组
- Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是 Vector 实例。 Arrays.asList(…) 返回值是一个固定长度的 List 集合
3、List实现类之二:LinkedList
说明:
- 对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高 。
- LinkedList:双向链表,内部没有声明数组,而是定义了Node类型的first和last, 用于记录首末元素。同时,定义内部类Node,作为LinkedList中保存数据的基 本结构。Node除了保存数据,还定义了两个变量:prev(变量记录前一个元素的位置 )和 next(变量记录下一个元素的位置)。
- 新增方法:
- void addFirst(Object obj)
- void addLast(Object obj)
- Object getFirst()
- Object getLast()
- Object removeFirst()
- Object removeLast()
4、List 实现类之三:Vector
说明:
- Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList 相同,区别之处在于Vector是线程安全的。
- 在各种list中,最好把ArrayList作为缺省选择。当插入、删除频繁时, 使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用。
- 新增方法:
- void addElement(Object obj)
- void insertElementAt(Object obj,int index)
- void setElementAt(Object obj,int index)
- void removeElement(Object obj)
- void removeAllElements()
三、 Collection子接口之二: Set接口
说明:
- Set接口是Collection的子接口,set接口没有提供额外的方法。
- Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
- Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法
1、Set实现类之一:HashSet
说明:
-
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
-
不能保证元素的排列顺序 ;HashSet 不是线程安全的 ;集合元素可以是 null。
-
HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
-
对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
-
向HashSet中添加元素的过程:
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法 来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列函数决定该对象 在 HashSet 底层数组中的存储位置。(这个散列函数会与底层数组的长度相计算得到在 数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布, 该散列函数设计的越好)。
如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果 为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了, 那么会通过链表的方式继续链接。
-
底层也是数组,初始容量为16,当如果使用率超过0.75,(16*0.75=12) 就会扩大容量为原来的2倍。(16扩容为32,依次为64,128....等)
2、Set实现类之二:LinkedHashSet
说明:
- LinkedHashSet 是 HashSet 的子类。
- LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置, 但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入 顺序保存的。
- LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全 部元素时有很好的性能。
3、Set实现类之三:TreeSet
说明:
-
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。
-
TreeSet底层使用红黑树结构存储数据 。
-
新增方法:
- Comparator comparator()
- Object first()
- Object last()
- Object lower(Object e)
- Object higher(Object e)
- SortedSet subSet(fromElement, toElement)
- SortedSet headSet(toElement)
- SortedSet tailSet(fromElement)
-
只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常。
@Test public void test1(){ TreeSet set = new TreeSet(); //失败:不能添加不同类的对象 // set.add(123); // set.add(456); // set.add("AA"); // set.add(new User("Tom",12)); //举例一: // set.add(34); // set.add(-34); // set.add(43); // set.add(11); // set.add(8); //举例二: set.add(new User("Tom",12)); set.add(new User("Jerry",32)); set.add(new User("Jim",2)); set.add(new User("Mike",65)); set.add(new User("Jack",33)); set.add(new User("Jack",56)); Iterator iterator = set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } }
-
TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
//自然排序 //按照姓名从大到小排列,年龄从小到大排列 @Override public int compareTo(Object o) { if(o instanceof User){ User user = (User)o; // return -this.name.compareTo(user.name); int compare = -this.name.compareTo(user.name); if(compare != 0){ return compare; }else{ return Integer.compare(this.age,user.age); } }else{ throw new RuntimeException("输入的类型不匹配"); } }
@Test public void test2(){ Comparator com = new Comparator() { //按照年龄从小到大排列 @Override public int compare(Object o1, Object o2) { if(o1 instanceof User && o2 instanceof User){ User u1 = (User)o1; User u2 = (User)o2; return Integer.compare(u1.getAge(),u2.getAge()); }else{ throw new RuntimeException("输入的数据类型不匹配"); } } }; TreeSet set = new TreeSet(com); set.add(new User("Tom",12)); set.add(new User("Jerry",32)); set.add(new User("Jim",2)); set.add(new User("Mike",65)); set.add(new User("Mary",33)); set.add(new User("Jack",33)); set.add(new User("Jack",56)); Iterator iterator = set.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } }
四、Map接口
说明:
- Map与Collection并列存在。用于保存具有映射关系的数据:key-value 。
- Map 中的 key 和 value 都可以是任何引用类型的数据。
- Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode()和equals()方法。
- Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用频率最高的实现类。
1、常用方法:
@Test
public void test3(){
Map map = new HashMap();
//1.Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
map.put("AA",123);
map.put(45,123);
map.put("BB",56);
map.put("AA",87);
Map map1 = new HashMap();
map1.put("CC",123);
map1.put("DD",123);
//2.void putAll(Map m):将m中的所有key-value对存放到当前map中
map.putAll(map1);
//3.Object remove(Object key):移除指定key的key-value对,并返回value
Object value = map.remove("CC");
System.out.println(value);
System.out.println(map);
//4.void clear():清空当前map中的所有数据
map.clear();//与map = null操作不同
System.out.println(map.size());
System.out.println(map);
}
@Test
public void test4(){
Map map = new HashMap();
map.put("AA",123);
map.put(45,123);
map.put("BB",56);
//5.Object get(Object key):获取指定key对应的valuey)
System.out.println(map.get(45));
//6.boolean containsKey(Object key):是否包含指定的key
boolean isExist = map.containsKey("BB");
System.out.println(isExist);
//7.boolean containsValue(Object value):是否包含指定的value
isExist = map.containsValue(123);
System.out.println(isExist);
map.clear();
//8.int size():返回map中key-value对的个数
System.out.println(map.size());
//9.boolean isEmpty():判断当前map是否为空
System.out.println(map.isEmpty());
//10.boolean equals(Object obj):判断当前map和参数对象obj是否相等
}
@Test
public void test5(){
Map map = new HashMap();
map.put("AA",123);
map.put(45,1234);
map.put("BB",56);
//11.Set keySet():返回所有key构成的Set集合
Set set = map.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//12.Collection values():返回所有value构成的Collection集合
Collection values = map.values();
for(Object obj : values){
System.out.println(obj);
}
//13.Set entrySet():返回所有key-value对构成的Set集合
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
while (iterator1.hasNext()){
Object obj = iterator1.next();
//entrySet集合中的元素都是entry
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "---->" + entry.getValue());
}
System.out.println();
//方式二:
Set keySet = map.keySet();
Iterator iterator2 = keySet.iterator();
while(iterator2.hasNext()){
Object key = iterator2.next();
Object value = map.get(key);
System.out.println(key + "=====" + value);
}
}
2、Map实现类之一:HashMap
说明:
- HashMap是 Map 接口使用频率最高的实现类。
- 允许使用null键和null值,与HashSet一样,不保证映射的顺序。
- 所有的key构成的集合是Set:无序的、不可重复的。所以,key所在的类要重写:equals()和hashCode()。
- 一个key-value构成一个entry。
- JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法) 。JDK 8版本发布以后:HashMap是数组+链表+红黑树实现。
3、Map实现类之二:LinkedHashMap
说明:
- LinkedHashMap 是 HashMap 的子类。
- 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序。
- 与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致。
4、Map实现类之三:TreeMap
说明:
- TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。 TreeMap 可以保证所有的 Key-Value 对处于有序状态。
- TreeSet底层使用红黑树结构存储数。
- 自然排序、定制排序
5、Map实现类之四:Hashtable
说明:
- Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap, Hashtable是线程安全的。
- Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询 速度快,很多情况下可以互用。
- 与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value。
6、Map实现类之五:Properties
- Properties 类是 Hashtable 的子类,该对象用于处理属性文件。
- 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型。
- 存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法。
public class PropertiesTest {
//Properties:常用来处理配置文件。key和value都是String类型
public static void main(String[] args) {
FileInputStream fis = null;
try {
Properties pros = new Properties();
fis = new FileInputStream("jdbc.properties");
pros.load(fis);//加载流对应的文件
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + ", password = " + password);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}