数组
数组是由同类型的对象组成的,这些对象可由索引来引用。
数组的声明通常是在类型或标识符后面加上“[]”,“[]”的个数表示数组嵌套的层数。数组的嵌套实际上是将数组中的元素也是数组,这也就表明了数组中每个数组元素的长度可以不同。
在声明数组时使用“{}”为数组赋初值。这种赋值不能在非声明场合使用。
数组的初始化通过new运算实现,使用new运算初始化时需要在“[]”内设置数组的长度。
数组的下标从0开始,到length-1。如果使用的下标不在[0, length-1]的范围内,则会抛出ArrayIndexOutOfBoundsException异常。
数组可以通过“.length”语法获得当前数组的长度。
1 @Test 2 void testArray() { 3 System.out.println("--数组元素长度不同的数组--"); 4 int[][] a = {{1, 2, 3}, {4, 5}}; 5 System.out.println("数组的长度:" + a.length); 6 System.out.println("第一个数组元素的长度:" + a[0].length); 7 System.out.println("第二个数组元素的长度:" + a[1].length); 8 System.out.println("--数组元素长度相同的数组--"); 9 int[][] b = new int[2][3]; 10 System.out.println("数组的长度:" + b.length); 11 System.out.println("第一个数组元素的长度:" + b[0].length); 12 System.out.println("第二个数组元素的长度:" + b[1].length); 13 }
输出结果:
Arrays类
java.util.Arrays类中提供了很多操作数组的方法。常用的有:
1.static <T> List<T> asList(T... a):创建一个java.util.Arrays.ArrayList对象并将所有的参数放入该List中。该List不能添加和删除元素。
a.传入的参数的类型必须相同。
b.若传入的参数只有一个,且为数组,则会将数组内的所有元素添加到List中。
2.static <T> T[] copyOfRange(T[] original, int from, int to):截取数组中[from, to)的元素(Arrays类中重载该方法以适用于任何类型的数组)。
3.static void fill(Object[] a, int fromIndex, int toIndex, Object val):为数组中[fromIndex, toIndex)的元素统一赋值(Arrays类中重载该方法以适用于任何类型的数组)。
4.static void sort(Object[] a, int fromIndex, int toIndex):将数组中的元素升序排列,元素类型必须是可比较的(Arrays类中重载该方法以适用于任何类型的数组)。
5.static String toString(Object[] a):获取一维数组的字符串形式(Arrays类中重载该方法以适用于任何类型的数组)。
6.static String deepToString(Object[] a):获取多维数组的字符串形式(Arrays类中重载该方法以适用于任何类型的数组)。
1 @Test 2 void testArrays() { 3 int[][] a = {{1, 2, 3}, {4, 5, 6}, {9, 8, 7}}; 4 System.out.println("asList: " + Arrays.asList(a)); 5 System.out.println("toString: " + Arrays.toString(a)); 6 System.out.println("deepToString: " + Arrays.deepToString(a)); 7 Arrays.sort(a[2]); 8 System.out.println(Arrays.deepToString(a)); 9 int[] b = new int[3]; 10 System.out.println(Arrays.toString(b)); 11 Arrays.fill(b, 5); 12 System.out.println(Arrays.toString(b)); 13 b = Arrays.copyOfRange(a[1], 0, 3); 14 System.out.println(Arrays.toString(b)); 15 }
输出结果:
Arrays.toString()方法用于打印一维数组,打印多维数组时只打印最外层数组,此时其中的元素视为数组元素。Arrays.deepToString()方法则可以把多维数组的元素打印。
集合
集合是把多个同一类型的元素放进一个单元中,形成一个对象,方便存储、读取、处理数据。常用的集合有:
Set:集合中不包含重复元素。
List:集合中的元素是有序的。
Map:集合中的元素以键值对(key-value)的形式存储。
Collection接口
java.util.Collection接口定义了Set、List和Queue这三种集合的公共行为。
Collection接口常用的方法有:
1.int size():获取集合的大小(集合中元素的个数)。
2.boolean isEmpty():判断集合是否为空(集合中是否没有元素)。
3.Iterator<E> iterator():获取Iterator对象。
4.Object[] toArray():将所有元素放进Object数组中。
5.boolean add(E e):在集合末尾新增元素。
6.boolean remove(Object o):将指定元素删除。
7.void clear():清空集合。
8.boolean contains(Object o):判断集合中是否存在指定元素。
1 @Test 2 void testCollection() { 3 Collection<Character> collection = new HashSet<Character>(Set.of('a', 'b', 'c')); 4 System.out.println("初始集合:" + collection + " 大小:" + collection.size()); 5 System.out.println("集合是否为空:" + collection.isEmpty()); 6 System.out.println("集合中是否存在元素'i':" + collection.contains('i')); 7 collection.clear(); // 清空集合 8 System.out.println("集合是否为空:" + collection.isEmpty()); 9 System.out.println("插入元素'i':" + collection.add('i')); 10 System.out.println("集合中是否存在元素'i':" + collection.contains('i')); 11 System.out.println("删除元素'j':" + collection.remove('j')); 12 }
输出结果:
Iterator接口
java.util.Iterator接口用于遍历Collection对象。可以调用Collection的iterator()方法获取Iterator对象。
Iterator接口常用的方法有:
1.boolean hasNext():判断是否还有下一个元素。
2.E next():获取下一个元素。
1 @Test 2 void testIterator() { 3 Collection<Character> collection = new HashSet<Character>(Set.of('a', 'b', 'c')); 4 Iterator<Character> iterator = collection.iterator(); 5 while (iterator.hasNext()) { 6 System.out.println(iterator.next()); 7 } 8 }
输出结果:
Set接口
Set是不包含重复元素的集合。java.util.Set接口实现了Collection接口。
常用的Set实现类有:
HashSet:元素按哈希值排列。
TreeSet:元素按元素值排列。TreeSet中存放的元素类型必须是可比较的,即对应类必须直接或间接实现Comparable接口。
LinkedHashSet:元素按插入顺序排列。
1 @Test 2 void testSet() { 3 Set<String> set = Set.of("Anna", "Bob", "Namy", "Nancy"); 4 System.out.println("AbstractImmutableSet: " + set); 5 // 将set中的元素插入到hashSet中 6 Set<String> hashSet = new HashSet<String>(set); 7 System.out.println("HashSet: " + hashSet); 8 // 将set中的元素插入到treeSet中 9 Set<String> treeSet = new TreeSet<String>(set); 10 System.out.println("TreeSet: " + treeSet); 11 // 将set中的元素插入到linkedHashSet中 12 Set<String> linkedHashSet = new LinkedHashSet<String>(set); 13 System.out.println("LinkedHashSet: " + linkedHashSet); 14 }
输出结果:
可以看到:AbstractImmutableSet存放的元素是无序的;HashSet按照哈希值顺序排列;TreeSet按照元素值顺序排列;LinkedHashSet按照插入顺序排列,所以跟AbstractImmutableSet的顺序一致。
List接口
List是有序的集合。java.util.List接口实现了Collection接口,除了Collection接口的方法之外,还有以下常用的方法:
1.E get(int index):获取指定位标的元素。
2.E set(int index, E element):为指定位标的元素重新赋值,返回原来的值。
3.void add(int index, E element):在指定位标中添加元素。
4.E remove(int index):删除指定位标的元素。
5.int indexOf(Object o):获取指定元素在List中第一个位标。
6.int lastIndexOf(Object o):获取指定元素在List中最后一个位标。
7.ListIterator<E> listIterator():获取ListIterator对象。
8.List<E> subList(int fromIndex, int toIndex):截取List中[fromIndex, toIndex)之间的元素,创建一个新的List。
常用的List实现类有:
ArrayList:将元素存放在数组中。访问和删除性能较好。
LinkedList:将元素存放在链表中。插入性能较好。
1 @Test 2 void testList() { 3 List<String> list = List.of("Anna", "Bob", "Namy", "Nancy"); 4 ArrayList<String> arrayList = new ArrayList<String>(list); 5 LinkedList<String> linkedList = new LinkedList<String>(list); 6 7 long start, end; 8 // 测试访问时间 9 start = System.nanoTime(); 10 arrayList.get(2); 11 end = System.nanoTime(); 12 System.out.println("ArrayList访问元素运行时间:" + (end - start) + "ns"); 13 start = System.nanoTime(); 14 linkedList.get(2); 15 end = System.nanoTime(); 16 System.out.println("LinkedList访问元素运行时间:" + (end - start) + "ns"); 17 // 测试插入时间 18 start = System.nanoTime(); 19 arrayList.add("David"); 20 end = System.nanoTime(); 21 System.out.println("ArrayList插入元素运行时间:" + (end - start) + "ns"); 22 start = System.nanoTime(); 23 linkedList.add("David"); 24 end = System.nanoTime(); 25 System.out.println("LinkedList插入元素运行时间:" + (end - start) + "ns"); 26 // 测试删除时间 27 start = System.nanoTime(); 28 arrayList.remove(0); 29 end = System.nanoTime(); 30 System.out.println("ArrayList删除元素运行时间:" + (end - start) + "ns"); 31 start = System.nanoTime(); 32 linkedList.remove(); 33 end = System.nanoTime(); 34 System.out.println("LinkedList删除元素运行时间:" + (end - start) + "ns"); 35 }
输出结果:
可以看到:ArrayList访问元素和删除元素的速度要比LinkedList快;而插入元素的速度则比LinkedList慢。
Map接口
Map是键值对的集合。一个键映射一个值,一个值可以由多个键映射。Map中不能包含重复的键。java.util.Map接口中定义了一个内部接口Entry,用于保存键值对信息。
Map接口中常用的方法有:
1.int size():获取Map的大小(Map中键值对个数)。
2.boolean isEmpty():判断Map是否为空(Map中没有键值对)。
3.boolean containsKey(Object key):判断Map中是否有指定键的键值对。
4.boolean containsValue(Object value):判断Map中是否有指定值的键值对。
5.V get(Object key):根据键获取值。
6.V put(K key, V value):向Map中插入键值对,并返回键值对的键原先映射的值。
7.V remove(Object key):删除指定键的键值对,并返回删除的键值对的值。
8.void clear():清空Map。
9.Set<K> keySet():获取Map中的所有键,返回一个Set对象。
10.Collection<V> values():获取Map中的所有值,返回一个Collection对象。
11.Set<Map.Entry<K, V>> entrySet():获取Map中所有键值对,返回一个Set对象。
Entry接口中常用的方法有:
1.K getKey():获取键。
2.V getValue():获取值。
3.V setValue(V value):设置值,返回原先的值。
常用的Map实现类有:
HashMap:键值对按键的哈希值排列。
TreeMap:键值对按键的元素值排列。TreeMap存放的键值对的键的类型必须是可比较的,即对应类必须直接或间接实现Comparable接口。
LinkedHashMap:键值对按插入顺序排列。
1 @Test 2 void testMap() { 3 Map<String, Integer> map = Map.ofEntries(Map.entry("Anna", 1), Map.entry("Bob", 2), Map.entry("Namy", 3), Map.entry("Nancy", 4)); 4 System.out.println(map); 5 HashMap<String, Integer> hashMap = new HashMap<String, Integer>(map); 6 System.out.println(hashMap); 7 TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>(map); 8 System.out.println(treeMap); 9 LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<String, Integer>(map); 10 System.out.println(linkedHashMap); 11 12 // 测试Map的方法 13 map = hashMap; 14 System.out.println("Map的大小:" + map.size()); 15 System.out.println("Map是否为空:" + map.isEmpty()); 16 System.out.println("Map是否包含键”Anna“:" + map.containsKey("Anna")); 17 System.out.println("Map是否包含值5:" + map.containsValue(5)); 18 System.out.println("Map中所有键:" + map.keySet()); 19 System.out.println("Map中所有值:" + map.values()); 20 System.out.println("Map中所有键值对:"); 21 for (Entry<?, ?> entry : map.entrySet()) { 22 System.out.println(entry + " key: " + entry.getKey() + " value: " + entry.getValue()); 23 } 24 map.clear(); // 清空Map 25 System.out.println("Map是否为空:" + map.isEmpty()); 26 System.out.println("插入键值对:" + map.put("David", 5)); 27 System.out.println("获取键“David”的值:" + map.get("David")); 28 System.out.println("删除键值对:" + map.remove("David")); 29 }
输出结果:
Collections类
java.util.Collections类中提供了很多操作集合的方法。常用的有:
1.static <T extends Comparable<? super T>> void sort(List<T> list):对List中的元素升序排列。
2.static void reverse(List<?> list):将List中的元素反转。
3.static void shuffle(List<?> list):将List中的元素排序随机打乱。
4.static void swap(List<?> list, int i, int j):将List中指定的两个位标的元素交换。
5.static <T> void fill(List<? super T> list, T obj):为List中的元素统一赋值。
6.static <T> void copy(List<? super T> dest, List<? extends T> src):拷贝List。注意dest的大小不能小于src的大小。
该方法与在创建对象时传入List的区别是:
a.Collections.copy()方法是将dest中[0, src.size())的元素替换为src中相应的元素。也就是说,dest中[src.size(), dest.size())的元素不会发生改变,还是原先的值。
b.在创建对象时传入List是将参数List中的元素都插入到创建完的List对象中。也就是说,创建完的List的大小与参数List的大小相同。
7.static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll):获取Collection中最小的元素。
8.static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll):获取Collection中最大的元素。
1 @Test 2 void testCollections() { 3 List<Integer> list = new ArrayList<Integer>(List.of(3, 1, 2, 4, 7, 5, 8, 6, 9)); 4 System.out.println("原先的List:" + list); 5 Collections.reverse(list); 6 System.out.println("反转后的List:" + list); 7 Collections.shuffle(list); 8 System.out.println("打乱后的List:" + list); 9 Collections.swap(list, 0, 8); 10 System.out.println("将0号元素和8号元素交换:" + list); 11 Collections.sort(list); 12 System.out.println("升序排列后的List:" + list); 13 System.out.println("List中的最小值:" + Collections.min(list)); 14 System.out.println("List中的最大值:" + Collections.max(list)); 15 List<Integer> l = new ArrayList<Integer>(Arrays.asList(new Integer[list.size()])); 16 System.out.println("原先的l:" + l); 17 Collections.fill(l, 3); 18 System.out.println("填充值后的l:" + l); 19 Collections.copy(l, list); 20 System.out.println("复制后的l:" + l); 21 }
输出结果:
不可变的集合
JDK 9之后的版本新增了java.util.ImmutableCollections类,用来表示不可变的集合。不可变的集合指的是集合声明之后不能对其元素进行任何操作(插入、删除、重新赋值等),只能获取元素。该类中定义了AbstractImmutableSet、AbstractImmutableList和AbstractImmutableMap,分别对应Set、List和Map这三种集合。
作为不可变的集合,AbstractImmutableSet、AbstractImmutableList和AbstractImmutableMap对象不能对其元素进行操作,所以在调用与元素操作相关的方法时,会抛出UnsupportedOperationException异常。
JDK 9之后的版本在Set接口、List接口和Map接口中定义了创建不可变集合的方法,这些方法都是将传入的参数作为元素插入不可变集合中:
Set接口:static <E> Set<E> of(E... elements)
List接口:static <E> List<E> of(E... elements)
Map接口:static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)
static <K, V> Entry<K, V> entry(K k, V v)
JDK 10之后的版本在Set接口、List接口和Map接口中又定义了新的创建不可变集合的方法,这些方法是将传入的集合中的元素插入不可变集合中:
Set接口:static <E> Set<E> copyOf(Collection<? extends E> coll)
List接口:static <E> List<E> copyOf(Collection<? extends E> coll)
Map接口:static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map)