13.1 概念
以前存储一组相同类型的数据使用数组,固定大小,具有连续性的存储空间。比如,5个长度的数组再存入数据时,如果现在已经存满,存入第六个元素,这时数组空间不够,扩容。Arrays.copyOf() , 很不方便,如果扩容频率太高,也影响你程序运行效率。集合来解决数组固定,如果扩容又影响效率的问题
UML图 类图
实线三角形是继承关系
虚线三角形是实现关系
箭头关联关系(结合两张图片,大概的了解一下)
iterator 迭代器对象,是所有集合类的父接口
重点
Vector 线程安全
List线路:
- Collection 接口
- List,Set,Queue接口
- HashSet 类 ArrayList 类 LinkedList 类
Map线路:
- HashMap 类 k-v 键值对
- 下图是总结,各个数据结构底层
图一:
图二:
13.2 ArrayList集合(底层是数组)
ArrayList是数组的原理,一组连接性且具体相同类型的存储空间,没有长度的限制(扩容--扩容机制),它用解决不确定数量的元素的存储。
构造方法:
构造方法 | 案例 |
ArrayList() | 创建一个初始长度为0的集合对象 |
| ArrayList list=new ArrayList(newList) 用newList的元素去初始化list |
| ArrayList list=new ArrayList(5) 调用一个初始的数组的存储容量 |
通过源码查看,构造方法案例ArrayList()并没有对数据数组分配长度,给的是一个为0个元的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //默认的0个元素的空数组
transient Object[] elementData; //集合存放数据的数组
public ArrayList() {
//1、当new ArrayList的时候长度为0但到的是一个空数组
//2、集合的底层数组储存结构是数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
ArrayList中的API (每个API都练一遍)
API | 说明 | |
boolean | 向集合中添加一个元素 | list.add("hello"); |
void | 向指定位置插入一个元素 | list.add(1,"word") |
Object get(int index) | 根据指定的下标取出对应的元素,一般要配合循环使用 | list.get(1) |
| 将一个集合添加到另一个集合中 | list.addAll(newList) |
clear() | 清除集合中所有的元素 | list.clear() |
clone() | 对集合元素进行克隆 | ArrayList newList=(ArrayList)list.clone(); |
| 判断指定元素在集合中是否存在,存在返回true,不存在返回false | list.contains("王政"); |
| 循环迭代集合中的元素 | list.forEach(System.out::println) |
| 判断指定元素在集合中是否存在,找到返回下标,找不到返回-1 | list.indexOf("王政"); -1 |
| 集合是空返回true,集合非空返回false | list.isEmpty(); |
| 返回迭代器对象 iterator.hasNext() 判断指针的下一个元素是否存iterator.next()指针向下移动后并获出当前元素的值 | Iterator iterator = students.iterator(); |
| 从后向前判断指定元素在集合中是否存在,找到返回下标,找不到返回-1 | |
| 根据下标删除元素 | list.remove(1); |
| 根据元素对去删除集合中的元素,要保证删除指定的元素对象与集合中存放的元素对象是同一对象,内存地址一样。 | list.remove("张鹏");list.remove(new Student(1,"张鹏")); new重新分配了地址,与元素不是同一对象,删除不了 |
| 在指定下标位修改元素,直接修改覆盖 | students.set(2,"陈朋");将下标2的元素修改为陈朋 |
| 获取列表中元素的个数 | list.size() |
| 对集合进行排序操作,参数是一个Comparator比较器 | list.sort(new StudentComparator()); |
toArray() | 将一个集合转换成一个数组 | Object[] objects = students.toArray();转换的数组是什么类型取决于集合给的什么类型,像这样集合没有给具体的类型就是Object类型 |
集合的循环访问:
//size()的案例
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
//使用size来循环集合中的元素
for (int i=0;i<students.size();i++ ) {
System.out.println(students.get(i));
}
}
}
//第二种,foreach方式来访问
ArrayList students=new ArrayList();//这样创建出来的集合元素的类型就是Object
for (Object o:students) {
System.out.println(o);
}
//第三种,迭代器形式
// students.iterator() 获取一个Iterator对象
Iterator iterator = students.iterator();
//iterator.hasNext() 判断指针指向后一个元素是否存在数据,存在返回true,不存在返回false
while (iterator.hasNext()){
//iterator.next() 真正将指针向后一个元素进行移动,并获取指向元素的值
System.out.println(iterator.next());
}
students.forEach(System.out::println);
addAll(List list)
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
ArrayList newList= new ArrayList();
newList.add("陶治");
newList.add("浩楠哥");
newList.add("王政");
//成批量的将一个集合内容添加到另一个集合中
students.addAll(newList);
students.forEach(System.out::println);
}
}
clear清除集合中所有的元素
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
ArrayList newList= new ArrayList();
newList.add("陶治");
newList.add("浩楠哥");
newList.add("王政");
//成批量的将一个集合内容添加到另一个集合中
students.addAll(newList);
System.out.println(students.size());
System.out.println("=====================清除后======================");
students.clear();//清除
System.out.println(students.size());
}
}
clone()
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
ArrayList newStudents=(ArrayList) students.clone();
newStudents.forEach(System.out::println);
}
}
contains查找某元素在集合中是否存在
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
System.out.println(students.contains("王政")); //false
System.out.println(students.contains("沈查")); //true
}
}
forEach(Consumer<T> action); //Consumer接口
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
students.add("张跃成");
/*for (Object o:students) {
String str=o.toString();
if(str.startsWith("张")){
System.out.println(str);
}
}*/
/**
当前这个结构与上面的for是一样的道理这里的o就是迭代变量, ->因定写法,{ }中就是上面for的{}
*/
students.forEach(o -> {
String str=o.toString();
if(str.startsWith("张")){
System.out.println(str);
}
});
}
}
indexOf(值)查找元素在集合中是否存在,找到返回下标,找不到返回-1
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
students.add("张跃成");
System.out.println(students.indexOf("张鹏"));
System.out.println(students.indexOf("王政"));
}
}
isEmpty() 集合空返回true,非空返回false
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
System.out.println(students.isEmpty());//true
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
students.add("张跃成");
System.out.println(students.isEmpty());//false
}
}
remove(index) 根据下标删除
remove(Object) 根据对象删除
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
students.add("张跃成");
System.out.println("第一次删除");
students.remove(1);//删除元素下标为1的值
students.forEach(System.out::println);
System.out.println("第二次删除");
students.remove("蔡金恩"); //根据元素在再删除数据 这里容易迷惑
students.forEach(System.out::println);
}
}
public class Main1 {
public static void main(String[] args) {
ArrayList list=new ArrayList();
list.add(new Student(1,"谢兴灵"));
list.add(new Student(2,"张鹏"));
list.add(new Student(3,"冯小龙"));
list.add(new Student(4,"蔡金恩"));
list.add(new Student(5,"浩楠哥"));
//list.remove(new Student(4,"蔡金恩"));//这样删除不了,因为重新new了就不再是同一对象
list.remove(list.get(3));//这样才能删除 先去集合中取出对象,再删除。
System.out.println(list);
}
static class Student{
private Integer id;
private String name;
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
}
set(int index,Object e);修改指定下标的元素
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add(3,"沈查");
students.add("张跃成");
students.set(2,"陈朋");
students.forEach(System.out::println);
}
}
sort(Comparator<? super E> c) 对集合元素进行排序
public class Main1 {
public static void main(String[] args) {
ArrayList list=new ArrayList();
list.add(new Student(18,"谢兴灵"));
list.add(new Student(12,"张鹏"));
list.add(new Student(33,"冯小龙"));
list.add(new Student(24,"蔡金恩"));
list.add(new Student(15,"浩楠哥"));
list.sort(new StudentComparator()); //开始排序
list.forEach(System.out::println);
}
}
//实现Comparator比较器
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getId()-o2.getId();
}
}
toArray() 将集合转换成数组
public class Main {
public static void main(String[] args) {
ArrayList students=new ArrayList();
students.add("谢兴灵");
students.add("张鹏");
students.add("冯小龙");
students.add("蔡金恩");
students.add("王浩月");
students.add("张跃成");
Object[] objects = students.toArray();
}
}
13.3 LinkedList 集合
语法: LinkedList list=new LinkedList ();
LinkedList 非线程安全,链表做为底层实现。ArrayList也是非线程安全,使用的是数组做为底层实现。
public class Main2 {
public static void main(String[] args) {
List<Integer> list=new LinkedList<>();
//同时开启30个线程,每个线程向集合填入一个数,这时就会出资源争抢,从而引发异常
for (int i = 1; i <= 30 ; i++) {
final int j=i;
new Thread(()->{
list.add(j);
System.out.println(list);
}).start();
}
}
}
数组:
1、我们以后的使用习惯会经常使用ArrayList。用它来进行数据运输工作。
2、ArrayList是一组连接性的存储空间,好处查找方便。查找效率比较高,但是插入效率比较低。
链表:
1、不是连续性存储单元,每个对象之间有一个关联关系,插入的只需要修改相邻两个对象之间的关联关系就好了,所以插入的效率比较高
2、链表是以碎片形式在内存中存在,它的查找效率就比较低
13.4 HashSet
hashSet 无序列表(不允许排序)。ArrayList底层由数组实现,数组是一组有序的存储空间,LinkedList由链表实现,链表也有顺序关联。HashSet没有顺序可言,就没有下标的概念,并且HashSet中不允许出现重复的数据。
构造方法
方法 | 说明 | 案例 |
| 构造一个新的空集合 | Set set=new HashSet() |
| 用一个集合来构造一个新的Set | Set set = new HashSet(list) |
常用API
方法名 | 说明 | |
add(E e) | 向Set集合中添加一个元素 | set.add("张鹏") |
size() | 返回set集合中元素的个数 | set.size(); |
clear() | 清空set集合中所有元素 | set.clear() |
isEmpty() | 判断set集合是否有元素存在,没有返回true,有返回false | set.isEmpty() |
remove(E e) | 删除set集合中的元素,只能根据对象去删除元素 | set.remove(e) |
contains(E e) | 判断set集合某个元素是否存在 | set.contains(e) |
注意set集合不能使用for(int i=0;i<set.size();i++){}结构来对set进行循环拿值,只能使用迭代器的形式。
public class Main6 {
public static void main(String[] args) {
Set<String> set=new HashSet<>();
set.add("张鹏");
set.add("谢兴灵");
set.add("冯小龙");
set.add("蔡金恩");
System.out.println(set.isEmpty());
set.remove("张鹏");
System.out.println(set.contains("张鹏"));
set.clear();
for (String s: set) {
System.out.println(s);
}
}
}
有一堆同学的姓名,这一堆同学的姓名中可能会有重复的,要求将重复的姓名删除,只保留一个(去重)。
public class Main6 {
public static void main(String[] args) {
Set<String> set=new HashSet<>();
set.add("张鹏");
set.add("谢兴灵");
set.add("冯小龙");
set.add("蔡金恩");
set.add("张鹏");//重复姓名
set.add("谢兴灵");
for (String s: set) {
System.out.println(s);
}
}
}
结果:
张鹏
冯小龙
谢兴灵
蔡金恩
结论:添加重复的内容不会报错,但是添加不成功。
解决方案:
public class Main6 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("张鹏");
list.add("谢兴灵");
list.add("冯小龙");
list.add("蔡金恩");
list.add("张鹏");
list.add("谢兴灵");
Set<String> set=new HashSet<>(list);
for (String s: set) {
System.out.println(s);
}
}
}
HashSet底层用什么实现,HashMap,如何实现。map--> key - value 键值对map.put(key, value),HashSet添加时会将值存入到map的键中,而map的中的值使用的是一个Object类型的常量。所有的add添加都使用这个固定常量。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
13.5 TreeSet
可排序的列表,TreeSet会对内部的值进行自然排序
public class Main6 {
public static void main(String[] args) {
Set<Integer> set=new TreeSet<>();
set.add(53);
set.add(19);
set.add(77);
set.add(8);
set.add(100);
set.add(100);//重复数据
for (Integer s: set) {
System.out.println(s);
}
}
}
结果:
8
19
53
77
100
public class Main6 {
public static void main(String[] args) {
Set<Student> set=new TreeSet<>();
set.add(new Student(18, "张鹏"));
set.add(new Student(99, "谢兴灵"));
set.add(new Student(37, "冯小龙"));
set.add(new Student(56, "蔡金恩"));
set.forEach(System.out::println);
}
}
运行结果
Exception in thread "main" java.lang.ClassCastException: com.qf.entitys.Student cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1290)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
at Main6.main(Main6.java:9)
结论,因为TreeSet会自然排序,普通的类直接丢进TreeSet中会报错, 解决方案,Student中实现Comparable接口。
package com.qf.entitys;
public class Student implements Comparable<Student> {
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Student o) {
return this.getId()-o.getId();
}
}
重写之后,上面的调用代码可正常运行了。
13.6 HashMap 重点
HashMap是以Key(键)--Value(值) 通过Key去寻找对应的值,江湖简称K-V键值对。例如,家庭地址(键),520平米的大平层就是(值),通过标识(家庭地址)可以寻找到你的家的那片空间。
语法:
Map<键的类型,值的类型> maps=new HashMap<>();
Map<String,Integer> maps=new HashMap<>();
HashMap 底实现 数组+链表(哈希表)+红黑树(二叉树的一种)
构造方法:
方法名 | 说明 |
HashMap() | 构造一个空的 |
HashMap(int initialCapacity) | 构造一个空的 |
HashMap(int initialCapacity, float loadFactor) | 构造一个空的 |
HashMap(Map<? extends K,? extends V> m) | 构造一个新的 |
负载系数说的是如果这个默认长度为16的数组元素存储率到达75%的时候,需要重新创建数组扩容再来存放数据。一般使用HashMap()默认的就够了。
API:
方法名 | 说明 | 案例 |
put(K key, V value) | 将指定的值与此映射中的指定键相关联 | maps.put("zhangsan","张三"); |
get(Object key) | 返回到指定键所映射的值 | maps.get("zhangsan"); |
entrySet() | 返回此Map中包含的映射的Set的集合,返回的是Map.Entry这样的一个类型的Set,Set<Map.Entry<K,V>> | Set<Map.Entry<K,V>> set=maps.entrySet(); |
keySet() | 返回此Map中包含的映射的Set的集合,返回的是Set<K> | Set<String> key=maps.keySet() |
values() | 返回此Map中所有值的集合 | Collection<V> list=maps.values() |
isEmpty() | Map中没有元素返回true,否则返回false | maps.isEmpty() |
containsKey(Object key) | 判断map中指定的键是否存在,存在返回true,不存在返回false | maps.containsKey("zhangsan")true |
containsValue(Object value) | 判断map中指定的值是否存在,存在返回true,不存在返回false | maps.containsValue("张三")true |
putAll(Map<? extends K,? extends V> m) | 将另一个map添加到本map中 | maps.putAll(oldMap); |
remove(Object key) | 根据key 删除元素 | maps.remove("zhangpeng") |
remove(Object key,Object value) | 根据key和value删除元素,key和value要与元素中的一致才能删除 | names.remove("zhangpeng","谢兴灵");删除不掉names.remove("zhangpeng","张鹏");删除了 |
size() | 返回map的元素个数 | maps.size() |
clear() | 清空这个map | maps.clear() |
- Map.Entry<K,V> 这个接口是就键-值对的对象 这个接口中提供了
方法名 | 说明 |
K getKey(); | 获取当前键值对中的键 |
V getValue(); | 获取当前键值对中的值 |
public class Main10 {
public static void main(String[] args) {
Map<String,String> names=new HashMap<>();
names.put("zhangsan","张三");
names.put("lisi","李四");
names.put("wangwu","王武");
names.put("zhuliu","朱牛");
names.put("zhaoqi","赵妻");
//names Map中存入的是多个键值对,所以拿出来的Entry对象也应该是多个,Set<Map.Entry<String, String>>
Set<Map.Entry<String, String>> entries = names.entrySet();
for (Map.Entry e: entries) {
System.out.println(e.getKey()+"--------------"+e.getValue());
}
}
}
keySet() 返回键的集合 Set<K>
//keySet() 返回键的集合 Set<K>
Set<String> keys = names.keySet();
for (String k: keys) {
//拿到了键就可以通过 get方法拿值
System.out.println(k+"--------------"+names.get(k));
}
values() 获取所有值的集合
Collection<String> values = names.values();
for (String v: values) {
System.out.println(v);
}
完整案例:
import java.util.*;
public class Main10 {
public static void main(String[] args) {
Map<String,String> names=new HashMap<>();
names.put("zhangsan","张三");
names.put("lisi","李四");
names.put("wangwu","王武");
names.put("zhuliu","朱牛");
names.put("zhaoqi","赵妻");
//第一种迭代
Set<Map.Entry<String, String>> entries = names.entrySet();
for (Map.Entry e: entries) {
System.out.println(e.getKey()+"--------------"+e.getValue());
}
//第二种迭代
Set<String> keys = names.keySet();
for (String k: keys) {
System.out.println(k+"--------------"+names.get(k));
}
//第三种迭代
Collection<String> values = names.values();
for (String v: values) {
System.out.println(v);
}
}
}
putAll(oldMap)
Map<String,String> oldMap=new HashMap<>();
//HashSet存储时值是存在HashMap的键中 HashSet不允许有重复值
oldMap.put("zhangpeng","张鹏");
//oldMap.put("zhangpeng","谢兴灵");//如果键重复值就是后面的覆盖前面的
oldMap.put("xiexingling","谢兴灵");
Map<String,String> names=new HashMap<>();
names.put("zhangsan","张三");
names.put("lisi","李四");
names.put("wangwu","王武");
names.put("zhuliu","朱牛");
names.put("zhaoqi","赵妻");
names.putAll(oldMap);
names.keySet().forEach(System.out::println);
System.out.println("=======================");
names.values().forEach(System.out::println);
在项目中时,多数情况下,Map中的值是一个类的对象,Map中的键是这个类唯一能代表这个人的属性
public class Main10 {
public static void main(String[] args) {
//唯一的属性会作为键存在
Map<Integer, Student> stuMap=new HashMap<>();
Student stu1=new Student(1,"张鹏");
Student stu2=new Student(2,"谢兴灵");
Student stu3=new Student(3,"冯小龙");
Student stu4=new Student(4,"蔡金恩");
Student stu5=new Student(5,"陈朋");
stuMap.put(stu1.getId(),stu1);
stuMap.put(stu2.getId(),stu2);
stuMap.put(stu3.getId(),stu3);
stuMap.put(stu4.getId(),stu4);
stuMap.put(stu5.getId(),stu5);
System.out.println(stuMap.get(3).getName());
}
}
13.7 HashTable 和 TreeMap
这两个的操作API与HashMap一样
1、HashTable: jdk1.1版本就出现的一个东西,它内部实现使用的是数组+链表
2、TreeMap , HashMap没办法排序,如果想要对元素进行自然排序的时候就使用TreeMap;
13.8 Collections工具类
Collections内部提供了很多的方法对集合进行操作:
addAll(list, T...element),将多个元素添加到集合中.
List<String> list=new ArrayList<>();
Collections.addAll(list,"张鹏","谢兴灵","冯小龙");
System.out.println(list);
binarySearch(List<? extends Comparable<? super T>> list, T key)
List<String> list=new ArrayList<>();
Collections.addAll(list,"张鹏","谢兴灵","冯小龙");
System.out.println(Collections.binarySearch(list, "谢兴灵"));
System.out.println(list);
emptyList() emptySet() emptyMap() 返回一个空的不可变的集合
List<Object> objects = Collections.emptyList();
objects.add("张三");
System.out.println(objects.get(0));
返回的是一个不可变的List所以无法对返回的结果的元素进行改变,用处再于某一个方法的返回值如果有可能为null的时候用这个东西来替换。
fill(List<? super T> list, T obj)
List<String> list=new ArrayList();
list.add("张鹏");
list.add("谢兴灵");
Collections.fill(list,"冯小龙");
System.out.println(list);
//会将集合中所有的元素都替换为冯小龙
max(Collection<? extends T> coll)
min(Collection<? extends T> coll)
List<String> list=new ArrayList();
list.add("张鹏");
list.add("谢兴灵");
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
如果两个自定义对象要比较的话必须要实现Comparable
reverse(List<?> list) 反向排序元素的位置
List<String> list=new ArrayList();
list.add("张鹏");
list.add("谢兴灵");
list.add("冯小龙");
System.out.println(list);
System.out.println("===================================");
Collections.reverse(list);
System.out.println(list);
shuffle(List<?> list) 随机排列元素的位置
List<String> list=new ArrayList();
list.add("张鹏");
list.add("谢兴灵");
list.add("冯小龙");
System.out.println(list);
System.out.println("===================================");
Collections.shuffle(list);
System.out.println(list);
sort(List<T> list) 对元素进行排序
List<Integer> list=new ArrayList();
list.add(53);
list.add(45);
list.add(49);
System.out.println(list);
System.out.println("===================================");
Collections.sort(list);
System.out.println(list);
swap(List<?> list, int i, int j) 交换指定位置上的元素
List<Integer> list=new ArrayList();
list.add(53);
list.add(45);
list.add(49);
Collections.swap(list,0,2);
System.out.println(list);
synchronizedList(List<T> list)
synchronizedSet(Set<T> set)
synchronizedMap(Map<K,V> m)
用当前的集合构造一个线程安全的集合对象
public static void main(String[] args) {
List<Integer> list=Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i <= 30 ; i++) {
final int j=i;
new Thread(()->{
list.add(j);
System.out.println(list);
}).start();
}
}
13.9 泛型
泛型,一般在类上进行定义可以用于全类的范围,如果在方法上定义只能在方法中使用
泛型就是使用一个任意命名的替代符去代替即将使用的类型,这是一种抽象概念。
约定俗成:
E entity-->实体的意思
K key--> 键
V value-> 值
T target-> 目标对象
public class 类名<E>{
}
这里的E是一个类型,具体。是什么类型要在创建这个对象的时候才去指定。 var i="123"; var i=1; var i=3.14;
public class MyList<E> implements List<E> { //这里是对泛型的定义 E 可以随机写 一般大写单个字母
@Override
public boolean add(E e) { // E 上面定义的泛型,现在不知道什么类型,等对象创建的时候给定具体的类型
return false;
}
}
public class Main2 {
public static void main(String[] args) {
List<Student> list=new MyList<>(); //创建MyList对象,给定了一个Student,E就是Student.
list.add(new Student(1,"张鹏"));//调用add方法只能传Student数据进去
}
}
泛型写在方法上时
public <T> void 方法名(T t){
}
public class MyList<E> {
public void add(E e){
System.out.println(e);
}
//参数给什么值 T就代表什么类型
public <T> void show(T t){
System.out.println(t);
}
}
public class Main2 {
public static void main(String[] args) {
MyList<Integer> list=new MyList<>();
list.add(12);
list.show(1);//T int
list.show(3.14);// T double
list.show("helloworld");//T String
}
}
无界,上界,下界
private static class MyList{
public <T> void show(T t){
System.out.println(t);
}
//无界 List<?> list 所有类型的集合都接收
//List<?>=List<Object>
public void show1(List<?> list){
System.out.println(list);
}
//上界 List<? extends 父类> list 父类及所有子类的集合接收
public void show2(List<? extends Number> list){
System.out.println(list);
}
//下界 List<? super 类名> list 只接收指定类名的集合
public void show3(List<? super Number> list){
System.out.println(list);
}
}