java之进阶语法(集合简介和泛型)

一.简介

(一)概述

集合就是一种容器,可以用来存储多个数据,和数组差不多。

但是集合和数组是存在差别的:1.数组的长度是固定的,集合的长度是可变的。2.数组存储的是同一类型的元素,可以存储基本数据类型。而集合存储的都是对象,而且对象类型可以不一致。

(二)集合的框架

集合按照存储结构分为两类,即单列集合(java.util.Collection)和双列集合(java.util.Map)

(三)Collection集合

1.概述

Collection为Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

包 (bag) 或多集合 (multiset)(可能包含重复元素的无序 collection)应该直接实现此接口。 

所有通用的 Collection 实现类(通常通过它的一个子接口间接实现 Collection)应该提供两个“标准”构造方法:一个是 void(无参数)构造方法,用于创建空 collection;另一个是带有 Collection 类型单参数的构造方法,用于创建一个具有与其参数相同元素新的 collection。实际上,后者允许用户复制任何 collection,以生成所需实现类型的一个等效 collection。尽管无法强制执行此约定(因为接口不能包含构造方法),但是 Java 平台库中所有通用的 Collection 实现都遵从它。

此接口中包含的“破坏性”方法,是指可修改其所操作的 collection 的那些方法,如果此 collection 不支持该操作,则指定这些方法抛出 UnsupportedOperationException。如果是这样,那么在调用对该 collection 无效时,这些方法可能,但并不一定抛出 UnsupportedOperationException。例如,如果要添加的 collection 为空且不可修改,则对该 collection 调用 addAll(Collection) 方法时,可能但并不一定抛出异常。

一些 collection 实现对它们可能包含的元素有所限制。例如,某些实现禁止 null 元素,而某些实现则对元素的类型有限制。试图添加不合格的元素将抛出一个未经检查的异常,通常是 NullPointerException 或 ClassCastException。试图查询是否存在不合格的元素可能抛出一个异常,或者只是简单地返回 false;某些实现将表现出前一种行为,而某些实现则表现后一种。较为常见的是,试图对某个不合格的元素执行操作且该操作的完成不会导致将不合格的元素插入 collection 中,将可能抛出一个异常,也可能操作成功,这取决于实现本身。这样的异常在此接口的规范中标记为“可选”。 

由每个 collection 来确定其自身的同步策略。在没有实现的强烈保证的情况下,调用由另一进程正在更改的 collection 的方法可能会出现不确定行为;这包括直接调用,将 collection 传递给可能执行调用的方法,以及使用现有迭代器检查 collection。

Collections Framework 接口中的很多方法是根据 equals 方法定义的。例如,contains(Object o) 方法的规范声明:“当且仅当此 collection 包含至少一个满足 (o==null ? e==null :o.equals(e)) 的元素 e 时,返回 true。” 应将此规范理解为它暗指调用具有非空参数 o 的 Collection.contains 方法会导致为任意的 e 元素调用 o.equals(e) 方法。可随意对各种实现执行优化,只要避免调用 equals 即可,例如,通过首先比较两个元素的哈希码。(Object.hashCode() 规范保证哈希码不相等的两个对象不会相等)。较为常见的是,各种 Collections Framework 接口的实现可随意利用底层 Object 方法的指定行为,而不管实现程序认为它是否合适。

此接口是 Java Collections Framework 的一个成员。

2.Collection方法摘要

 booleanadd(E e) 
          确保此 collection 包含指定的元素(可选操作)。
 booleanaddAll(Collection<? extends E> c) 
          将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
 voidclear() 
          移除此 collection 中的所有元素(可选操作)。
 booleancontains(Object o) 
          如果此 collection 包含指定的元素,则返回 true。
 booleancontainsAll(Collection<?> c) 
          如果此 collection 包含指定 collection 中的所有元素,则返回 true。
 booleanequals(Object o) 
          比较此 collection 与指定对象是否相等。
 inthashCode() 
          返回此 collection 的哈希码值。
 booleanisEmpty() 
          如果此 collection 不包含元素,则返回 true。
Iterator<E>iterator() 
          返回在此 collection 的元素上进行迭代的迭代器。
 booleanremove(Object o) 
          从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
 booleanremoveAll(Collection<?> c) 
          移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
 booleanretainAll(Collection<?> c) 
          仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
 intsize() 
          返回此 collection 中的元素数。
 Object[]toArray() 
          返回包含此 collection 中所有元素的数组。
<T> T[]
toArray(T[] a) 
          返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。

 

二、Iterator接口

(一)概述

java.util.Iterator是java集合中的一员,但是与Collection和Map接口存在不同的地方。Collection和Map用于存储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。

(二)方法摘要

booleanhasNext() 
          如果仍有元素可以迭代,则返回 true。
 Enext() 
          返回迭代的下一个元素。
 voidremove() 
          从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

(三)使用步骤

  1. 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)。
  2. 使用Iterator接口中的方法hasNext判断还有没有下一个元素,有的话返回true。
  3. 使用Iterator接口的方法next取出集合的下一个元素,如果没有元素会报NoSuchElementException异常,即没有元素异常。

(四)代码实现

