一、Collection接口
Collection是一个接口,如果要创建对象,必须要创建实现类的对象,最常用的实现类是ArrayList
1、Collection里面常见的方法:
public boolean add(E e) : 把给定的对象添加到当前集合中 。
public void clear() :清空集合中所有的元素。
public boolean remove(E e) : 把给定的对象在当前集合中删除。
public boolean contains(E e) : 判断当前集合中是否包含给定的对象。
public boolean isEmpty() : 判断当前集合是否为空。
public int size() : 返回集合中元素的个数。
public Object[] toArray() : 把集合中的元素,存储到数组中
public class Demo01CollectionMethod {
public static void main(String[] args) {
method7();
}
//public Object[] toArray(): 将集合转成一个Object数组
public static void method7() {
//创建集合添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//将集合转成一个数组
Object[] objs = c.toArray();
//对数组中的内容进行打印
System.out.println(Arrays.toString(objs));
}
//public int size():返回集合的大小,集合中有几个元素,大小就是几
public static void method6() {
//创建集合添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//打印集合的长度
System.out.println(c.size());
}
//public boolean isEmpty() : 判断当前集合是否为空。如果集合中没有元素,那么就是空的。是空结果为true。否则结果为false
public static void method5() {
//创建一个集合
Collection<String> c = new ArrayList<>();
//判断集合是否为空。
System.out.println(c.isEmpty()); //true
//向集合中添加元素
c.add("你哈");
c.add("我哈");
System.out.println(c.isEmpty()); //false
}
//public boolean contains(E e): 判断集合是否包含指定的元素
public static void method4() {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//判断集合中是否包含达尔文
boolean flag = c.contains("达尔文");
System.out.println(flag);
}
//public boolean remove(E e):删除集合中的指定元素。 删除成功返回true
public static void method3() {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("牛顿");
c.add("牛顿");
c.add("霍金");
//打印集合
System.out.println("删除前:" + c);
//调用remove方法进行删除
boolean flag = c.remove("牛顿");
System.out.println("删除后:" + c);
System.out.println("flag:" + flag);
}
//public void clear(): 清除集合中的所有元素
public static void method2() {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//打印集合中的内容
System.out.println("清除前:" + c);
//调用clear方法,清除集合中的元素
c.clear();
System.out.println("清除后:" + c);
}
//public boolean add(E e) : 向集合中添加元素
public static void method() {
//创建一个集合对象
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//直接打印集合
System.out.println(c);
}
}
2、迭代器-Iterator
如何对集合进行遍历?
我们之前使用的for循环根据索引依次获取集合中的每个元素 这种方式并不能适用于所有的集合, 因为有 些集合是没有索引的。
有一种通用的遍历方式,这个遍历方式叫做迭代器遍历。
迭代器就是一个遍历集合的工具, 里面有一个光标, 这个光标最开始指向集合的最开头(最左边)。
如何获取集合的迭代器? 调用Collection中的iterator方法即可
Iterator<E> iterator():获取集合的迭代器。
Iterator<E>,表示的就是迭代器,如果要使用迭代器进行遍历,那么还需要使用迭代器中的方法。
boolean hasNext(): 判断当前光标位置有没有元素,如果有元素,那么结果就是true。
E next(): 获取当前光标位置的元素,然后把光标后移。
迭代器遍历的步骤:
1. 调用集合的iterator方法获取集合的迭代器对象
2. 调用Iterator迭代器的hashNext方法, 判断是否有元素可以获取
3. 如果有元素可以获取,那么就调用迭代器的next方法,获取元素并且把光标后移。
public class Demo01Iterator {
public static void main(String[] args) {
//创建一个集合对象
Collection<String> c = new ArrayList<>();
//向集合中添加元素
c.add("hello");
c.add("world");
c.add("java");
//对集合中的内容进行遍历, 依次获取集合中的每一个元素并打印
//调用集合的iterator方法获取集合的迭代器对象
Iterator<String> iterator = c.iterator();
//使用while循环对集合进行遍历
while(iterator.hasNext()) { //如果有元素可以拿,那么我们就一直获取元素
//如果还有元素可以拿,那么我们就获取这个元素并打印
System.out.println(iterator.next());
}
/*
//调用Iterator迭代器的hashNext方法, 判断是否有元素可以获取
System.out.println(iterator.hasNext());
//获取当前位置的元素,并且把光标向后移动
System.out.println(iterator.next()); //hello
System.out.println(iterator.hasNext());//继续判断这个位置还有没有元素可以获取
System.out.println(iterator.next()); //world 获取当前位置的元素,并且把光标向后移动
System.out.println(iterator.hasNext());// 继续判断这个位置还有没有元素可以获取
System.out.println(iterator.next());//java 获取当前位置的元素,并且把光标向后移动
System.out.println(iterator.hasNext()); //false
System.out.println(iterator.next()); //NoSuchElementException
*/
}
}
3、增强for
在jdk5之后,多了一个新的遍历方式,叫做增强for循环遍历(foreach)
格式:
for(数据类型 变量名 : 容器名) {
//...
}
格式解释:
数据类型: 要遍历的容器里面的数据是什么类型的,那么这个数据类型就写什么。
变量名: 表示容器中的每一个元素。
容器名: 这个容器可以是数组,也可以是一个集合。 JDK规定,实现了Iterable接口,才可以成为增强for循环的目标。
增强for循环是普通for的语法糖(本质没有变,只不过语法更加的简洁),
使用增强for遍历数组,本质还是普通for遍历数组。
增强for的好处以及缺点:
好处: 增强for省去了索引的操作,语法更加的简洁。
缺点: 不能操作索引, 所以如果遍历的时候需要使用索引,还得用普通for循环。
public class Demo01Foreach {
public static void main(String[] args) {
//定义一个数组
int[] arr1 = {11, 22, 33, 44, 55};
//先使用普通for遍历这个数组
for(int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("===================");
//使用增强for遍历这个数组
for(int num : arr1) {
//变量num表示的是数组中的每一个元素,而不是索引
System.out.println(num);
}
System.out.println("===================");
//定义一个double数组
double[] arr2 = {10.1, 20.2, 30.3, 40.4, 50.5};
//使用增强for循环遍历这个数组
for(double num : arr2) {
System.out.println(num);
}
System.out.println("===================");
int[] arr = {10, 20, 30, 40, 50};
//使用增强for遍历数组,依次把数组中的每个元素改为原来的2倍
for(int num : arr) {
num *= 2;
}
System.out.println(Arrays.toString(arr));
}
}
(1)增强for遍历集合
格式:
for(数据类型 变量名 : 容器名) {
//...
}
增强for遍历集合,本质还是用的迭代器在遍历。
增强for是我们以后用的最多的遍历方式.
public class Demo02Foreach {
public static void main(String[] args) {
//定义一个集合,存放字符串
Collection<String> c = new ArrayList<>();
//存放数据
c.add("大幂幂");
c.add("小甜甜");
c.add("大冰冰");
//使用增强for遍历这个集合
for(String s : c) {
//s表示的是集合中的每一个元素
System.out.println(s);
}
System.out.println("--------------------------------");
//定义一个集合,存放学生对象
Collection<Student> c2 = new ArrayList<>();
//向集合中添加学生对象
c2.add(new Student("张三丰", 30));
c2.add(new Student("张翠山", 20));
c2.add(new Student("张无忌", 10));
//使用增强for,遍历集合
for(Student s : c2) {
System.out.println(s);
}
}
}
二、泛型
1、泛型的定义
泛型就是一种未知的,不确定的数据类型。
如果在类名后面加上<T>,那么这类就是一个泛型类。 注意<T>,里面E可以使用任何字母代替
类名后面的<T>表示定义了一种未知的不确定的数据类型,并且可以在这个类中去使用这个未知的数据类型T。
当我们使用这个类的时候,才能确定这个T表示的数据类型真正是什么。
如果想要延后泛型的确认时机,缩小泛型的使用范围。 让泛型只能在当前方法中使用,并且让泛型确认的时机
在调用方法的时候才确认,那么可以使用泛型方法(把泛型定义在方法上)
格式:
public <泛型> 返回值类型 方法名(参数类型 参数名) {
方法体;
}
在方法上定义的泛型必须等到调用的方法的时候才能够确定这个泛型到底是什么类型
总结:
泛型类是定义在类上的泛型, 这个泛型所表示的数据类型必须等到使用这个类的时候才能够确定。
泛型方法是定义在方法上的泛型,这个泛型所表示的数据类型必须等到使用方法的使用才能够确定。
public class Factory<T> {// 表示定义了一个不确定的数据类型 T类型
/*
定义一个方法,接收什么类型的参数,那么就返回什么类型的结果
*/
public <E> E getSame(E e) {
return e;
}
public <E> E function() {
return null;
}
/*
定义方法,修理任何东西
下面的两个T,表示使用了这种不确定的数据类型T
*/
public T method(T t) {
//修理...
return t;
}
/*
定义方法,可以修理任何东西
*/
/*
public Object method(Object obj) {
//修理...
return obj;
}
*/
/*
定义方法,用来修理手机
*/
/*
public Phone method(Phone p) {
//修理....
return p;
}
*/
/*
定义方法,用来修理Pad
*/
/*
public Pad method(Pad pad) {
//修理...
return pad;
}
*/
}
2、泛型定义在接口上
(1) 如果把泛型定义在接口名后面那么这个就是泛型接口
接口上面定义的泛型既可以当做方法参数,也可以当做返回值
泛型接口的使用:
1. 实现类在实现接口的时候,直接确定出来这个泛型的数据类型
2. 实现类在实现接口的时候,不确定泛型的类型。 在使用实现类的时候才确认这个泛型是什么
public interface MyInterface<T> { //表示定义了一个不确定的类型T。
T method(T t);
}
(2)定义泛型一定要在当前类或者接口名的后面
前面的<T> 是在定义泛型,表示了定义了一个不确定的数据类型T
后面的<T> 是在使用这个泛型, 使用这个泛型类型来确认接口中的泛型到底是什么类型。 因为是在使用泛型T确认接口中的泛型,所以确认之后的结果依然是不确定的
这个实现类中定义的泛型T,需要等到使用这个类的时候才能够确定
public class MyInterfaceImplB<T> implements MyInterface<T>{
@Override
public T method(T t) {
return null;
}
}
3 泛型: 就是一种未知的,不确定的数据类型。
比如ArrayList<E>, 里面的E就是一个泛型,他是一个未知的不确定的数据类型。 当我们使用这个类(创建对象)的时候,
才能够确定这个泛型类型E它所表示的类型真正是什么。
泛型是可以省略的,如果省略泛型,那么泛型默认是Object
泛型的好处:
1. 省去了强转的代码。
2. 将运行时的错误提前到了编译时期.
public class Demo01Generic {
public static void main(String[] args) {
//创建集合,不给出泛型
ArrayList list = new ArrayList();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
//list.add(100); 运行时期会报错
//遍历集合,打印集合中每个字符串的长度
for(Object obj : list) {
//因为要调用字符串的length方法,所以需要把obj对象向下转型成String
String str = (String)obj;
System.out.println(str.length());
}
System.out.println("===============================");
//创建集合,给出泛型,泛型是String
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
list2.add("world");
list2.add("java");
//list2.add(100); 编译时期报错
//遍历集合,打印集合中每一个字符串的长度
for (String str : list2) {
System.out.println(str.length());
}
}
}
4、 Java中的泛型都是伪泛型,只在源代码中有效, 一旦编译后,这个泛型就会消失。 俗称泛型擦除。
public class Demo02Generic {
public static void main(String[] args) {
//创建一个集合,指定泛型为String
ArrayList<String> list = new ArrayList<>();
list.add("你好");
list.add("我好");
list.add("大家好");
//遍历集合,拿到里面的每一个元素
for(String str : list) {
System.out.println(str);
}
}
}
三、泛型中的通配符
1、注意: 泛型之间没有继承关系。
ArrayList<Person> 不是 ArrayList<Student> 的父类.
泛型通配符 ?,可以匹配任何类型的泛型
比如ArrayList<?>, 那么它接收的泛型类型可以是任何类型,包括Person,包括Student,Teacher或者其他任意类型
泛型通配符只能被动匹配,不能主动使用
public class Demo01Test {
public static void main(String[] args) {
//创建一个集合,并添加元素
ArrayList<Student> stuList = new ArrayList<>();
stuList.add(new Student("小明", 10));
stuList.add(new Student("小黄", 12));
stuList.add(new Student("小绿", 14));
//调用方法,对这个存放Student的集合进行遍历
printArrayList(stuList);
System.out.println("---------------------------");
//创建存放老师的集合
ArrayList<Teacher> teacherList = new ArrayList<>();
teacherList.add(new Teacher("小苍老师", 35));
teacherList.add(new Teacher("小泽老师", 36));
teacherList.add(new Teacher("小波老师", 37));
printArrayList(teacherList);
/*
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
printArrayList(list);*/
//ArrayList<?> list = new ArrayList<>();
//list.add(new Object());
}
/*
定义方法,可以既能遍历存放Student的集合,又能遍历存放Teacher的集合
*/
public static void printArrayList(ArrayList<?> list) { //?表示通配符,可以匹配任何类型的泛型
//对list集合进行遍历
for(Object obj : list) {
//向下转型成Person
Person p = (Person)obj;
System.out.println(p.getName() + "-" + p.getAge());
}
}
/*
定义方法,用来遍历存放Person的集合
*/
/*
public static void printArrayList(ArrayList<Person> list) {
for(Person p : list) {
System.out.println(p.getName() + "-" + p.getAge());
}
}
*/
/*
定义方法,用来对存放Teacher的集合进行遍历
*/
/*
public static void printArrayList2(ArrayList<Teacher> list) {
for (Teacher t : list) {
System.out.println(t.getName() + "-" + t.getAge());
}
}
*/
/*
定义方法,用来对存放Student的集合进行遍历
*/
/*
public static void printArrayList(ArrayList<Student> list) {
//使用增强for循环进行遍历
for(Student stu : list) {
System.out.println(stu.getName() + "-" + stu.getAge());
}
}
*/
}
2、 泛型通配符的限定。 可以对泛型通配符的取值进行一个限制。
<? extends A>: 泛型的类型只能是A类或者A类的子类。 上限, 最高到A类。
<? super A>: 泛型的类型只能是A类或者A类的父类。 下限, 最低到A类。
泛型的使用场景: 主要用在代码的重构
public class Demo02Test {
public static void main(String[] args) {
//创建集合,并遍历
ArrayList<Student> stuList = new ArrayList<>();
stuList.add(new Student("小明", 10));
stuList.add(new Student("小黄", 12));
stuList.add(new Student("小绿", 14));
printArrayList(stuList);
System.out.println("=================================");
ArrayList<Person> personList = new ArrayList<>();
personList.add(new Person("大黄", 10));
personList.add(new Person("大紫", 12));
personList.add(new Person("大绿", 14));
printArrayList(personList);
System.out.println("=================================");
ArrayList<Object> objList = new ArrayList<>();
//printArrayList(objList); //参数集合的泛型要么是Person子类,要么是Person,不能是其他类或者Person的父类
//泛型下限
//method(stuList); //泛型要么是Person父类,要么是Person,不能是Person子类
//method(personList);
method(objList);
}
public static void method(ArrayList<? super Person> list) {
}
/*
定义方法,用来对存放Teacher和Student的集合进行遍历。
参数集合的泛型要么是Person,要么是Person的子类
*/
public static void printArrayList(ArrayList<? extends Person> list) { //参数集合的泛型要么是Person,要么是Person的子类
for(Person p : list) {
System.out.println(p.getName() + "-" + p.getAge());
}
}
}
四、斗地主案例的实现、
package cn.itcast.demo06;
import java.util.ArrayList;
import java.util.Collections;
/*
斗地主案例的分析:
1. 准备牌
a. 定义一个集合存用来放扑克牌
b. 向集合中添加54张牌
2. 洗牌
a. 打乱牌的顺序。
在java中有一个操作集合的工具类,这个工具类叫做Collections
里面有一个方法,叫做shuffle,可以打乱顺序
3. 发牌
a. 定义三个集合,保存每个玩家手里的牌。
b. 定义一个集合,保存底牌。
c. 开始发牌, 把第1张,第4张,第7张....发给第一个人 把第2,5,8...张发给第二个人。 把第3,6,9...发给第三个人.
我们可以根据索引发牌
把索引为0, 3, 6 ....这样的牌发给第一个人(索引对3取余结果是0)
把索引为1, 4, 7 ....这样的牌发给第二个人 (索引对3取余结果是1)
把索引为2, 5, 8 ....这样的牌发给第三个人 (索引对3取余结果是2)
4. 看牌
遍历打印每个玩家的集合。
*/
public class Demo01Game {
public static void main(String[] args) {
//1. 准备牌
//定义一个集合存用来放扑克牌
ArrayList<String> poker = new ArrayList<>();
//向集合中添加54张牌
//定义两个数组,一个保存花色,一个保存点数,然后再进行组合
String[] colors = {"♠", "♥", "♣", "♦"};
String[] nums = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
//进行组合
for(String num : nums) {
for(String color : colors) {
//将组合的结果添加到ArrayList集合
poker.add(color + num);
}
}
//添加大小王
poker.add("小王");
poker.add("大王");
//2. 洗牌
Collections.shuffle(poker);
//3. 发牌
//定义集合,保存每个玩家手里的牌
ArrayList<String> playerOne = new ArrayList<>();
ArrayList<String> playerTwo = new ArrayList<>();
ArrayList<String> playerThree = new ArrayList<>();
//定义集合,保存底牌
ArrayList<String> diPai = new ArrayList<>();
//开始发牌了,根据牌的索引进行发牌
for(int i = 0; i < poker.size(); i++) {
//获取到当前遍历到的扑克牌
String card = poker.get(i);
//判断,如果是不足三张牌(53 52 51)了,就放入到底牌集合
if (i >= 51) {
diPai.add(card);
continue; //直接结束本次循环,开始下次循环.
}
//把这个牌发给玩家(根据索引进行发牌)
if (i % 3 == 0) {//如果牌的索引是0 3 6...,就发给第一个玩家(索引对3取余结果是0)
playerOne.add(card);
} else if(i % 3 == 1) {//如果牌的索引是1 4 7...,就发给第二个玩家(索引对3取余结果是1)
playerTwo.add(card);
} else { //否则,这个牌的索引对3取余的结果肯定是2.就发给第三个玩家
playerThree.add(card);
}
}
//4. 看牌
lookCard("发哥", playerOne);
lookCard("华仔", playerTwo);
lookCard("星爷", playerThree);
lookCard("底牌", diPai);
}
/*
定义一个方法,用来看牌
参数: String类型的姓名, ArrayList<String> 玩家手里的牌
*/
public static void lookCard(String name, ArrayList<String> list) {
System.out.print(name + ": ");
//遍历集合,打印集合中的每一个元素
for(String card : list) {
System.out.print(card + " ");
}
//为了方便后面的操作,打印一个空换行
System.out.println();
}
}
总结 :
能够说出集合与数组的区别
数组长度固定,集合长度可变。
数组可以存放基本类型也可以存放引用类型,集合只能存放引用类型的数据
说出Collection集合的常用功能
public boolean add(E e) : 把给定的对象添加到当前集合中 。
public void clear() :清空集合中所有的元素。
public boolean remove(E e) : 把给定的对象在当前集合中删除。
public boolean contains(E e) : 判断当前集合中是否包含给定的对象。
public boolean isEmpty() : 判断当前集合是否为空。
public int size() : 返回集合中元素的个数。
public Object[] toArray() : 把集合中的元素,存储到数组中
能够使用迭代器对集合进行取元素
1. 调用集合的iterator方法,获取这个集合的迭代器
2. 调用迭代器的hashNext方法,判断还有没有元素可以获取
3. 调用next方法获取元素,并且把光标后移。
能够说出集合的使用细节
集合的使用步骤
能够使用集合存储自定义类型
ArrayList<Student>
ArrayList<Person>
能够使用foreach循环遍历集合
for(数据类型 变量名 : 集合) {
//变量名表示的是的值集合中的每一个元素
}
能够使用泛型定义集合对象
ArrayList<E>. 要使用集合存放什么类型的数据,那么这个E就写什么类型
能够阐述泛型通配符的作用
? 表示泛型通配符,可以匹配任何类型的泛型
能够理解泛型上下限
<? extends A>: 泛型可以是A类或者A类的子类。 上限, 最高到A类
<? super A>: 泛型可以是A类或者A类的父类。 下限, 最低到A类
一、Collection接口
Collection是一个接口,如果要创建对象,必须要创建实现类的对象,最常用的实现类是ArrayList
1、Collection里面常见的方法:
public boolean add(E e) : 把给定的对象添加到当前集合中 。
public void clear() :清空集合中所有的元素。
public boolean remove(E e) : 把给定的对象在当前集合中删除。
public boolean contains(E e) : 判断当前集合中是否包含给定的对象。
public boolean isEmpty() : 判断当前集合是否为空。
public int size() : 返回集合中元素的个数。
public Object[] toArray() : 把集合中的元素,存储到数组中
public class Demo01CollectionMethod {
public static void main(String[] args) {
method7();
}
//public Object[] toArray(): 将集合转成一个Object数组
public static void method7() {
//创建集合添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//将集合转成一个数组
Object[] objs = c.toArray();
//对数组中的内容进行打印
System.out.println(Arrays.toString(objs));
}
//public int size():返回集合的大小,集合中有几个元素,大小就是几
public static void method6() {
//创建集合添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//打印集合的长度
System.out.println(c.size());
}
//public boolean isEmpty() : 判断当前集合是否为空。如果集合中没有元素,那么就是空的。是空结果为true。否则结果为false
public static void method5() {
//创建一个集合
Collection<String> c = new ArrayList<>();
//判断集合是否为空。
System.out.println(c.isEmpty()); //true
//向集合中添加元素
c.add("你哈");
c.add("我哈");
System.out.println(c.isEmpty()); //false
}
//public boolean contains(E e): 判断集合是否包含指定的元素
public static void method4() {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//判断集合中是否包含达尔文
boolean flag = c.contains("达尔文");
System.out.println(flag);
}
//public boolean remove(E e):删除集合中的指定元素。 删除成功返回true
public static void method3() {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("牛顿");
c.add("牛顿");
c.add("霍金");
//打印集合
System.out.println("删除前:" + c);
//调用remove方法进行删除
boolean flag = c.remove("牛顿");
System.out.println("删除后:" + c);
System.out.println("flag:" + flag);
}
//public void clear(): 清除集合中的所有元素
public static void method2() {
//创建集合,并添加元素
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//打印集合中的内容
System.out.println("清除前:" + c);
//调用clear方法,清除集合中的元素
c.clear();
System.out.println("清除后:" + c);
}
//public boolean add(E e) : 向集合中添加元素
public static void method() {
//创建一个集合对象
Collection<String> c = new ArrayList<>();
//调用add方法,向集合中添加元素
c.add("达尔文");
c.add("牛顿");
c.add("霍金");
//直接打印集合
System.out.println(c);
}
}
2、迭代器-Iterator
如何对集合进行遍历?
我们之前使用的for循环根据索引依次获取集合中的每个元素 这种方式并不能适用于所有的集合, 因为有 些集合是没有索引的。
有一种通用的遍历方式,这个遍历方式叫做迭代器遍历。
迭代器就是一个遍历集合的工具, 里面有一个光标, 这个光标最开始指向集合的最开头(最左边)。
如何获取集合的迭代器? 调用Collection中的iterator方法即可
Iterator<E> iterator():获取集合的迭代器。
Iterator<E>,表示的就是迭代器,如果要使用迭代器进行遍历,那么还需要使用迭代器中的方法。
boolean hasNext(): 判断当前光标位置有没有元素,如果有元素,那么结果就是true。
E next(): 获取当前光标位置的元素,然后把光标后移。
迭代器遍历的步骤:
1. 调用集合的iterator方法获取集合的迭代器对象
2. 调用Iterator迭代器的hashNext方法, 判断是否有元素可以获取
3. 如果有元素可以获取,那么就调用迭代器的next方法,获取元素并且把光标后移。
public class Demo01Iterator {
public static void main(String[] args) {
//创建一个集合对象
Collection<String> c = new ArrayList<>();
//向集合中添加元素
c.add("hello");
c.add("world");
c.add("java");
//对集合中的内容进行遍历, 依次获取集合中的每一个元素并打印
//调用集合的iterator方法获取集合的迭代器对象
Iterator<String> iterator = c.iterator();
//使用while循环对集合进行遍历
while(iterator.hasNext()) { //如果有元素可以拿,那么我们就一直获取元素
//如果还有元素可以拿,那么我们就获取这个元素并打印
System.out.println(iterator.next());
}
/*
//调用Iterator迭代器的hashNext方法, 判断是否有元素可以获取
System.out.println(iterator.hasNext());
//获取当前位置的元素,并且把光标向后移动
System.out.println(iterator.next()); //hello
System.out.println(iterator.hasNext());//继续判断这个位置还有没有元素可以获取
System.out.println(iterator.next()); //world 获取当前位置的元素,并且把光标向后移动
System.out.println(iterator.hasNext());// 继续判断这个位置还有没有元素可以获取
System.out.println(iterator.next());//java 获取当前位置的元素,并且把光标向后移动
System.out.println(iterator.hasNext()); //false
System.out.println(iterator.next()); //NoSuchElementException
*/
}
}
3、增强for
在jdk5之后,多了一个新的遍历方式,叫做增强for循环遍历(foreach)
格式:
for(数据类型 变量名 : 容器名) {
//...
}
格式解释:
数据类型: 要遍历的容器里面的数据是什么类型的,那么这个数据类型就写什么。
变量名: 表示容器中的每一个元素。
容器名: 这个容器可以是数组,也可以是一个集合。 JDK规定,实现了Iterable接口,才可以成为增强for循环的目标。
增强for循环是普通for的语法糖(本质没有变,只不过语法更加的简洁),
使用增强for遍历数组,本质还是普通for遍历数组。
增强for的好处以及缺点:
好处: 增强for省去了索引的操作,语法更加的简洁。
缺点: 不能操作索引, 所以如果遍历的时候需要使用索引,还得用普通for循环。
public class Demo01Foreach {
public static void main(String[] args) {
//定义一个数组
int[] arr1 = {11, 22, 33, 44, 55};
//先使用普通for遍历这个数组
for(int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("===================");
//使用增强for遍历这个数组
for(int num : arr1) {
//变量num表示的是数组中的每一个元素,而不是索引
System.out.println(num);
}
System.out.println("===================");
//定义一个double数组
double[] arr2 = {10.1, 20.2, 30.3, 40.4, 50.5};
//使用增强for循环遍历这个数组
for(double num : arr2) {
System.out.println(num);
}
System.out.println("===================");
int[] arr = {10, 20, 30, 40, 50};
//使用增强for遍历数组,依次把数组中的每个元素改为原来的2倍
for(int num : arr) {
num *= 2;
}
System.out.println(Arrays.toString(arr));
}
}
(1)增强for遍历集合
格式:
for(数据类型 变量名 : 容器名) {
//...
}
增强for遍历集合,本质还是用的迭代器在遍历。
增强for是我们以后用的最多的遍历方式.
public class Demo02Foreach {
public static void main(String[] args) {
//定义一个集合,存放字符串
Collection<String> c = new ArrayList<>();
//存放数据
c.add("大幂幂");
c.add("小甜甜");
c.add("大冰冰");
//使用增强for遍历这个集合
for(String s : c) {
//s表示的是集合中的每一个元素
System.out.println(s);
}
System.out.println("--------------------------------");
//定义一个集合,存放学生对象
Collection<Student> c2 = new ArrayList<>();
//向集合中添加学生对象
c2.add(new Student("张三丰", 30));
c2.add(new Student("张翠山", 20));
c2.add(new Student("张无忌", 10));
//使用增强for,遍历集合
for(Student s : c2) {
System.out.println(s);
}
}
}
二、泛型
1、泛型的定义
泛型就是一种未知的,不确定的数据类型。
如果在类名后面加上<T>,那么这类就是一个泛型类。 注意<T>,里面E可以使用任何字母代替
类名后面的<T>表示定义了一种未知的不确定的数据类型,并且可以在这个类中去使用这个未知的数据类型T。
当我们使用这个类的时候,才能确定这个T表示的数据类型真正是什么。
如果想要延后泛型的确认时机,缩小泛型的使用范围。 让泛型只能在当前方法中使用,并且让泛型确认的时机
在调用方法的时候才确认,那么可以使用泛型方法(把泛型定义在方法上)
格式:
public <泛型> 返回值类型 方法名(参数类型 参数名) {
方法体;
}
在方法上定义的泛型必须等到调用的方法的时候才能够确定这个泛型到底是什么类型
总结:
泛型类是定义在类上的泛型, 这个泛型所表示的数据类型必须等到使用这个类的时候才能够确定。
泛型方法是定义在方法上的泛型,这个泛型所表示的数据类型必须等到使用方法的使用才能够确定。
public class Factory<T> {// 表示定义了一个不确定的数据类型 T类型
/*
定义一个方法,接收什么类型的参数,那么就返回什么类型的结果
*/
public <E> E getSame(E e) {
return e;
}
public <E> E function() {
return null;
}
/*
定义方法,修理任何东西
下面的两个T,表示使用了这种不确定的数据类型T
*/
public T method(T t) {
//修理...
return t;
}
/*
定义方法,可以修理任何东西
*/
/*
public Object method(Object obj) {
//修理...
return obj;
}
*/
/*
定义方法,用来修理手机
*/
/*
public Phone method(Phone p) {
//修理....
return p;
}
*/
/*
定义方法,用来修理Pad
*/
/*
public Pad method(Pad pad) {
//修理...
return pad;
}
*/
}
2、泛型定义在接口上
(1) 如果把泛型定义在接口名后面那么这个就是泛型接口
接口上面定义的泛型既可以当做方法参数,也可以当做返回值
泛型接口的使用:
1. 实现类在实现接口的时候,直接确定出来这个泛型的数据类型
2. 实现类在实现接口的时候,不确定泛型的类型。 在使用实现类的时候才确认这个泛型是什么
public interface MyInterface<T> { //表示定义了一个不确定的类型T。
T method(T t);
}
(2)定义泛型一定要在当前类或者接口名的后面
前面的<T> 是在定义泛型,表示了定义了一个不确定的数据类型T
后面的<T> 是在使用这个泛型, 使用这个泛型类型来确认接口中的泛型到底是什么类型。 因为是在使用泛型T确认接口中的泛型,所以确认之后的结果依然是不确定的
这个实现类中定义的泛型T,需要等到使用这个类的时候才能够确定
public class MyInterfaceImplB<T> implements MyInterface<T>{
@Override
public T method(T t) {
return null;
}
}
3 泛型: 就是一种未知的,不确定的数据类型。
比如ArrayList<E>, 里面的E就是一个泛型,他是一个未知的不确定的数据类型。 当我们使用这个类(创建对象)的时候,
才能够确定这个泛型类型E它所表示的类型真正是什么。
泛型是可以省略的,如果省略泛型,那么泛型默认是Object
泛型的好处:
1. 省去了强转的代码。
2. 将运行时的错误提前到了编译时期.
public class Demo01Generic {
public static void main(String[] args) {
//创建集合,不给出泛型
ArrayList list = new ArrayList();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
//list.add(100); 运行时期会报错
//遍历集合,打印集合中每个字符串的长度
for(Object obj : list) {
//因为要调用字符串的length方法,所以需要把obj对象向下转型成String
String str = (String)obj;
System.out.println(str.length());
}
System.out.println("===============================");
//创建集合,给出泛型,泛型是String
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
list2.add("world");
list2.add("java");
//list2.add(100); 编译时期报错
//遍历集合,打印集合中每一个字符串的长度
for (String str : list2) {
System.out.println(str.length());
}
}
}
4、 Java中的泛型都是伪泛型,只在源代码中有效, 一旦编译后,这个泛型就会消失。 俗称泛型擦除。
public class Demo02Generic {
public static void main(String[] args) {
//创建一个集合,指定泛型为String
ArrayList<String> list = new ArrayList<>();
list.add("你好");
list.add("我好");
list.add("大家好");
//遍历集合,拿到里面的每一个元素
for(String str : list) {
System.out.println(str);
}
}
}
三、泛型中的通配符
1、注意: 泛型之间没有继承关系。
ArrayList<Person> 不是 ArrayList<Student> 的父类.
泛型通配符 ?,可以匹配任何类型的泛型
比如ArrayList<?>, 那么它接收的泛型类型可以是任何类型,包括Person,包括Student,Teacher或者其他任意类型
泛型通配符只能被动匹配,不能主动使用
public class Demo01Test {
public static void main(String[] args) {
//创建一个集合,并添加元素
ArrayList<Student> stuList = new ArrayList<>();
stuList.add(new Student("小明", 10));
stuList.add(new Student("小黄", 12));
stuList.add(new Student("小绿", 14));
//调用方法,对这个存放Student的集合进行遍历
printArrayList(stuList);
System.out.println("---------------------------");
//创建存放老师的集合
ArrayList<Teacher> teacherList = new ArrayList<>();
teacherList.add(new Teacher("小苍老师", 35));
teacherList.add(new Teacher("小泽老师", 36));
teacherList.add(new Teacher("小波老师", 37));
printArrayList(teacherList);
/*
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
printArrayList(list);*/
//ArrayList<?> list = new ArrayList<>();
//list.add(new Object());
}
/*
定义方法,可以既能遍历存放Student的集合,又能遍历存放Teacher的集合
*/
public static void printArrayList(ArrayList<?> list) { //?表示通配符,可以匹配任何类型的泛型
//对list集合进行遍历
for(Object obj : list) {
//向下转型成Person
Person p = (Person)obj;
System.out.println(p.getName() + "-" + p.getAge());
}
}
/*
定义方法,用来遍历存放Person的集合
*/
/*
public static void printArrayList(ArrayList<Person> list) {
for(Person p : list) {
System.out.println(p.getName() + "-" + p.getAge());
}
}
*/
/*
定义方法,用来对存放Teacher的集合进行遍历
*/
/*
public static void printArrayList2(ArrayList<Teacher> list) {
for (Teacher t : list) {
System.out.println(t.getName() + "-" + t.getAge());
}
}
*/
/*
定义方法,用来对存放Student的集合进行遍历
*/
/*
public static void printArrayList(ArrayList<Student> list) {
//使用增强for循环进行遍历
for(Student stu : list) {
System.out.println(stu.getName() + "-" + stu.getAge());
}
}
*/
}
2、 泛型通配符的限定。 可以对泛型通配符的取值进行一个限制。
<? extends A>: 泛型的类型只能是A类或者A类的子类。 上限, 最高到A类。
<? super A>: 泛型的类型只能是A类或者A类的父类。 下限, 最低到A类。
泛型的使用场景: 主要用在代码的重构
public class Demo02Test {
public static void main(String[] args) {
//创建集合,并遍历
ArrayList<Student> stuList = new ArrayList<>();
stuList.add(new Student("小明", 10));
stuList.add(new Student("小黄", 12));
stuList.add(new Student("小绿", 14));
printArrayList(stuList);
System.out.println("=================================");
ArrayList<Person> personList = new ArrayList<>();
personList.add(new Person("大黄", 10));
personList.add(new Person("大紫", 12));
personList.add(new Person("大绿", 14));
printArrayList(personList);
System.out.println("=================================");
ArrayList<Object> objList = new ArrayList<>();
//printArrayList(objList); //参数集合的泛型要么是Person子类,要么是Person,不能是其他类或者Person的父类
//泛型下限
//method(stuList); //泛型要么是Person父类,要么是Person,不能是Person子类
//method(personList);
method(objList);
}
public static void method(ArrayList<? super Person> list) {
}
/*
定义方法,用来对存放Teacher和Student的集合进行遍历。
参数集合的泛型要么是Person,要么是Person的子类
*/
public static void printArrayList(ArrayList<? extends Person> list) { //参数集合的泛型要么是Person,要么是Person的子类
for(Person p : list) {
System.out.println(p.getName() + "-" + p.getAge());
}
}
}
四、斗地主案例的实现、
package cn.itcast.demo06;
import java.util.ArrayList;
import java.util.Collections;
/*
斗地主案例的分析:
1. 准备牌
a. 定义一个集合存用来放扑克牌
b. 向集合中添加54张牌
2. 洗牌
a. 打乱牌的顺序。
在java中有一个操作集合的工具类,这个工具类叫做Collections
里面有一个方法,叫做shuffle,可以打乱顺序
3. 发牌
a. 定义三个集合,保存每个玩家手里的牌。
b. 定义一个集合,保存底牌。
c. 开始发牌, 把第1张,第4张,第7张....发给第一个人 把第2,5,8...张发给第二个人。 把第3,6,9...发给第三个人.
我们可以根据索引发牌
把索引为0, 3, 6 ....这样的牌发给第一个人(索引对3取余结果是0)
把索引为1, 4, 7 ....这样的牌发给第二个人 (索引对3取余结果是1)
把索引为2, 5, 8 ....这样的牌发给第三个人 (索引对3取余结果是2)
4. 看牌
遍历打印每个玩家的集合。
*/
public class Demo01Game {
public static void main(String[] args) {
//1. 准备牌
//定义一个集合存用来放扑克牌
ArrayList<String> poker = new ArrayList<>();
//向集合中添加54张牌
//定义两个数组,一个保存花色,一个保存点数,然后再进行组合
String[] colors = {"♠", "♥", "♣", "♦"};
String[] nums = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
//进行组合
for(String num : nums) {
for(String color : colors) {
//将组合的结果添加到ArrayList集合
poker.add(color + num);
}
}
//添加大小王
poker.add("小王");
poker.add("大王");
//2. 洗牌
Collections.shuffle(poker);
//3. 发牌
//定义集合,保存每个玩家手里的牌
ArrayList<String> playerOne = new ArrayList<>();
ArrayList<String> playerTwo = new ArrayList<>();
ArrayList<String> playerThree = new ArrayList<>();
//定义集合,保存底牌
ArrayList<String> diPai = new ArrayList<>();
//开始发牌了,根据牌的索引进行发牌
for(int i = 0; i < poker.size(); i++) {
//获取到当前遍历到的扑克牌
String card = poker.get(i);
//判断,如果是不足三张牌(53 52 51)了,就放入到底牌集合
if (i >= 51) {
diPai.add(card);
continue; //直接结束本次循环,开始下次循环.
}
//把这个牌发给玩家(根据索引进行发牌)
if (i % 3 == 0) {//如果牌的索引是0 3 6...,就发给第一个玩家(索引对3取余结果是0)
playerOne.add(card);
} else if(i % 3 == 1) {//如果牌的索引是1 4 7...,就发给第二个玩家(索引对3取余结果是1)
playerTwo.add(card);
} else { //否则,这个牌的索引对3取余的结果肯定是2.就发给第三个玩家
playerThree.add(card);
}
}
//4. 看牌
lookCard("发哥", playerOne);
lookCard("华仔", playerTwo);
lookCard("星爷", playerThree);
lookCard("底牌", diPai);
}
/*
定义一个方法,用来看牌
参数: String类型的姓名, ArrayList<String> 玩家手里的牌
*/
public static void lookCard(String name, ArrayList<String> list) {
System.out.print(name + ": ");
//遍历集合,打印集合中的每一个元素
for(String card : list) {
System.out.print(card + " ");
}
//为了方便后面的操作,打印一个空换行
System.out.println();
}
}