Java中Collection集合、Iterator迭代器、泛型

集合是Java中提供的一种容器,可以用来存储多个数据,可以对其中的数据进行操作

一、集合继承关系


 由上图可以看到,Collection接口为集合中的顶层接口,Collection 接口下面分为两大部分,左边为 List 接口,右边为 Set 接口,在List 接口下面有两个分支,分别为 ArrayList 类和 LinkedList 类,在 Set 接口下面也有两个分支,分别为 HashSet 类和 LinkedHashSet 类

collection 接口常用的子接口有:List 接口、Set 接口

List 接口常用的子类有:ArrayList 类、LinkedList 类

Set 接口常用的子类有:HashSet 类、LinkedHashSet 类

二、Collection接口

Collection 接口是所有集合的顶层接口,其所有功能子类都可以使用,Collection 表示一组对象,这些对象也称为 collection 的元素,其中List 接口允许存放重复的元素,并且元素都是有序的,而Set 接口不允许存放重复元素,并且元素是无序的

1、Collection 集合创建格式

方法一:Collection<元素类型> 变量名 = new ArrayList<元素类型>();   ==>只能存储<>中指定的元素类型,比较常用的方式

方法二:Collection 变量名 = new ArrayList();   ==>集合的元素默认为Object类型,可以存储任何类型的元素

2、Collection 接口的基本方法

boolean add(Object obj):添加一个元素

void clear():移除collection中所有元素(集合还在)

boolean contains(Object obj):判断对象是否存在集合中

boolean remove(Object obj):移除集合中指定的元素(删除第一个遇到的元素)

int size():返回集合中元素的个数

Object[] toArray():把集合中的元素转成数组中的元素(集合转成数组)

逻辑实例:

Collection<String> C = new ArrayList<>();    //创建集合

C.add("abc");    //添加元素

C.add("bcd");

C.add("cef");

System.out.println(C.contains("d"));    //判断元素是否在集合中

System.out.println(C.size());  //返回集合的元素个数

C.remove("abc");    //移除集合中的元素

Object[] O = C.toArray();  //将集合转换成数组

for(int i = 0;i < O.length;i++)    //遍历打印数组

{

    System.out.println(O[i]);

}

 三、Iterator 迭代器

在集合中,由于采取的存储数据方式不同,获取数据方式也会不同,为了能够使用同一种方式来获取数据,Java 中采用 Iterator 迭代器来获取数据,即遍历获取,称之为迭代

Collection 集合获取数据的通用方法:先判断集合中有没有元素,如果有,就把元素取出来并继续判断,如果还有就继续取出,一直把集合中的元素全部取出。即迭代。集合中把这种取元素的方式描述在 Iterator 接口中,

1、Iterator 迭代器的实现

在ArrayList 中重写了方法 iterator(),返回了 Iterator 接口的实现类的对象

使用ArrayList集合的对象 array,Iterator it =array.iterator(),运行结果就是 Iterator 接口的实现类的对象

it 是接口的实现类对象,调用方法 hasNext 和 next 集合元素迭代

2、Iterator 迭代器中常用的方法

boolean hasNext():判断集合中是否还有元素可以迭代

next():获取出可以迭代的下一个元素

void remove():从迭代器指向的集合中移除迭代器返回的最后一个元素

逻辑实例:

Collection<String> C = new ArrayList<>();    //创建集合

C.add("abc");    //添加元素

C.add("bcd");

C.add("cef");

//迭代器,对集合ArrayList中的元素进行取出

//调用集合的方法iterator()获取出Iterator接口的实现类的对象

Iterator<String> it = C.iterator();

//迭代是反复内容,使用循环实现,循环的条件,集合中没元素, hasNext()返回了false

while(it.hasNext())

{

    String s = it.next();

    System.out.println(s);

}

四、集合迭代中的转型

当使用第二种方法:Collection 变量名 = new ArrayList();  创建集合的时候,集合中就能存储任意类型的对象,存储时提升了 Object,这样一来,取出时要使用元素的特有内容,必须向下转型。所以说一般使用第一种方法创建集合,这种不常用。

逻辑实例:

Collection C = new ArrayList();    //创建集合

C.add("abc");    //添加元素

C.add("bcd");

C.add("cde");

Iterator it = C.iterator();    //调用集合的方法iterator()获取出,Iterator接口的实现类的对象

while (it.hasNext())

{

    //由于元素被存放进集合后全部被提升为Object类型

    //当需要使用子类对象特有方法时,需要向下转型

    String str = (String) it.next();

    System.out.println(str.length());

}

 注:如果集合中存放的是多个对象,这时进行向下转型会发生类型转换异常,这时,就要采用泛型来解决这个问题

