集合、迭代器、增强for循环、泛型
1集合
集合是java中提供的一种容器,可以用来存储多个数据。
数组的长度是固定的。集合的长度是可变的。集合中存储的元素必须是引用类型数据。
1.1ArrayList集合存储元素(复习)
例:
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
import java.util.ArrayList;
public class Test1 {
public static void main(String[] args) {
//集合复习:存储基本数据类型
ArrayList<Double> arr1=new ArrayList<Double>();
arr1.add(1.6);
arr1.add(2.3);
arr1.add(3.6);
for(int i=0;i<arr1.size();i++){
System.out.print(arr1.get(i)+" ");
}
System.out.println();
//集合存储引用数据类型
ArrayList<Person> arr2=new ArrayList<Person>();
arr2.add(new Person("张三",18));//存匿名对象
arr2.add(new Person("小红帽",8));
arr2.add(new Person("大灰狼",55));
for(int i=0;i<arr2.size();i++){
System.out.println(arr2.get(i)); //调用toString方法,已重写
}
}
}

1.2集合的继承实现关系
常用的:

1.3 Collection接口
Collection接口是集合中的顶层接口,它中定义的所有功能子类都可以使用。
Collection 是层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
(这里的有序不是指元素在值上的排序,而是指存、取的顺序一致,怎么存就怎么取,有索引下标)
1.3.1 Collection常用方法
Collection是接口,所以全是抽象方法。
需要用多态new对象。

例:
import java.util.Collection;
import java.util.ArrayList;
public class CollectionTest {
public static void main(String[] args) {
//创建对象
Collection<String> col=new ArrayList<String>();
//添加元素
col.add("中国");
col.add("你好");
col.add("java");
//判断集合中是否包含某元素
boolean flag=col.contains("java");
if(flag){
System.out.println("true,包含元素");
}
//移除元素
boolean dels=col.remove("你好"); //这个是返回布尔值
if(dels){
System.out.println("移除成功");
}
//向下转型
ArrayList<String> arr=null; //定义成全局,不然遍历时取不到
if(col instanceof ArrayList){
arr=(ArrayList<String>)col;
}
System.out.println();
//遍历
System.out.println("遍历结果:");
for(int i=0;i<arr.size();i++){
System.out.print(arr.get(i)+" ");
}
System.out.println();
System.out.println();
//转成数组
Object[] strs=col.toArray();
System.out.println("遍历数组:");
for(int i=0;i<strs.length;i++){
//String str=(String)strs[i];//这里是Object型数组,如果想转成String数组,不能直接强转,要给元素转型
System.out.print(strs[i]+" ");
}
System.out.println();
System.out.println();
//清除内容
col.clear();
System.out.println("清除后:");
for(int i=0;i<arr.size();i++){
System.out.print(arr.get(i)+" ");
}
}
}

注意:
1注意方法的返回值类型
2一定要指定泛型,不然还要强转
例:会有警告


1.4 Iterator迭代器
1.4.1定义
java中提供了很多个集合,它们在存储元素时,采用的存储方式不同。
List有序(有下标索引),set无序(看上面的继承体系图)
要取出这些集合中的元素,可通过一种通用的获取方式来完成。
迭代定义:
Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
集合中把这种取元素的方式描述在Iterator接口中。
1.4.2 Iterator接口的常用方法

hasNext()方法:用来判断集合中是否有下一个元素可以迭代。如果返回true,说明可以迭代。
next()方法:用来返回迭代的下一个元素,并把指针向后移动一位。

1.4.3 Iterator接口的对象

Iterable对象里有一个iterator() 方法,可以返回Iterator对象,Collection继承了这个方法,那么其子类或实现类就都有了这个方法,可以用这个方法创建Iterator对象。

例:(Iterator接口也可以使用<>来控制迭代元素的类型的)
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorTest {
public static void main(String[] args) {
Collection<Integer> col=new ArrayList<Integer>();
col.add(1);
col.add(2);
col.add(3);
col.add(4);
//获取迭代器对象
Iterator<Integer> it=col.iterator();
//循环
while(it.hasNext()){
int i=it.next(); //自动拆箱
System.out.println(i);
}
}
}

注意:
1)next()只能用一次,再调用,指针还会往后走,想判断,要先把值获取到,再判断值。
例:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class I2 {
public static void main(String[] args) {
Collection<Integer> col=new ArrayList<Integer>();
col.add(1);
col.add(2);
col.add(3);
col.add(4);
//获取迭代器对象
Iterator<Integer> it=col.iterator();
//用循环
while(it.hasNext()){
if(it.next()==2){
System.out.println(it.next());
}
}
}
}

说明next()又向后走了,所以要改成这样:
while(it.hasNext()){
int i=it.next();
if(i==2){
System.out.println(i);
}
}

