本文最后更新于:1 年前
集合-1
1.集合的概念
集合就是用于存储多个数据的容器。相对于具有相同功能的数组来说,集合的长度可变会更加灵活方便。Java中提供了使用不同数据结构存储数据的不同集合类,他们有各自不同的特点,并且在类中提供了很多常用了方法,便于我们使用。
2.集合体系结构
集合主要有两个顶层接口,Collection和Map。
image-20201128195014504
3. 常用list集合
3.1 list集合的特点
List接口下的集合都会有以下特点:
- 有索引
- 可以存储重复元素
- 元素存入的顺序和实际存储的顺序相同
3.2 ArrayList
3.2.1 创建对象
1 2
| ArrayList list = new ArrayList<>(); ArrayList<集合元素的数据类型> list2 = new ArrayList<>();
JAVA
|
3.2.2 常用方法
1 2 3 4 5 6 7 8
| boolean add(E e) void add(int index, E element) boolean remove(Object o) E remove(int index) E set(int index, E element) E get(int index) int size() boolean contains(Object o)
JAVA
|
我们平时对集合用的最多的是add,remove,get,set,size这几个方法。
3.2.3 遍历
1.使用索引遍历
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("三"); list.add("更"); list.add("草"); list.add("堂"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } }
JAVA
|
2.使用迭代器遍历
1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("三"); list.add("更"); list.add("草"); list.add("堂"); Iterator<String> it = list.iterator(); while (it.hasNext()){ String s = it.next(); System.out.println(s); } }
JAVA
|
注意:为了避免并发修改异常(ConcurrentModificationException)的出现。避免在使用迭代器遍历的过程中对集合进行操作。
3.使用foreach遍历
foreach是java提供的一个语法糖。可以让我们更方便的遍历集合或数组。
格式如下:
1 2 3
| for(元素数据类型 变量名 : 遍历的集合或者数组){ }
JAVA
|
例如:
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("三"); list.add("更"); list.add("草"); list.add("堂"); for (String s : list) { System.out.println(s); } }
JAVA
|
1 2 3 4
| String[] arr = {"三","更","草","堂"}; for(String s : arr){ System.out.println(s); }
JAVA
|
4.转换为数组遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("三"); list.add("更"); list.add("草"); list.add("堂");
String[] strings = list.toArray(new String[0]); for (String string : strings) { System.out.println(string); }
}
JAVA
|
3.3 LinkedList
3.3.1 创建对象
1 2
| LinkedList list = new LinkedList<>(); LinkedList<集合元素的数据类型> list2 = new LinkedList<>();
JAVA
|
3.3.2 常用方法
1 2 3 4 5 6 7 8
| boolean add(E e) void add(int index, E element) boolean remove(Object o) E remove(int index) E set(int index, E element) E get(int index) int size() boolean contains(Object o)
JAVA
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); list.add("更"); list.add(0,"三"); list.remove("三"); list.set(0,"三更草堂"); String s = list.get(0); int size = list.size(); boolean flag = list.contains("三更草堂"); }
JAVA
|
我们发现上面这些方法其实和ArrayList中的常用方法都是相同的。因为LinkedList和ArrayList都是List接口的实现类,上面的很多方法都是他们共同的接口中定义的方法,所以都会有。
下面是LinkedList的一些特有方法:
1 2 3 4
| >void addFirst(E e) >void addLast(E e) >E removeFirst() >E removeLast()
JAVA
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); list.add("三"); list.add("更"); list.add("草"); list.add("堂");
list.addFirst("["); list.addLast("]");
String s = list.removeFirst(); System.out.println(s); String s1 = list.removeLast(); System.out.println(s1); }
JAVA
|
3.3.3 遍历
同ArrayList。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); list.add("三"); list.add("更"); list.add("草"); list.add("堂");
String[] strings = list.toArray(new String[0]); for (int i = 0; i < strings.length; i++) { System.out.println(strings[i]); } }
JAVA
|
3.4 ArrayList和LinkedList的区别
都是实现了List接口,不同点是底层存储数据的数据结构不同。ArrayList底层是用数组来存储,而LinkedList是链表。所以各自的特点也和数据结构的特点一样。
ArrayList : 查找快,增删慢
LinkedList: 增删快,查找慢
集合-2
1. 常用Set集合
1.1 Set集合的特点
Set接口下的集合都会有以下特点
1.2 HashSet
HashSet集合的特点
- 底层数据结构是哈希表
- 存储元素的顺序和遍历获取出来的顺序可能不一致
- 没有索引
- 集合中不能存储重复元素
1.2.1 创建对象
1
| HashSet<元素数据类型> set = new HashSet<>();
JAVA
|
1 2 3
| public static void main(String[] args) { HashSet<String> set = new HashSet<>(); }
JAVA
|
1.2.2 常用方法
1 2 3 4
| >boolean add(E e) >boolean remove(Object o) >boolean contains(Object o) >int size()
JAVA
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static void main(String[] args) { HashSet<String> set = new HashSet<>(); boolean f = set.add("三"); set.add("更"); set.add("草"); set.add("堂");
boolean f2 = set.add("三");
boolean f3 = set.remove("三"); boolean f4 = set.remove("三");
boolean f5 = set.contains("更");
int size = set.size();
}
JAVA
|
1.2.3 遍历
1.转换为数组遍历
1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("三"); set.add("更"); set.add("草"); set.add("堂");
String[] strings = set.toArray(new String[0]); for (int i = 0; i < strings.length; i++) { System.out.println(strings[i]); } }
JAVA
|
2.使用迭代器遍历
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("三"); set.add("更"); set.add("草"); set.add("堂");
Iterator<String> it = set.iterator(); while (it.hasNext()){ String s = it.next(); System.out.println(s); } }
JAVA
|
3.foreach遍历
1 2 3 4 5 6 7 8 9 10 11
| public static void main(String[] args) { HashSet<String> set = new HashSet<>(); set.add("三"); set.add("更"); set.add("草"); set.add("堂");
for (String s : set) { System.out.println(s); } }
JAVA
|
2. 泛型
2.1 概述
泛型可以把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型 。
相当于把数据类型作为参数来进行传递。
注意:泛型只能是引用数据类型。
2.2 使用
2.2.1 泛型类&泛型接口
泛型类和泛型接口的用都相同,下面我们以泛型类为例进行讲解。
泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来 。
2.2.1.1 定义泛型
在类名后加<>,在<>中定义泛型,<>中的内容相当于泛型的名字,可以随便写。在泛型类中我们可以把这个泛型的名字当做一个数据类型来使用。
1 2 3
| public class TestClass<T> { }
JAVA
|
2.2.1.2 使用泛型
在泛型类中可以使用在类名后面定义的泛型。
1 2 3 4 5
| public class TestClass<T> { public void test(T t){ } }
JAVA
|
2.2.1.3 泛型的确定
①创建对象时确定
在创建泛型类对象的时候确定之前定义的泛型代表什么数据类型。在定义泛型类对象的时候,在类名的后加<>,在其中写一个具体的数据类型。
1 2 3 4
| public static void main(String[] args) { TestClass<String> t = new TestClass(); t.test("三更草堂"); }
JAVA
|
②定义子类时确定
在定义子类的时候可以确定泛型。具体用法如下:
1 2 3 4 5 6
| public class SubClass extends TestClass<String> { @Override public void test(String s) { } }
JAVA
|
这样在子类SubClass中泛型就确定为String类型了。
注意:我们在定义子类时也可以选择不确定泛型,让其在创建对象的时候在确定。写法如下
1 2 3 4 5 6
| public class SubClass<T> extends TestClass<T> { @Override public void test(T t) { super.test(t); } }
JAVA
|
2.2.2泛型方法
2.2.2.1 定义泛型
在方法返回值类型的前面加<>,在<>中定义泛型,<>中的内容相当于泛型的名字,可以随便写。在该泛型方法中我们可以把这个泛型的名字当做一个数据类型来使用。
1 2 3
| public static <T> T test(T t){ return t; }
JAVA
|
2.2.2.2 使用泛型
在泛型方法中可以使用定义的泛型。并且我们一般是在参数列表中或者是返回值类型上使用到这个泛型。
1 2 3
| public static <T> T test(T t){ return t; }
JAVA
|
2.2.2.3 泛型的确定
在调用泛型方法的时候才真正确定之前定义的泛型代表什么数据类型。在调用泛型方法的时候,程序会根据你的调用自动推导泛型的具体类型。
1 2 3 4
| public static void main(String[] args) { Integer test = test(1); String s = test("三更草堂"); }
JAVA
|
2.3 泛型上限&泛型下限
2.3.1 泛型限定的概念
我们在使用确定泛型的时候可以使用任意的引用数据类型去确定。但是在某些场景下我们要求这个泛型必须是某个类的子类或者是某个类的父类。这种情况下我们就需要用到泛型上限和泛型上限来限制泛型的范围。
2.3.1 泛型上限
限制泛型必须是某个类或者是其子类。
格式:
例如:
1 2 3
| public static void test(List<? extends Person> t){
}
JAVA
|
这样我们再调用test方法的时候只能存入泛型为Person或者是Person子类的List集合对象。
2.3.2 泛型下限
限制泛型必须是某个类或者是其父类。
格式:
例如:
1 2 3
| public static void test(List<? super Student> t){
}
JAVA
|
这样我们再调用test方法的时候只能存入泛型为Student或者是Student父类的List集合对象。
2.3.3 注意事项
1.泛型上限可以在定义泛型类和方法参数上使用
1 2 3 4
| public class Box<E extends Person> { E e; }
JAVA
|
2.泛型下限主要在方法参数上使用。
集合-3
1. 常用Map集合
1.1 Map集合的概述
Map接口是双列集合的顶层接口,下面是Map接口的定义
1
| interface Map<K,V> K:键的类型;V:值的类型
JAVA
|
存储的数据必须包含key和value。
key和value在Map集合中是一一对应的关系。一个key对应一个value。
key在map集合中是不会重复的。
1.2 HashMap
HashMap集合的特点
- 底层数据结构是哈希表
- 存储元素的顺序和遍历获取出来的顺序可能不一致
- key不会重复
1.2.1 创建对象
1
| HashMap<key的数据类型,value的数据类型> map = new HashMap<>();
JAVA
|
例如:
1 2 3 4
| public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); HashMap<String,Integer> map = new HashMap<>(); }
JAVA
|
1.2.2 常用方法
1 2 3 4 5 6
| >V put(K key, V value) >V get(Object key) >V remove(Object key) >boolean containsKey(Object key) >int size() >void clear()
JAVA
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void main(String[] args) { HashMap<String,String> map = new HashMap<>();
map.put("name", "三更"); map.put("age", "15"); String v = map.put("name", "三更草堂"); String name = map.get("name"); String age = map.get("age"); String delV = map.remove("age"); if(map.containsKey("name")){ String age111 = map.get("name"); System.out.println(age111.length()); } int size = map.size(); map.clear(); }
JAVA
|
1.2.3 遍历
1.使用entrySet遍历
map集合的entrySet方法可以获取一个Set集合,集合中存放的是Entry对象,一个Entry对象相当于一个键值对。我们可以遍历set集合拿到Entry对象,然后获取出里面的键和值。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); map.put("name","三更"); map.put("age","15");
Set<Map.Entry<String, String>> entries = map.entrySet(); Iterator<Map.Entry<String, String>> it = entries.iterator(); while (it.hasNext()){ Map.Entry<String, String> entry = it.next(); System.out.println(entry.getKey()+"===="+entry.getValue()); } }
JAVA
|
1 2 3 4 5 6 7 8 9 10 11
| public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); map.put("name","三更"); map.put("age","15"); Set<Map.Entry<String, String>> entries = map.entrySet(); for (Map.Entry<String, String> entry : entries) { System.out.println(entry.getKey()+"===="+entry.getValue()); } }
JAVA
|
2.使用keySet遍历
map集合的keySet方法可以获取一个Set集合,集合中存放的是所有的key。我们可以遍历set集合拿到key对象,然后通过key获取对应的value。
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) { HashMap<String,String> map = new HashMap<>(); map.put("name","三更"); map.put("age","15");
Set<String> keys = map.keySet(); for (String key : keys) { System.out.println(key+"===="+map.get(key)); } }
JAVA
|
1.3 HashMap的key去重原理
HashMap在添加元素的时候会判断集合中是否有key和本次存入的key相同。判断的时候主要是通过hashCode方法和equals方法来进行判断的。hashCode相同,并且equals判断也相同就会认为是同一个key。
image-20201205213813932
所以如果我们要存储到HashMap中的key是一个自定义的类型。就需要根据情况判断下是否需要重写下hashCode方法和equals方法。重写的时候使用IDEA的提示即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Student { private int age; private String name;
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); }
@Override public int hashCode() { return Objects.hash(age, name); } }
JAVA
|
注意:HashSet存储数据其实也是使用了HashMap。所以如果往HashSet中存储自定义对象也要看情况是否需要重写hashCode方法和equals方法。