Collection<String> coll = new ArrayList<>();
coll.add('a');
coll.add('b');
coll.add('c');
coll.add('d');
coll.add('e');

// 1.使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
// Iterator<E>也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型
Iterator<String> it = coll.iterator();

// 2.使用Iterator接口中的方法hasNext判断还有没有下个元素
while (it.hasNext()){
  String e = it.next();
  System.out.prinln(e);
}

// 也可使用for循环实现
for(Iterator<String> it2=coll.iterator();it2.hasNext();){
  String e = it2.next();
  System.out.println(e);
}

(五)迭代器原理

(六)增强for循环

增强for循环,也称for each循环,是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是一个Iterator迭代器,所以在遍历的过程中,只能进行元素遍历,不能对集合的元素进行增删操作。

Collection<E> extends Iterable<E>:所有的单列集合都可以使用增强for。

// 遍历数组
int[] arr = {1,2,3,4,5};
for (int i:arr){
  System.out.println(i);
}

// 遍历集合
for (String s:coll){
  System.out.println(s);
}

三、泛型

1.泛型的概念

2.使用泛型的好处

  • 集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据。弊端就是:不安全,会引发异常。
  • 具体异常为不使用泛型就会在集合存入不同类型的元素,在使用元素的特定的方法时,一些不同类的元素可能不同,比如集合里存String和Integer两中类型,就不能对所有的元素用length方法。
  • 具体来说,泛型的好处为:1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型。2.把运行期异常(代码运行之后会抛出的异常),提升到了编译期(写代码的时候会报错)。

3.泛型的定义和使用

// 定义一个含有泛型的类,泛型是一个未知的数据类型,当我们不确定什么数据类型的时候,可以使用泛型,泛型可以接受任意的数据类型,创建对象的时候确定泛型的类型。
public class GenericClass<E> {
  private E name;
  public E getname(){
    return name;
  }
  public void setname(E name){
    this.name = name;
  }
}



// 数据类型可以不写死,灵活使用
GeneraicClass<Integer> gc2 = new GeneraicClass<>();
gc2.setname(1);//此时name是整型

GeneraicClass<String> gc2 = new GeneraicClass<>();
gc2.setname("abc"); // 此时name是String类型
// 定义和使用含有泛型的方法
// 定义格式:修饰符<代表泛型的变量> 返回值类型 方法名(参数(使用泛型)){ }

public class GenericMethod {
  public <E> void method1(E m){
    System.out.println(m);
  }
  public static <E> void method02(E e){
    System.out.println(e);
  }
  public static void main(String args[]){
    GenericMethod gm = new GenericMethod();
    

    gm.method1(10);
    gm.method1("abc");
    gm.method1(8.8);
    gm.method1(true);

    GenericMethod.method02("123");
  }
}

4.含有泛型的接口

 

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

public interface GenericInterface<I> {

  public abstract void method(I i);
}
// 使用方法1:定义接口的实现类,实现类指定泛型类型
public class GenericMethodImpl1 implements GenericInterface<String>{
  public void method(String s){
    System.out.println(s);
  }
}


// 使用方法2:定义接口的实现类,接口使用什么类型,实现类就用什么泛型,类跟着接口走
// 创建对象时再确定泛型的类型
public class GenericMethodImpl2 implements GenericInterface<I>{
  public void method(I s){
    System.out.println(i);
  }
}
public class demo{
  public static void main(){
    GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
    gi1.method("123");

    GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
    gi1.method(123);
    GenericInterfaceImpl1<Double> gi3 = new GenericInterfaceImpl2();
    gi1.method(123.0);

  }
}

5.泛型的通配符

(1)普通泛型

  • 当使用泛型类或接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合元素自身方法无法使用。只能接收数据,不能存储数据。
  • 泛型在定义的时候不能使用通配符,只能作为函数的方法进行传递。
public class Demo{
  public static void main(String[] args){
    ArrayList<Integer> list01 = new ArrayList<>();
    list01.add(1);
    list01.add(2);
    
    ArrayList<String> list02 = new ArrayList<>();
    list01.add("a");
    list01.add("b");

    printArray(list01);
    printArray(list02);
  }
  // 定义一个方法,能遍历所有类型的ArrayList集合,这时候,我们不知道ArrayList集合使用什么数据类型,可以使用泛型的通配符?来接收数据类型。
  public static void printArray(ArrayList<?> list){
    Iterator<?> iterator = list.iterator();
    while(iterator.hasNext()){
      Object o = iterator.next();
      System.out.println(o);
    }
  }
}

(2)受限泛型(通配符的高级使用)

/*
设置泛型的时候,是可以随意设置的,只要是类,就可以设置为泛型。但是java的泛型中可以指定一个泛型的上限和下限
- 泛型上限的格式:
  格式: 类型名称 <? extends 类> 对象名称
  意义: 只能接收该类及其子类

- 泛型上限的格式:
  格式: 类型名称 <? super 类> 对象名称
  意义: 只能接收该类及其父类
*/

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement(list1);
    getElement(list2);//报错
    getElement(list3);
    getElement(list4);//报错
  
    getElement2(list1);//报错
    getElement2(list2);//报错
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值