还可以for循环,但不常用
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class I2 {
public static void main(String[] args) {
Collection<Integer> col=new ArrayList<Integer>();
col.add(1);
col.add(2);
col.add(3);
col.add(4);
for(Iterator<Integer> it=col.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
2)在进行集合元素取出时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会发生java.util.NoSuchElementException没有集合元素的错误。
例:


1.5集合元素的向下转型
集合中可以存储任何对象,那么存放进去的数据就不再是原来的类型了,而是提升成了Object。
如果集合中存放的是多个对象,这时进行向下转型会发生类型转换异常。


3增强for循环
增强for循环是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
3.1格式:
for(元素的数据类型 变量 : Collection集合or数组){
}
例:
import java.util.ArrayList;
import java.util.Collection;
public class forTest {
public static void main(String[] args) {
Collection<String> col=new ArrayList<String>();
col.add("你好");
col.add("快乐");
//使用增强for
for(String str:col){
System.out.println(str); //取到的就是String对象
}
//使用增强for遍历数组
int[] arr={1,2,3,4,5};
for(int i:arr){
System.out.print(i+" "); //i就是每个值
}
}
}

3.2对比:
1)迭代器只能迭代集合,增强for能遍历集合和数组。
2)新for循环必须有被遍历的目标。目标只能是Collection或者是数组。只用来遍历,不进行任何操作。
遍历数组时,如果仅为遍历,可以使用增强for。
如果要对数组的元素进行操作,使用老式for循环,(因为可以通过下标操作)
3.3总结:
遍历集合:三种方式
遍历数组:两种方式
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test1 {
public static void main(String[] args) {
showList();
showArr();
}
public static void showList(){
Collection<String> col=new ArrayList<String>();
col.add("abc");
col.add("ABC");
col.add("12345");
//for循环遍历
System.out.println("for循环遍历集合:");
ArrayList<String> arr=null;
if(col instanceof ArrayList){
arr=(ArrayList<String>)col;
}
for(int i=0;i<arr.size();i++){
System.out.print(arr.get(i)+"\t");
}
//迭代器
System.out.println();
System.out.println("迭代器集合:");
Iterator<String> it=col.iterator();
while(it.hasNext()){
System.out.print(it.next()+"\t");
}
//增强for
System.out.println();
System.out.println("增强for遍历集合:");
for(String str:col){
System.out.print(str+"\t");
}
}
public static void showArr(){
System.out.println();
int[] arr={1,2,3,4,5};
System.out.println("普通for遍历数组:");
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
System.out.println("增强for遍历数组:");
for(int i:arr){
System.out.print(i+" ");
}
}
}

4泛型
前面一些例子,集合中是可以存放任意对象的,提升成Object类型,这时容易发生
ClassCastException类型转换异常,泛型就是为了解决这个问题。
4.1定义
使用集合时,必须明确集合中元素的类型,这种方式称为泛型。
泛型,用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。
定义格式:
修饰符 class 类名<代表泛型的变量> { }
修饰符 interface接口名<代表泛型的变量> { }
E就是一个变量,是element的意思,在什么时候明确:
1)实现或继承时明确
Public class MyList<String> implements list<E>{}
Public class MyList<E> implements list<String>{}
2)new对象时明确
Api中带<E>的方法都是如此
4.2使用泛型的好处
将运行时期的ClassCastException,转移到了编译时期变成了编译失败。避免了类型强转的麻烦。
Tips:
泛型:又叫伪泛型,编译时不进.class文件 (注释也不进)
只在java代码中对集合存储数据类型进行约束
4.3泛型通配符
当定义方法时,无法确定具体集合中的元素类型是什么,可以使用泛型通配符<?>,用来占空。
例:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class Test02 {
public static void main(String[] args) {
ArrayList<String> arr=new ArrayList<String>();
arr.add("中国");
arr.add("java");
HashSet<Integer> set=new HashSet<Integer>();
set.add(1);
set.add(2);
showAll(arr);
showAll(set);
}
//泛型通配符
public static void showAll(Collection<?> col){
Iterator<?> it=col.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}

但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。(可以向下转型,但是太麻烦了)
4.4泛型限定
泛型里面没有向上向下转型的概念。所以要定好。
限定泛型的上限:
格式:? extends E
? 代表接收E类型或者E的子类型的元素
限定泛型的下限:
格式:? super E
? 代表接收E类型或者E的父类型的元素(父类型,不只是父类)
例:
//员工类
public abstract class Emp {
public abstract void work();
}
//经理类
public class Manager extends Emp{
public void work() {
System.out.println("经理管理");
}
}
//服务员类
public class Waiter extends Emp{
public void work() {
System.out.println("服务员上菜");
}
}
//厨师类
public class Cooker extends Emp{
public void work() {
System.out.println("厨师炒菜");
}
}
import java.util.ArrayList;
public class Test03 {
//四个类:员工,经理,服务员,厨师 都有work方法
//传入三个类调用其work方法
public static void main(String[] args) {
Manager m=new Manager();
ArrayList<Manager> arr1=new ArrayList<Manager>();
arr1.add(m);
Waiter w=new Waiter();
ArrayList<Waiter> arr2=new ArrayList<Waiter>();
arr2.add(w);
Cooker c=new Cooker();
ArrayList<Cooker> arr3=new ArrayList<Cooker>();
arr3.add(c);
working(arr1);
working(arr2);
working(arr3);
ArrayList<Object> arr4=new ArrayList<Object>();
arr4.add("这是一个Object类型的数据");
arr4.add("这是一个Object类型的数据2");
working2(arr4);
}
public static void working(ArrayList<? extends Emp> arr){ //限定泛型的上限
Emp emp=arr.get(0);
emp.work();
}
public static void working2(ArrayList<? super Emp> arr){ //限定泛型的下限
for(int i=0;i<arr.size();i++){
System.out.println(arr.get(i));
}
}
}

这里如果是接口,也可以用extends。

浙公网安备 33010602011771号