五、泛型

在进行迭代的转型的时候,如果集合中存放的是多个对象,进行向下转型就会发生 ClassCastExpception 的异常,这时,必须明确集合中元素的类型。这种方式称之为:泛型(在JDK1.5之后出现的)

1、泛型的定义

泛型表示:使用 < 元素类型 > 指明集合中存储数据的类型。如:Collection<元素类型> 变量名 = new ArrayList<元素类型>();

Java 中的伪泛型:泛型只在编译的时候存在,编译之后就擦除,在编译之前就可以限定其集合的类型

2、泛型类

格式:修饰符 class 类名<代表泛型的变量> {  }

​//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型

//在实例化泛型类时,必须指定T的具体类型

public class Generic<T>{

    //key这个成员变量的类型为T,T的类型由外部指定 

    private T key;

    public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定

        this.key = key;

    }

    public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定

        return key;

    }

}

在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。

3、泛型接口

格式:修饰符 interface 接口名 <代表泛型的变量>{  }

泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中

//定义一个泛型接口

public interface Generator<T> {

    public T next();

}


当实现泛型接口的类,未传入泛型实参时:

/**

* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中

* 即:class FruitGenerator<T> implements Generator<T>{

* 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"

*/

class FruitGenerator<T> implements Generator<T>{

    @Override

    public T next() {

        return null;

    }

}


 当实现泛型接口的类,传入泛型实参时:

/**

* 传入泛型实参时:

* 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>

* 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。

* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型

* 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。

*/

public class FruitGenerator implements Generator<String> {

    private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

    @Override

    public String next() {

        Random rand = new Random();

        return fruits[rand.nextInt(3)];

    }

}

参考:https://blog.csdn.net/s10461/article/details/53941091

4、泛型通配符

泛型通配符 ‘ ?’是一个类型“实参”,不是一个类型“形参”。它可以被看作成所有类型(如Integer、String、Number)的父类,即 泛型类名称与同一泛型类名称并不是子父类的关系。具体来说就是,当我们想实现一个方法,方法的参数是 泛型类名称的时候,如果我们还想实现同一泛型类名称的时候,只能重新编写一个参数为 同一泛型类名称的方法,但这不符合java的多态思想,多态思想要求我们用一个逻辑引用类型就可以同时表示它们,这时候泛型通配符‘?’就排上了用场,把<>里面变成‘?’就把上面的问题解决了。

public static void main(String[] args) {

  ArrayList<String> array = new ArrayList<String>();


  HashSet<Integer> set = new HashSet<Integer>();


  array.add("123");

  array.add("456");


  set.add(789);

  set.add(890);


  iterator(array);

  iterator(set);

}

/*

*  定义方法,可以同时迭代2个集合

*  参数: 怎么实现 , 不能写ArrayList,也不能写HashSet

*  参数: 或者共同实现的接口

*  泛型的通配,匹配所有的数据类型  ?

*/

public static void iterator(Collection<?> coll){

  Iterator<?> it = coll.iterator();

  while(it.hasNext()){

//it.next()获取的对象,什么类型

System.out.println(it.next());

  }

}


5、泛型限定

public static void main(String[] args) {

  //创建3个集合对象

  ArrayList<Person> P = new ArrayList<Person>();

  ArrayList<Teacher> T = new ArrayList<Teacher>();

  ArrayList<Student> S = new ArrayList<Student>();


  //每个集合存储自己的元素

  P.add(new Person("张三", "休息001"));

  P.add(new Person("李四", "休息002"));


  T.add(new Teacher("王老师", "上课001"));

  T.add(new Teacher("易老师", "上课002"));


  S.add(new Student("小名", "学习001"));

  S.add(new Student("小强", "学习002"));


  iterator(P);

  iterator(T);

  iterator(S);

}

/*

* 定义方法,可以同时遍历3集合,遍历三个集合的同时,可以调用工作方法 work

* ? 通配符,迭代器it.next()方法取出来的是Object类型,怎么调用work方法

* 强制转换:  it.next()=Object o ==> Employee

* 方法参数: 控制,可以传递Employee对象,也可以传递Employee的子类的对象

* 泛型的限定  本案例,父类固定Employee,但是子类可以无限?

*  ? extends Employee 限制的是父类, 上限限定, 可以传递Employee,传递他的子类对象

*  ? super  Employee 限制的是子类, 下限限定, 可以传递Employee,传递他的父类对象

*/

public static void iterator(ArrayList<? extends Employee> array){


  Iterator<? extends Employee> it = array.iterator();

  while(it.hasNext()){

//获取出的next() 数据类型,是什么Employee

Employee e = it.next();

e.work();

  }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容