Java集合框架简介
什么是集合?
集合是用来存放数据对象引用的容器,是对数组在功能上的扩展。
如果需要存放基本数据类型的数据,则需要使用包装类,基本类型可以自动转换为包装类型。
java.util包下的集合框架主要有几个接口和实现类组成。
Iterator接口
Iterator接口,这是一个用于遍历集合中元素的接口,主要包含hashNext(),next(),remove()三种方法。它的一个子接口LinkedIterator在它的基础上又添加了三种方法,分别是add(),previous(),hasPrevious()。也就是说如果是先Iterator接口,那么在遍历集合中元素的时候,只能往后遍历,被遍历后的元素不会再遍历到,通常无序继续实现的都是这个接口,比如HashSet,HashMap;而那些元素有序的集合,实现的一般都是LinkedIterator接口,实现这个接口可以双向遍历,既可以通过next()访问下一个元素,又可以通过previous()访问前一个元素,比如ArrayList。
Collection是一个接口
Collection常用方法
方法 | 说明 |
---|---|
boolean add(E e) | 将元素e放入集合中 |
void clear() | 删除集合中的所有元素 |
boolean isEmpty() | 判断集合是否没有任何元素,俗称空集合 |
boolean remove(object e) | 如果元素e出现在集合中,删除其中一个 |
int size() | 返回集合中的元素个数 |
object[ ] toArray() | 返回一个装有所有集合中元素的数组 |
public static void main(String[] args) {
// 集合里面放存放数据类型的包装类,一定不能是简单类型 后面的<>里面的类型可以省略
// 使用Collection 发生了向上转型
Collection<Integer> collation = new ArrayList<>();
// 此时相当于有了一个顺序表
collation.add(1);
collation.add(2);
// 能打印出来 可能是ArrayList 或者它的父类重写了toString方法
System.out.println(collation);
// java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
// 问题:数组不能整体进行强制类型转换
Object[] array = collation.toArray();
System.out.println(Arrays.toString(array));
}
/**
[1, 2]
[1, 2]
*/
泛型
泛型就是编写模板代码来适应任意类型;(泛型就是将类型参数化,给类或者方法传类型)
泛型的好处是使用时不必对类型进行强制转换,它通过编译器对类型进行检查;
注意泛型的继承关系:可以把ArrayList向上转型为List(T不能变!),但不能把ArrayList向上转型为ArrayList(T不能变成父类)。
* 问题:如何实现一个通用顺序表?
* 1. : 代表当前类是一个泛型类。
* 2. new T[10]:(×) 不能new泛型类型的数组 T[] t = new T[];
*
* 泛型的意义:
* 1.在存储元素的时候,可以自动进行类型检查
* 2.在获取元素的时候,可以进行自动类型的转换
* 3.泛型类型的参数,不可以是简单参数
* 4.泛型类型的参数,是不参与类型的组成的
*
* 面试问题:
* 泛型是怎么编译的?
* 1.泛型只在编译的时候起作用,在运行的时候,是没有泛型的概念的!
* 2.泛型的编译使用的是擦除机制 -> 把类型擦除成 Object -> 不严谨,可以设置擦除边界
基本数据类型与包装类的对应关系
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Interger |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
包装类有三个作用 一个实现基本类型之间的转换 ,二是便于函数传值 ,三就是在一些地方要用到Object的时候方便将基本数据类型装换。
包装类的使用:装箱和拆箱
装箱/装包 就是把简单数据类型转变成包装类型
装箱又分为自动装箱和手动装箱
// 装箱
int i = 10;
Integer j = i; //自动装箱
Integer j2 = Integer.valueOf(i);
System.out.println(j);
System.out.println(j2);
// 拆箱
Integer a = 20;
int b = a; // 自动拆箱
int b2 = a.intValue(); // ×××Value()
System.out.println(b);
Integer x1 = -129;
Integer x2 = -129;
// true 的范围为 -128 ~ 127
System.out.println(x1==x2);
列表(List):有序存放,允许重复,可以存放不同类型的对象。
List继承了Collection接口:元素有序(有序或无序是指是否按照其添加的顺序来存储对象),可重复,并引入位置下标
方法 | 说明 |
---|---|
boolean add(E e) | 尾插e |
void add(int index,E element) | 将e插入到index位置 |
boolean addAll(Collection extends E> c) | 尾插c中的元素 |
E remove(int index) | 删除index位置元素 |
boolean remove(Object o) | 删除遇到的第一个o |
E get(int index) | 获取下标index位置元素 |
E set(int index,E element) | 将下标index位置元素设置为element |
void clear() | 清空 |
boolean contains(Object o) | 判断o是否在线性表中 |
int indexOf(Object o) | 返回第一个o所在下标 |
int lastIndexOf(Object o) | 返回最后一个o的下标 |
List subList(int fromIndex,int toIndex) | 截取部分list |
public static void main(String[] args) {
List<Integer> list = new ArrayList();
list.add(10);
}
此时 elementDat[size++]=e 代码运行的结果相当于:
elementData[size] = 10;
size++;
public static void main(String[] args) {
List<Integer> list = new ArrayList();
list.add(10);
list.add(1,10);
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
list2.add(4);
list.addAll(list2);
System.out.println(list); // [10, 10, 1, 2, 3, 4]
//迭代器 就是用来遍历集合中的元素的
// 只有实现了iterable接口的类才能用iterable来打印 Map就不行
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
for (Integer e:list) {
System.out.println(e);
}
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list); // [1, 2, 3]
int index = list.remove(2); // 3
System.out.println(index);
System.out.println(list); // [1, 2]
//get返回的是对象
boolean flg = list.remove(list.get(1));
System.out.println(list); // [1]
list.set(0,100);
// list.set(1,200); 下标没有数据的地方不能修改元素
System.out.println(list); // [100]
//list.clear();
//System.out.println(list); // []
boolean flg2 = list.contains(100);
System.out.println(flg2); // true
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(4);
list.add(4);
list.add(4);
System.out.println(list.indexOf(2)); // 1
System.out.println(list.lastIndexOf(4)); // 6
List<Integer> elist = list.subList(1,3);
elist.set(1,11);
// subList截取出来的还是原来的数组
System.out.println(elist); // [2, 11]
System.out.println(list); // [1, 2, 11, 4]
}
LinkedList
构造方法
方法 | 说明 |
---|---|
ArrayList() | 无参数构造 |
ArrayList(int initialCapacity) | 指定顺序表初始容量 |
ArrayList(Collection extends E> c) | 利用其他Collection构建ArrayList |
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>(30);
ArrayList<Integer> list3 = new ArrayList<>(list2);
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.lang.*;
/*有若干学生(学生对象放在一个List中),每个学生有一个姓名(String),班级(String)和考试成绩属性(double)
某次考试结束后,每个学生都获得了一个考试成绩。遍历list集合,并把学会对象的属性打印出来。
* */
/**
* 有一个List当中存放的是整形的数据,要求使用Collections.sort对List进行排序
* */
class Student implements Comparable<Student>{
private String name;
private String className;
private int sorce;
public Student(String name, String className, int sorce) {
this.name = name;
this.className = className;
this.sorce = sorce;
}
public String getName() {
return name;
}
public String getClassName() {
return className;
}
public double getSorce() {
return sorce;
}
public void setName(String name) {
this.name = name;
}
public void setClassName(String className) {
this.className = className;
}
public void setSorce(int sorce) {
this.sorce = sorce;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", className='" + className + '\'' +
", sorce=" + sorce +
'}';
}
@Override
public int compareTo(Student o) {
return this.sorce-o.sorce;
}
}
public class TestDemo9 {
public static void main(String[] args) {
// 自定义类型也能放到list中
List<Student> list = new ArrayList<>();
list.add(new Student("张三","一班",95));
list.add(new Student("李四","二班",75));
list.add(new Student("王五","三班",100));
Collections.sort(list);
System.out.println(list);
//[Student{name='李四', className='二班', sorce=75},
// Student{name='张三', className='一班', sorce=95},
// Student{name='王五', className='三班', sorce=100}]
}
}
public static void main(String[] args) {
/**
* 删除第一个字符串当中出现的第二个字符串中的字符
* 例如:String str1 = "welcome to bit";
* String str2 = "come";
* 输出 wl t bit
* */
String str1 = "welcome to bit";
String str2 = "come";
ArrayList<Character> list = new ArrayList<>();
for (int i = 0; i < str1.length(); i++) {
// charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1。
char ch = str1.charAt(i);
if(!str2.contains(ch+"")){
list.add(ch);
}
}
System.out.println(list);
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class Card{
public int rank; // 牌面值
public String suit; // 花色
public Card(int rank, String suit) {
this.rank = rank;
this.suit = suit;
}
@Override
public String toString() {
return "Card{" +
"rank=" + rank +
", suit='" + suit + '\'' +
'}';
}
}
public class TestDemo11 {
// 穷举所有的花色
public static final String[] SUITS = {"♠","♥","♣","♦"};
// 买一副牌
private static List<Card> buyDeck(){
List<Card> deck = new ArrayList<>(52);
// 经过两次循环 产生52个牌对象
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 13; j++) {
// 花色进行赋值
String suit = SUITS[i];
// j就相当于牌面值
int rank = j;
Card card = new Card(rank,suit);
deck.add(card);
}
}
return deck;
}
private static void swap(List<Card> deck,int i,int index){
// 此时是链表 不是数组了
Card t = deck.get(i);
deck.set(i,deck.get(index));
deck.set(index,t);
}
private static void shuffle(List<Card> deck){
Random random = new Random(20190905);
for (int i = deck.size()-1; i > 0; i--) {
// nextInt(int n) 方法用于获取一个伪随机,在0(包括)和指定值(不包括),从此随机数生成器的序列中取出均匀分布的int值。
int r = random.nextInt(i);
swap(deck,i,r);
}
}
public static void main(String[] args) {
List<Card> deck = buyDeck();
System.out.println("刚买回来的牌:");
System.out.println(deck);
shuffle(deck);
System.out.println("洗过的牌");
System.out.println(deck);
List<List<Card>> hands = new ArrayList<>();
hands.add(new ArrayList<>());
hands.add(new ArrayList<>());
hands.add(new ArrayList<>());
//三个人 每个人轮流抓5张牌
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 3; j++) {
//返回值
//如果传入元素,删除成功,则返回 true。
//如果传入索引值,则返回删除的元素。
Card card = deck.remove(0);
hands.get(j).add(card);
}
}
System.out.println("剩余的牌:");
System.out.println(deck);
System.out.println("A手中的牌:");
System.out.println(hands.get(0));
System.out.println("B手中的牌:");
System.out.println(hands.get(1));
System.out.println("C手中的牌:");
System.out.println(hands.get(2));
}
}
使用remove方法也可以
LinkedList(链表) LinkedList的内存结构是用双向链表存储
构造方法 | 说明 |
---|---|
LinkedList() | 无参构造 |
集合(Set):无序存放,不允许重复,可存放不同类型的对象。
SortedSet:排好序列的Set
映射(Map):俗称键值对
Map接口是键-值对象
常用方法
方法 | 说明 |
---|---|
V get(object k) | 根据指定的k查找对应的v |
V getOrDefault(object k,v defaultvalue) | 根据指定的k查找对应的v,没有找到用默认值代替 |
V put(k key,v value) | 将指定的k-v放入Map |
boolean containskey(object key) | 判断是否包含key |
boolean containValue(object value) | 判断是否包含value |
Set |
将所有键值对返回 |
boolean isEmpty() | 判断是否为空 |
int size() | 返回键值对的数量 |
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(1981,"张三");
map.put(2001,"李四");
map.put(1990,"王二");
System.out.println(map);
// {2001=李四, 1990=王二, 1981=张三}
// 哈希表在存放元素的时候,是根据某种函数来存储的
String value = map.getOrDefault(1984,"逗比");
System.out.println(value);
//逗比
// map.entrySet() 的作用是把 k和v封装成一个整体,放到set当中(相当于一个布袋)
// 每一个东西的类型是 Map.Entry
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
for (Map.Entry<Integer,String> en : entrySet) {
System.out.println(en.getKey()+"-->"+en.getValue());
/**
* 2001-->李四
* 1990-->王二
* 1981-->张三
* */
}
}
SortedMap:排好序列的Map