集合就是容器,容器有数组,集合。
集合和数组既然都是容器,它们有什么区别呢?
数组的长度是固定的。集合的长度是可变的。
数组中存储的是同一类型的元素,可以存储任意类型数据。集合存储的都是引用数据类型。如果想存储基本类型数据需要存储对应的包装类型。
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循环。 【代码实践】
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) { } }发牌逻辑
