Java集合框架
目录
- 集合的概念
- Collection接口
- Collection父接口
- List接口
- List实现类在这里插入代码片
- 泛型和工具类
- Set接口和实现类
- Map接口与实现类
- Collections工具类
1、什么是集合
1.1集合的概念
对象的容器,定义了多个对象进行操作的常用方法;可实现数组的功能
1.2集合和数组的区别
- 1 数组的长度固定,集合长度不固定
- 2 数组可以存储基本类型和引用类型,集合只能存储引用类型
2、 Collection体系结构:
3、 Collection父接口
- 特点:代表一组应以类型的对象,无序、无下标、不能重复
- 方法
- boolean add (0bject obj) //添加一个对象。
- boolean addAl1 (Collection c) //将一个集合中的所有对象添加到此集合中。
- void clear() //清空此集合中的所有对象。
- boolean contains (Object o) //检查此集合中是否包含0对象
- boolean equals (object o) //比较此集合是否与指定对象相等。
- boolean isEmpty () //判断此集合是否为空
- boolean remove (0bject o) //在此集合中移除0对象
- int size() //返回此集合中的元素个数。
- Object[] toArray() //将此集合转换成数组。
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add("西瓜");
collection.add("苹果");
collection.add("梨子");
System.out.println(collection.size());
System.out.println(collection);
for (Object o : collection) {
System.out.println(o);
}
System.out.println("---------------------");
Iterator it = collection.iterator();
while (it.hasNext()){
String s = (String) it.next();
System.out.println(s);
}
System.out.println(collection.contains("西瓜"));
System.out.println(collection.isEmpty());
}
4、List子接口
特点:有序、有下标、元素可以重复
- 有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。
方法:
- void add (int index, Object o) //在index位置插入对象0。
- boolean addAll (int index, Collection c) //将一个集合中的元素添加到此集合中的index位置。
- Object get (int index) //返回集合中指定位置的元素。
- List sublList (int fromIndex, int toIndex) //返回fromlndex和toIndex之间的集合元素。
public static void main(String[] args) {
List list = new ArrayList();
list.add("小米");
list.add(0,"华为");
list.add("水果");
System.out.println(list.toString());
list.remove(2);
System.out.println(list.toString());
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));
}
for (Object o : list) {
System.out.print(o);
}
System.out.println("_______________");
Iterator it = list.iterator();
while (it.hasNext()){
System.out.print(it.next());
}
ListIterator lt = list.listIterator();
while (lt.hasNext()){
System.out.println(lt.nextIndex()+":"+lt.next());
}
while (lt.hasPrevious()){
System.out.println(lt.previousIndex()+":"+lt.previous());
}
System.out.println(list.contains("华为"));
System.out.println(list.isEmpty());
System.out.println(list.indexOf("华为"));
}
4.1、数字及subLIst
public static void main(String[] args) {
List list = new ArrayList();
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.add(60);
System.out.println(list.toString());
System.out.println(list.toString());
List sublist = list.subList(1,3);
System.out.println(sublist.toString());
}
5、List实现类
- ArrayList(重点)
- 数组结构实现,查询快、增删慢
- jdk1.2版本,运行效率快、线程不安全
- Vector
- 数组结构实现,查询快、增删慢
- jdk1.0版本,运行慢,线程安全
- LinkedList(常用)
- 链表结构实现,增删快,查询慢
- 链表首先有个head元素,添加元素,第一个就指向第二个元素以此类推
5.1、ArrayList(重点)
- 数组结构实现,查询快、增删慢
- 没有向集合中添加元素时,容量为0
- //数组容量超过10以后再添加元素,就扩容到原来的1,5倍,
int newCapacity = oldCapacity + (oldCapacity >> 1);
例子
public static void main(String[] args) {
Student s1 = new Student("张三",22);
Student s2 = new Student("李四",22);
Student s3 = new Student("麻子",22);
ArrayList arr = new ArrayList<>();
arr.add(s1);
arr.add(s2);
arr.add(s3);
System.out.println(arr.toString());
System.out.println("_____________");
System.out.println(arr.toString());
System.out.println("_____________");
Iterator it = arr.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("_____________");
ListIterator lit = arr.listIterator();
while (lit.hasNext()){
System.out.println(lit.next());
}
System.out.println(lit.nextIndex());
System.out.println("_____________");
System.out.println(lit.previousIndex());
while (lit.hasPrevious()){
System.out.println(lit.previous());
}
}
ArrayList源码
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
elementData[size++] = e;
int newCapacity = oldCapacity + (oldCapacity >> 1);
5.2、Vector集合(不常用)
Vector 类实现了可扩展的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector 的大小可以根据需要增长或缩小,以适应在创建Vector 之后添加和删除项目。
public static void main(String[] args) {
Vector vt = new Vector<>();
vt.add("苹果");
vt.add("草莓");
vt.add("西瓜");
System.out.println(vt.size());
Enumeration en = vt.elements();
while (en.hasMoreElements()){
System.out.println(en.nextElement());
}
System.out.println(vt.contains("西瓜"));
System.out.println(vt.isEmpty());
vt.firstElement();
vt.lastElement();
vt.elements();
}
5.3、LinkedList
LinkedList(常用)
- 链表结构实现,增删快,查询慢,双向链表
- 链表首先有个head元素,添加元素,第一个就指向第二个元素以此类推
常用方法
public static void main(String[] args) {
Student s1 = new Student("张三",22);
Student s2 = new Student("李四",22);
Student s3 = new Student("麻子",22);
LinkedList linkedList = new LinkedList<>();
linkedList.add(s1);
linkedList.add(s3);
linkedList.add(s2);
System.out.println(linkedList.toString());
ListIterator lt = linkedList.listIterator();
while (lt.hasNext()){
System.out.println(lt.next().toString());
}
System.out.println(linkedList.contains(s1));
System.out.println(linkedList.isEmpty());
System.out.println(linkedList.indexOf(s1));
}
LinkedList 源码
- size = 0
- first 头 last 尾
- 前一个指向后一个,后一个指向前一个
public LinkedList() {
}
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
5.4 ArrayList和LinkedList的区别
- LinkedList
- 查询慢:需要从头或从尾一个个找
- 删除快:删除一个元素,只需要改变指向关系就可以了
5.5、小问题
列表迭代器ListIterator
- nextIndex()默认是0,previousIndex() : nextIndex()-1 = -1
- 直接逆遍历需要先把遍历一次,让nextIndex()到最后一位
ListIterator lit = arr.listIterator();
while (lit.hasNext()){
System.out.println(lit.next());
}
System.out.println(lit.nextIndex());
System.out.println(lit.previousIndex());
while (lit.hasPrevious()){
System.out.println(lit.previous());
}
System.out.println(lit.nextIndex());
System.out.println("_____________");
System.out.println(lit.previousIndex());
while (lit.hasPrevious()){
System.out.println(lit.previous());
}
6、泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法。
- 语法:
- .<T,…> T称为类型占位符,表示一种引用类型。
- 好处:
- (1)提高代码的重用性:比如传递时可以传递任意类型的参数
- (2)防止类型转换异常,提高代码的安全性
6.1、泛型类
- 语法,类名
- T是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开
- 泛型只能使用引用类型
- 不同泛型类型对象之间不能相互赋值
public class MyGeneric<T> {
T t;
public void show(T t){
System.out.println(t);
}
public T getT() {
return t;
}
}
public static void main(String[] args) {
MyGeneric<String> myGeneric = new MyGeneric<String>();
myGeneric.t = "hello";
myGeneric.show("大家好");
String str = myGeneric.getT();
System.out.println(str);
MyGeneric<Integer> myGeneric1 = new MyGeneric<Integer>();
myGeneric1.t = 100;
myGeneric1.show(200);
Integer integer = myGeneric1.getT();
System.out.println(integer);
}
6.2、泛型接口
- 定义泛型接口,接口名
- 注意:不能用泛型创建常量
- 实现类
- 1:可以在实现类上泛型直接指定类型,方法使用对应类型
- 2:实现类泛型不指定类型,使用的时候再指定
例子:
public interface MyInterface<T> {
String name = "张三";
T server(T t);
}
public class MyInterfaceImpl implements MyInterface<String> {
@Override
public String server(String t) {
System.out.println(t);
return t;
}
}
public class MyInterfaceImpl2<T> implements MyInterface<T> {
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
public static void main(String[] args) {
MyInterfaceImpl impl1 = new MyInterfaceImpl();
impl1.server("ttttttttttttt");
MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>();
impl2.server(2020);
}
6.3、泛型方法
- 语法,方法返回值类型前加:public void show(){}、
- 传递的类型是由传递的值决定
public <T> T show(T t){
System.out.println("泛型方法"+t);
return t;
}
MyGenericMethod mg = new MyGenericMethod();
mg.show(222);
mg.show("行啊");
6.4、泛型集合
概念:
- 参数化类型、类型安全的集合,强制集合元素的类型必须一致
特点:
- 编译时即可检查,而非运行时抛出异常
- 访问时,不需要类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList();
arrayList.add("aaa");
arrayList.add("bbb");
for (String s : arrayList) {
String ss = s;
System.out.println(ss);
}
Student s1 = new Student("aaa",11);
Student s2 = new Student("bbb",22);
ArrayList<Student> arrayList1 = new ArrayList<>();
arrayList1.add(s1);
arrayList1.add(s2);
Iterator<Student> it = arrayList1.iterator();
while (it.hasNext()){
Student st = it.next();
System.out.println(st);
}
}
7、Set子接口
特点:
方法:
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("苹果");
set.add("西瓜");
set.add("香蕉");
System.out.println(set.toString());
for (String s : set) {
System.out.println(s);
}
Iterator<String> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
7.1、Set实现类(HashSet)
public static void main(String[] args) {
HashSet<Person> hashSet = new HashSet<>();
Person s1 = new Person("张三",11);
Person s2 = new Person("麻子",22);
Person s3 = new Person("蓝色",33);
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(new Person("张三",11));
System.out.println(hashSet);
hashSet.remove(new Person("张三",11));
}
7.2、TreeSet
特点:
- 基于排序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age-o.getAge();
return n1==0?n2:n1;
}
public class Demo2 {
public static void main(String[] args) {
TreeSet<Person> person = new TreeSet<>();
Person p1 = new Person("xyz",18);
Person p2 = new Person("aaa",33);
Person p3 = new Person("ddd",22);
Person p4 = new Person("ddd",20);
person.add(p1);
person.add(p2);
person.add(p3);
person.add(p4);
System.out.println(person);
person.remove(new Person("ddd",20));
}
自定义比较规则
public static void main(String[] args) {
TreeSet<Person> ts = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge()-o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1 == 0 ? n2:n1 ;
}
});
Person p1 = new Person("xyz",18);
Person p2 = new Person("aaa",33);
Person p3 = new Person("ddd",22);
Person p4 = new Person("ddd",20);
ts.add(p1);
ts.add(p2);
ts.add(p3);
ts.add(p4);
System.out.println(ts);
}
public static void main(String[] args) {
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1 = o2.length()-o1.length();
int n2 = o1.compareTo(o2);
return n1==0 ? n2:n1;
}
});
ts.add("sidfhkajlsdhfj");
ts.add("aaas");
ts.add("bbb");
ts.add("cccds");
ts.add("caaas");
System.out.println(ts);
}
8、Map集合
8.1、Map父接口
特点:
- 存储一对数据(Key-Value),无序、无下标,键不可重复,值可以重复
方法:
- V put (K key, V value) //将对象存入到集合中,关联键值。key重复则覆盖原值。
- Object get (object key) //根据键获取对应的值。
- KeySet //返回所有key。
- Collection values () //返回包含所有值的Collection集合。
- Set<Map. Entry<K, V>> //键值匹配的Set集合。
- entrySet() 返回此映射中包含的映射关系的Set视图。
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("pg","苹果");
map.put("xg","西瓜");
map.put("xj","香蕉");
System.out.println(map.size()+":"+map);
for (String s1 : map.keySet()) {
System.out.println(s1+":"+map.get(s1));
}
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
System.out.println(map.containsValue("西瓜"));
System.out.println(map.isEmpty());
}
8.1、HashMap*
基于哈希表的实现的Map 接口。 此实现提供了所有可选的地图操作,并允许null的 值和null 键。 ( HashMap 类大致相当于Hashtable ,除了它是不同步的,并允许null)。这个类不能保证地图的顺序; 特别是,它不能保证订单在一段时间内保持不变。
public static void main(String[] args) {
HashMap<Student,String> hm = new HashMap<>();
Student s1 = new Student("孙悟空",100);
Student s2 = new Student("猪八盖",101);
Student s3 = new Student("沙僧",102);
hm.put(s1,"贵阳");
hm.put(s2,"金阳");
hm.put(s3,"火车站");
hm.put(new Student("沙僧",102),"北站");
System.out.println(hm.size()+":"+hm);
for (Student student : hm.keySet()) {
System.out.println(student+":"+hm.get(student));
}
for (Map.Entry<Student, String> studentStringEntry : hm.entrySet()) {
System.out.println(studentStringEntry.getKey()+":"+studentStringEntry.getValue());
}
}
HashMap小结:
- 刚创建集合时集合的长度为0,(节省空间)
- (put)添加数据时集合长度调整为16(0-15)
- 当数据个数达到阈值(16*0.75)12时,扩容为原来的两倍,32(16的二倍)
- jdk1.8当每个链表长度大于8,并且元素个数大于等于64时,会调整为红黑树,日的提高执行效率
- jdk1.8当链表长度小于6时,调整成链表
- jdk 1.8以前,链表时头插入, jdk1.8以后时是尾插入
HashMap和HashSet
- HashSet实际上使用的是HashMap的Key
8.2、Hashtable和Properties
- JDK1.0版本,线程安全,运行效率慢,键值不允许为null
- 子类:Properties
8.3、TreeMap
public static void main(String[] args) {
TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n1 = o1.getStuNo()-o2.getStuNo();
return n1;
}
});
Student s1 = new Student("孙悟空",100);
Student s2 = new Student("猪八盖",101);
Student s3 = new Student("沙僧",102);
tm.put(s1,"北京");
tm.put(s2,"上海");
tm.put(s3,"深圳");
System.out.println(tm.size()+":"+tm);
tm.put(new Student("沙僧1",102),"南京");
System.out.println(tm.size()+":"+tm);
for (Student student : tm.keySet()) {
System.out.println(student+":"+tm.get(student));
}
for (Map.Entry<Student, String> entry : tm.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
TreeSet 和TreeMap
9、Collections工具类
概念:
- 集合工具类,定义了除了存取以外的集合常用方法。
- 方法:
- public static void reverse(List<?> list) //反转集合中元素的顺序
- public static void shuffle(List<?> list) //随机重置集合元素的顺序
- public static void sort (List list) //升序排序(元素类型必须实现Comparable接口)
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(22);
list.add(5);
list.add(2);
list.add(44);
list.add(11);
Collections.sort(list);
System.out.println(list);
int i = Collections.binarySearch(list,444);
System.out.println(i);
List<Integer> list1 = new ArrayList<>();
for (int j = 0; j < list.size(); j++) {
list1.add(0);
}
Collections.copy(list1,list);
System.out.println(list1);
Collections.reverse(list);
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
}
数组集合转换
Integer[] it = list.toArray(new Integer[0]);
System.out.println(it.length+":"+ Arrays.toString(it));
String[] names = {"aaa","bbb","ddd","FFF"};
List<String> list2 = Arrays.asList(names);
System.out.println(list2);
Integer[] nums = {111,222,33,44,55};
List<Integer> integers = Arrays.asList(nums);
System.out.println(integers);
小问题
|