集合框架
Java集合框架详解
集合的概念
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
- 和数组的区别
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型(要使用基本类型可以对其进行装箱操作)
- 位置:java.util.*;
Collection接口
//创建集合,接口本身不能被实例化,new实现该接口的类
Collection collection = new ArrayList();
//添加元素
collection.add("苹果");
collection.add("香蕉");
collection.add("榴莲");
System.out.println("元素个数为:"+collection.size());
System.out.println(collection.toString());
//删除元素
collection.remove("榴莲");
System.out.println("删除后元素个数为:"+collection.size());
//遍历元素,不能使用for,没有下标
// collection.clear();
// System.out.println(collection);
for (Object o:collection) {
System.out.println(o);
}
//使用迭代器(迭代器专门用来遍历集合的一种方式)
//hasNext();有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
System.out.println("------------");
Iterator t = collection.iterator();
while (t.hasNext()){
String s = (String)t.next();
System.out.println(s);
//collection.remove(s);
//t.remove();
}
System.out.println("元素个数:"+collection.size());
//判断:
System.out.println(collection.contains("苹果"));
System.out.println(collection.isEmpty());
将存储对象由字符串换成对象
Collection collection = new ArrayList();
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",19);
Student s3 = new Student("王五",18);
collection.add(s1);//添加元素
collection.add(s2);
collection.add(s3);
System.out.println("总元素个数为:"+collection.size());
/* collection.remove(s1);
System.out.println("总元素个数为:"+collection.size());*/
/* for (Object o : collection) {
Student s = (Student) o;
System.out.println(s.toString());
}*/
Iterator iterator = collection.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println(collection.contains(s1));
System.out.println(collection.isEmpty());
List接口与实现类
-
特点:有序、有下标
-
方法:
- void add(int index, Object o)//在index位置插入对象
- boolean addAll(int index,Collection c)//将一个集合中的元素添加到此集合中的index位置
- Object get(int index)//返回集合中指定位置的元素
- List subList(int fromIndex, int toIndex)//返回fromIndex和toIndex之间的集合元素
List list = new ArrayList();
list.add("小米");
list.add("华为");
list.add("苹果");
list.add(0,"三星");
System.out.println("元素个数为:"+list.size());
System.out.println(list.toString());
//删除元素
/* list.remove(0);
list.remove("小米");
System.out.println(list.toString());*/
//遍历
System.out.println("--------使用for遍历--------");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("--------使用增强for遍历--------");
for (Object o : list) {
System.out.println(o);
}
//使用列表迭代器,和Iterator的区别,ListIterator,可以向前或者向后遍历,添加、删除、修改元素
ListIterator listIterator = list.listIterator();
System.out.println("----------使用迭代器从前往后----------");
while (listIterator.hasNext()){
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
System.out.println("----------使用迭代器从后往前----------");//这个时候指针刚好指向最末端
while(listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
//判断
System.out.println(list.contains("三星"));
System.out.println(list.isEmpty());
//获取位置
System.out.println(list.indexOf("华为"));
注意添加数字类会自动装箱
List list = new ArrayList();
//添加数字会自动装箱
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.add(60);
System.out.println("元素个数为:"+":"+list.size());
System.out.println(list.toString());
//list.remove(new Integer(20));//表示的是下标不能直接使用数字,可以使用Object ,或者包装类(new一个)
System.out.println();
System.out.println("删除之后元素个数为:"+list.size());
System.out.println(list.subList(1, 3));//含头不含尾
List实现类
-
ArraysList【重点】
- 数组结构实现,查询块、增删慢;
- JDK1.2版本,运行效率高、线程不安全
-
Vector
- 数组结构实现,查询块、增删慢
- JDK1.0版本,运行效率慢、线程安全
-
LinkedList:
- 链表结构实现,增删快,查询慢。
-
* ArrayList的用法 * 存储结构:数组,查找遍历快,增删慢 ArrayList arrayList = new ArrayList(); Student s1 = new Student("张三",20); Student s2 = new Student("李四",21); Student s3 = new Student("王二",19); arrayList.add(s1); arrayList.add(s2); arrayList.add(s3); System.out.println("元素总数为:"+arrayList.size()); arrayList.remove(new Student("张三",20)); System.out.println("元素总数为:"+arrayList.size()); //重写了equals方法,判断对象是否相等,判断是否为空,判断是否为同一类型,属性是否相等,默认返回false Iterator iterator = arrayList.iterator(); while(iterator.hasNext()){ Student s = (Student)iterator.next(); System.out.println(s.toString()); } ListIterator listIterator = arrayList.listIterator(); System.out.println("-------使用列表迭代器--------"); while (listIterator.hasNext()){ System.out.println(listIterator.next()); } while(listIterator.hasPrevious()){ System.out.println(listIterator.previous()); } //判断 System.out.println(arrayList.contains(new Student("王二",19))); System.out.println(arrayList.indexOf(new Student("王二",19)));
ArrayList()源码分析
- m默认容量DEFAULT_CAPACITY = 10
- 存放元素的数组:elementData
- 实际元素个数:size
- 如果没有在集合中添加任何元素,容量为0
- 添加任意一个元素之后,容量为10
- 每次扩容是原来的一点五倍
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//-------------------------------------------
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
//-----------------------------------
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//----------------------------
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Linkedlist
/**
* LinkedList的使用
* 存储结构:采用双向链表
*/
public class Demo01 {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",21);
Student s3 = new Student("王二",19);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println(linkedList.toString());
/* linkedList.remove(new Student("张三",20));
System.out.println("删除之后:"+linkedList.size());*/
System.out.println("-----------for-------------");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
System.out.println("---------增强for-------------");
for (Object o : linkedList) {
Student s = (Student)o;
System.out.println(s.toString());
}
System.out.println("---------迭代器-------------");
Iterator iterator = linkedList.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
源码分析
int size:集合的大小
Node first:链表的头结点
Node last:链表的尾结点
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;
}
}
泛型和工具类
- Java泛型是DJK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类、泛型接口、泛型方法
- 语法
- <T,...>T称为类型占位符,表示一种引用类型
- 好处
- 提高代码的重用性
- 防止类型转换异常,提高代码的安全性
使用泛型创建对象
//使用泛型创建对象,不同类型的泛型对象不能相互赋值
MyGeneric<String> myGeneric = new MyGeneric<String>();
myGeneric.t = "你好世界";
myGeneric.show("成功使用泛型");
String s = myGeneric.getT();
System.out.println(s);
//实际类型只能是引用类型
MyGeneric<Integer> myGeneric1 = new MyGeneric<>();
myGeneric1.show(520);
MyGeneric<String> myGeneric2 = myGeneric;
System.out.println(myGeneric2.t);
泛型接口
/**
* 使用泛型来创建接口
* 语法:接口名<T>
* 注意不能使用泛型静态常量
* @param <T>
*/
public interface MyInterface<T> {
String name = "pxt";
T serve(T t);
}
public class MyInterfaceImpl implements MyInterface<String>{
@Override
public String serve(String s) {
System.out.println(s);
return s;
}
}
//继承的类也可以使用泛型
public class MyInterfaceImpl2<T> implements MyInterface<T> {
@Override
public T serve(T t) {
System.out.println(t);
return t;
}
}
//实例
MyInterfaceImpl myInterface = new MyInterfaceImpl();
myInterface.serve("使用泛型接口");
MyInterfaceImpl2<Integer> myInterfaceImpl2 =new MyInterfaceImpl2();
myInterfaceImpl2.serve(200);
泛型方法
/**
* 泛型方法
* 语法:<T>返回值类型
*/
public class MyGenericMethod {
public <T> T show(T t){
System.out.println("泛型方法:"+t);
return t;
}
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("成功使用了");
myGenericMethod.show(3.1415926);
//方法的类型取决于输入的数据
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
- 特点
- 编译时即可检查,而非运行时抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间不能相互赋值,泛型不存在多态
ArrayList<String> arrayList = new ArrayList();
arrayList.add("第一个");
arrayList.add("第二个");
arrayList.add("第三个");
for (String s : arrayList) {
System.out.println(s);
}
ArrayList<Student> arrayList1 = new ArrayList<>();
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",21);
Student s3 = new Student("王二",19);
arrayList1.add(s1);
arrayList1.add(s2);
arrayList1.add(s3);
Iterator<Student> iterator = arrayList1.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Set接口和实现类
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
/**
*测试set接口的使用
* 无序,不可重复,乜有下标
*/
public class Demo01 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
}
//和Collection一样的增加,删除,遍历,就是注意输入顺序和输出顺序无关
//输入相同的元素会被无视
}
Set实现类
- HashSet【重点】
- 基于HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
/**
* HashSet的使用
* 存储结构:哈希表(数组+链表+红黑树)
* 存储过程:
* (1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,不为空则执行第二部
* (2)再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
*/
public class Demo03 {
public static void main(String[] args) {
HashSet<Person> hashSet = new HashSet<>();
//添加数据
Person p1 = new Person("刘德华",20);
Person p2 = new Person("郭富城",19);
Person p3 = new Person("梁朝伟",21);
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
hashSet.add(new Person("刘德华",20));
//没有名字的对象,地址不同被认为是不同元素
System.out.println("元素个数为:"+hashSet.size());
}
}
- TreeSet
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
/**
* 使用TreeSet保存数据
* 存储结构:红黑树
*要求:元素必须要实现Comparable接口,compareTo()方法返回值为0,认为是重复元素
*/
public class Demo04 {
public static void main(String[] args) {
TreeSet<Person> treeSet = new TreeSet<>();
Person p1 = new Person("aaa",20);
Person p2 = new Person("bbb",19);
Person p3 = new Person("ccc",21);
treeSet.add(p1);
treeSet.add(p2);
treeSet.add(p3);
System.out.println("元素个数为:"+treeSet.size());
/* treeSet.remove(new Person("梁朝伟",21));
System.out.println("元素个数为:"+treeSet.size());*/
/*
for (Person person : treeSet) {
System.out.println(person.toString());
}
*/
Iterator<Person> iterator = treeSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
Comparato;实现定制比较器
/**
* TreeSet集合的使用
* Comparator;实现定制比较器
* Comparable:可比较的(可以代替这个接口的作用)
*/
public class Demo05 {
public static void main(String[] args) {
TreeSet<Person> treeSet = 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;
}
});//注意这个是在()里的函数
Map接口和实现类
-
特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复
-
方法
- V put(K key,V value)//将对象存入到集合中,关联键值。key重复则覆盖原值
- Object get(Object key)//根据键获取对应的值
- Set
//返回所有的key - Collection
values() //返回包含所有值的Collection集合 - Set<Map.Entry<K,V>>//键值匹配的Set集合
/**
*Map接口的使用
* 特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
*/
public class Demo01 {
public static void main(String[] args) {
//创建map集合
Map<String,String> map= new HashMap<>();
//添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
System.out.println("元素个数为:"+map.size());
/* //删除元素
map.remove("cn");
System.out.println("元素个数为:"+map.size());*/
//遍历元素
System.out.println("----------使用keySet-----------");
// Set<String> keySet = map.keySet();//使用keySet方法得到的是键值
for (String s : map.keySet()) {
System.out.println(s+":"+map.get(s));
}
System.out.println("--------使用entryKey-------");
//Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String,String> entry : map.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
//判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("泰国"));
}
}
HashMap的实现
/**
* HashMap的使用
* 存储结构:哈希表(数组+链表+红黑树)
* 使用和hashCode()和equals判断是否重复
*/
public class Demo02 {
public static void main(String[] args) {
HashMap<Student,String> students = new HashMap<>();
Student s1 = new Student("孙悟空",101);
Student s2 = new Student("沙和尚",102);
Student s3 = new Student("猪八戒",103);
students.put(s1,"斗战圣佛");
students.put(s2,"卷帘大将");
students.put(s3,"净坛使者");
// students.put(new Student("猪八戒",103),"净坛使者");
System.out.println("元素个数为:"+students.size());
System.out.println(students.toString());
//删除
//students.remove("s1");//按键删除
//遍历
System.out.println("-------使用keySet------");
for(Student student:students.keySet()){
System.out.println(student.toString()+":"+students.get(student));
}
System.out.println("--------使用entrySet------");
for(Map.Entry<Student,String> entry:students.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
//判断
System.out.println(students.containsKey(new Student("孙悟空",101)));
System.out.println(students.containsValue("弼马温"));
}
}
源码分析
1 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//hashMap初始容量大小
2 static final int MAXIMUM_CAPACITY = 1 << 30;//hashMap的数组的最大容量
3 static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子
4 static final int TREEIFY_THRESHOLD = 8;//jdk1.8 当链表长度大于8时,调整成红黑树
5 static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8 当链表长度小于6时,调整成链表
6 static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8 当链表长度大于8时,并且集合元素个数大于等于64时,调整为红黑树
7 transient Node<K,V>[] table;//哈希表中的数组
8 transient int size;//元素个数
总结:
(1)HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16
(2)当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的两倍,目的是减少调整元素的个数
(3)jdk1.8以前,链表时头插入,jdk1.8之后是未插入
Treemap
- 和TreeSet的方法一样,需要构建比较的方法,要么让类对象实现Comparable接口,或者整Comparator类
Collections工具类的使用
/**
* 演示Collections的使用
*/
public class Demo01 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(5);
list.add(18);
list.add(36);
list.add(9);
System.out.println("排序之前:"+list.toString());
Collections.sort(list);
System.out.println("排序之后:"+list.toString());
Collections.reverse(list);
System.out.println("翻转之后:"+list.toString());
int i = Collections.binarySearch(list,13);
System.out.println("查找的位置为:"+i);//找不到就显示负数
List<Integer> list1 = new ArrayList<>();//长度为0,要长度相等才能copy成功
for (int j = 0; j < list.size(); j++) {
list1.add(0);
}
Collections.copy(list1,list);
System.out.println("复制之后:"+list1.toString());
Collections.shuffle(list);//每次都随机打乱
System.out.println("打乱之后:"+list);
//将list转为数组
Integer[] arr = list.toArray(new Integer[0]);
//小于等于原集合的长度生成的数组长度和集合一样,大于则以大的为准
System.out.println("生成的数组的长度:"+arr.length+"数组为:"+ Arrays.toString(arr));
//将数组转为List集合
String[] strings = {"孙悟空","唐僧","猪八戒"};
List<String> list2 = Arrays.asList(strings);
//生成的集合是一个受限集合,不能添加和删除
System.out.println(list2);
Integer[] num = {1,23,48,541,84,11};
//使用基本数据类型转化为集合要使用包装类
List<Integer> list_num = Arrays.asList(num);
}
}
前锋教育