Collection、泛型
Collection
概述
集合就是容器,容器有数组,集合。
集合和数组既然都是容器,它们有什么区别呢?
-
数组的长度是固定的。集合的长度是可变的。
-
数组中存储的是同一类型的元素,可以存储任意类型数据。集合存储的都是引用数据类型。如果想存储基本类型数据需要存储对应的包装类型。
集合框架介绍
集合Collection中常用的功能
public boolean add(E e)
: 把给定的对象添加到当前集合中 。public void clear()
:清空集合中所有的元素。public boolean remove(E e)
: 把给定的对象在当前集合中删除。public boolean contains(Object obj)
: 判断当前集合中是否包含给定的对象。public boolean isEmpty()
: 判断当前集合是否为空。public int size()
: 返回集合中元素的个数。public Object[] toArray()
: 把集合中的元素,存储到数组中
/*
Collection是接口,如果要创建对象需要借助其子类
*/
public class Demo01 {
public static void main(String[] args) {
//借助Collection子类创建对象
Collection<String> coll = new ArrayList<>(); // 多态
//- public boolean add(E e): 把给定的对象添加到当前集合中 。
coll.add("迪丽热巴");
coll.add("古力娜扎");
coll.add("玛尔扎哈");
coll.add("德玛西亚");
System.out.println("coll = " + coll);//[迪丽热巴, 古力娜扎, 玛尔扎哈, 德玛西亚]
//- public void clear() :清空集合中所有的元素。
//coll.clear();
//System.out.println("coll = " + coll); //[]
//- public boolean remove(E e): 把给定的对象在当前集合中删除。
boolean remove = coll.remove("德玛西亚");
System.out.println("remove = " + remove);
System.out.println("coll = " + coll);//[迪丽热巴, 古力娜扎, 玛尔扎哈]
//- public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
boolean contains = coll.contains("德玛西亚");
System.out.println("contains = " + contains);//false
boolean contains1 = coll.contains("古力娜扎");
System.out.println("contains1 = " + contains1);//true
System.out.println("coll = " + coll);
//- public boolean isEmpty(): 判断当前集合是否为空。
boolean empty = coll.isEmpty();
System.out.println("empty = " + empty);//false
//- public int size(): 返回集合中元素的个数。
int size = coll.size();
System.out.println("size = " + size);//3
//- public Object[] toArray(): 把集合中的元素,存储到数组中
Object[] objects = coll.toArray();
System.out.println("objects = " + Arrays.toString(objects));
}
}
迭代器Iterator的使用
1. 认识Iterator接口
Iterator专门用来遍历集合
含有方法:
2. 如何获取集合对应的Iterator迭代器?
Colleciton
接口继承了一个接口Iterable
,含有方法:
可以用以上方法获取一个集合的迭代器。
因为Iterable
是Colleciton
的父接口,所有Collcetion
的子类型都含有Iterable
的方法:iterator
的方法用来获取对应的迭代器。
3. 迭代器的使用
使用步骤:
- 可以调用集合的方法
iterator
方法,获取迭代器 - 通过迭代器对象的方法:
hasNext
方法判断是否有下一个元素。 - 如果有下一个元素通过
next
方法获取元素。 - 重复2,3步骤,直到
hasNext
方法执行返回false,遍历结束。
以上步骤优化:
-
可以调用集合的方法iterator方法,获取迭代器:
ter
-
借助while循环获取
while(iter.hasNext()){ E e = iter.next(); }
【代码实践】
public class Demo01 {
public static void main(String[] args) {
//借助Collection子类创建对象
Collection<String> coll = new ArrayList<>(); // 多态
coll.add("迪丽热巴");
coll.add("古力娜扎");
coll.add("玛尔扎哈");
coll.add("德玛西亚");
//使用迭代器进行遍历
//1. 可以调用集合的方法iterator方法,获取迭代器
Iterator<String> iter = coll.iterator();
//2. 通过迭代器对象的方法:hasNext方法判断是否有下一个元素。
boolean result = iter.hasNext();
//3. 如果有下一个元素通过next方法获取元素。
if (result) {
String next = iter.next();
System.out.println("next = " + next);
}
//4. 重复2,3步骤,直到hasNext方法执行返回false,遍历结束。
result = iter.hasNext();
if (result) {
String next = iter.next();
System.out.println("next = " + next);
}
//以上写法太low了,不适用
//使用while循环进行优化
//获取迭代器
Iterator<String> iter2 = coll.iterator();
while (iter2.hasNext()) {//如果有下一个元素,执行循环体进行获取下一个元素,否则结束
String element = iter2.next();//获取下一个元素
System.out.println("element = " + element);
}
}
}
迭代器使用时的注意事项
在使用迭代器进行遍历集合时,注意:
1)如果迭代器判断没有了元素,不能继续使用next方法获取元素,还继续取:oSuchElementException
2)当迭代器使用的过程中,不能直接使用集合对象进行增删数据,ConcurrentModificationException
如果一定要删除,可以使用迭代器自身的方法:remove
public class Demo02 {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("AAA1");
coll.add("AAA2");
coll.add("AAA3");
coll.add("AAA4");
coll.add("AAA5");
coll.add("AAA6");
Iterator<String> iter = coll.iterator();
while (iter.hasNext()) {
String s = iter.next();
System.out.println("s = " + s);
if ("AAA3".equals(s)) {
//迭代器执行过程中,不能直接使用集合对象进行增删数据
//coll.remove("AAA3");
//如果要删除,可以使用迭代器的remove方法
iter.remove();
}
}
System.out.println("coll = " + coll);
}
}
迭代器的使用操作原理介绍
我们可以借助while循环完成以上循环获取元素的操作,当最后一个元素获取完成,不能继续获取。
增强for循环的使用
增强for循环专门用来遍历数组和集合的循环
格式:
for(变量类型 变量 : 数组/集合){
//操作变量,变量就是每次循环取出的元素
}
注意:
变量类型应该就是集合或者数组所存储的数据类型。
小技巧:数组名/集合名.for 快速构建增强for循环。
【代码实践】
public class Demo01 {
public static void main(String[] args) {
//增强for循环,专门用来遍历数组和集合
//遍历数组
int[] arr = {100, 200, 300};
for (int i : arr) {
System.out.println("i = " + i);
}
//遍历集合
Collection<String> coll = new ArrayList<>();
coll.add("AAA1");
coll.add("AAA2");
coll.add("AAA3");
for (String e : coll) {
System.out.println("e = " + e);
}
}
}
泛型的概述
泛型:泛指任意的引用数据类型【就是使用的一种未知类型,具体在使用的时候进行确定】
泛型也可以不写,如果不写,那么泛型指定类型默认为Object。
public class Demo01 {
public static void main(String[] args) {
Collection coll = new ArrayList();
//泛型不指定具体类型,泛型指代的就是Object类型,意味着集合可以存储任意的类型数据。
coll.add("Hello");
coll.add("World");
coll.add(3.14);
coll.add(1000);
//有弊端,不利于后期数据的处理
for (Object o : coll) {
//获取字符串的长度
System.out.println(((String) o).length()); //报错
}
}
}
使用泛型好处:
- 可以避免在后期使用数据时,不必要的类型转化
- 让潜在的类型转化异常,提前到编译失败,强制程序员使用指定的数据
Collection<String> coll2 = new ArrayList<>();
coll2.add("Hello");
//coll2.add(1000); //可以将类型转化异常提前到编译异常,避免运行的时候报错
泛型可以理解为类型的变量,使用时具体指定。有利于程序的开发。
自定义泛型类及使用
泛型类的定义和使用
1)定义格式:类名后面加上 <泛型变量>
public class 类名<A,B,C,...>{
//把A,B,C当作是某一种具体类型使用,成员变量的类型,方法参数的类型,方法返回值类型
}
【例如】
public class MyArrayList<D>{
private D d;
public void setD(D d){
this.d=d;
}
}
2)怎么使用,什么时候类的泛型可以确定为具体的类型。
具体创建对象的时候,具体指定
public class Demo01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hello"); // E = String
MyArrayList<String> myList = new MyArrayList<>();
myList.setD("Hello"); // D = String
}
}
在类中定义的泛型,在整个类都能使用
自定义泛型的方法及使用
-
怎么在方法中定义泛型【格式】
在方法修饰符中添加一个泛型,这个泛型只能在本方法中使用
修饰符<泛型变量> 返回值类型 方法名(参数列表){ }
-
怎么使用,什么时候确定泛型的具体类型
在具体调用该方法时,传入的数据是什么类型,那么该泛型就是什么类型
自定义含有泛型的接口及使用
-
如何定义【格式】?
public interface 接口名<泛型变量>{} 例如: public interface Map<K,V>{}
【代码实践】
public interface MyCollection<W> { void add(W w); }
-
什么时候能指定接口中泛型的具体类型?
1:接口的泛型可以在子类实现的时候,具体指定
public class MyCollectionImp implements MyCollection<String> { //W =String @Override public void add(String o) { } }
2:如果子类无法确定泛型,可以在子类中类名后面定义一个泛型,在接口后面使用该泛型用,可以在创建这个子类对象的时候确定
public class MyCollImp<W> implements MyCollection<W> { @Override public void add(W w) { } } //具体子类创建对象的时候进行指定泛型【泛型类的使用】 public class Demo01 { public static void main(String[] args) { MyCollImp<String> coll = new MyCollImp<>(); // W = String coll.add("Hello"); } }
泛型通配符的基本使用
泛型通配符:
泛型通配符作用:如果想让我们得参数可以接收任意类型得泛型,就可以借助泛型通配符实现。
注意:泛型通配符定义的集合,不支持增删操作,只支持读取操作
/*
泛型通配符:?
作用:可以代表任意类型的泛型
注意:泛型通配符定义的集合,只能获取元素,不能增删数据
*/
public class Demo01 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
ArrayList<Number> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
//具体泛型只能接收具体类型
//printArrayList(list1); //x
//printArrayList(list2); //x 泛型没有多态
//printArrayList(list3);
//printArrayList(list4);//x
//泛型通配符,可以接收任意得泛型
printArrayList2(list1);
printArrayList2(list2);
printArrayList2(list3);
printArrayList2(list4);
}
public static void printArrayList2(ArrayList<?> list) {
//list.add(1000);
for (Object o : list) {
System.out.println("o = " + o);
}
}
public static void printArrayList(ArrayList<Number> list) {
list.add(1000);
for (Number n : list) {
}
}
}
受限泛型的使用
【代码实践】
public class Demo01 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
ArrayList<Number> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
//泛型上限:只能接收 Number及其子类类型
//print1(list1); //X 和Number没关系
print1(list2);// Integer 是Number的子类
print1(list3);// Number 自己也可以
//print1(list4);// Object 是Number父类
//泛型下限:只能接收 Number及其父类类型
//print2(list1); // X 和Number没关系
//print2(list2); // X Integer 是Number的子类
print2(list3); // Number 自己也可以
print2(list4); // Object 是Number父类
}
//泛型上限:只能接收 Number及其子类类型
public static void print1(ArrayList<? extends Number> list) {
}
//泛型下限:只能接收 Number及其父类类型
public static void print2(ArrayList<? super Number> list) {
}
}
斗地主案例
/*
1.准备牌
2.洗牌
3.发牌
4.看牌
*/
public class Demo01 {
public static void main(String[] args) {
//1.准备牌
ArrayList<String> pokers = new ArrayList<>();//集合用来存储牌
String[] colors = {"♥", "♠", "♣", "♦"};
String[] points = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
//花牌组装
for (String color : colors) {
for (String point : points) {
//System.out.println(color+point);
pokers.add(color + point);
}
}
//大王/小王
pokers.add("大🃏");
pokers.add("小🃏");
//System.out.println(pokers.size()+"::"+pokers);
//2.洗牌
Collections.shuffle(pokers);
//System.out.println(pokers.size() + "::" + pokers);
//3.发牌
ArrayList<String> player1 = new ArrayList<>();
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
for (int i = 0; i < pokers.size(); i++) {
String poke = pokers.get(i);
if (i > 50) {
dipai.add(poke);
} else if (i % 3 == 0) {
player1.add(poke);
} else if (i % 3 == 1) {
player2.add(poke);
} else if (i % 3 == 2) {
player3.add(poke);
}
}
//4.看牌
System.out.println("星仔:" + player1);
System.out.println("小高:" + player2);
System.out.println("华仔:" + player3);
System.out.println("底牌:" + dipai);
}
}
发牌逻辑