Java泛型的那些事

java

1.泛型概述

1.1.为什么使用泛型

没有泛型,在编写代码时只能使用具体类型或Object类型,无法做到使用者想要使用什么类型就是类型。比如:创建一个方法,形参需要指定需要使用的数据类型,在创建方法之初就已经决定了该方法可以处理的数据类型,这大大限制了编程的灵活性。正因如此,才出现了在使用时才决定具体类型是什么的泛型编程。

1.2.泛型是什么

泛:广泛、普遍,非具体的东西,泛型就是定义之初用符号表示不具体的类型,在使用的时候才动态地指定具体的类型。更应该明白这种泛型编程设计思想,使用泛型带来的好处是代码更加简洁、更加灵活、使程序更加健壮(编译期没警告,运行期不会出现类强转异常--ClassCastException)。

2.泛型接口、类、方法

泛型允许在定义接口、类、方法时使用,将在声明变量、创建对象、调用方法时动态地指定。

2.1.泛型接口

定义泛型接口:比如集合中的List接口

// 定义接口时指定泛型:E,E类型在接口中就可以作为类型使用

public interface List<E> extends Collection<E>{

……

boolean add(E e);

Iterator<E> iterator();

……

}

// 定义接口时指定泛型:K 和 V,K和V类型在接口中就可以作为类型使用

public interface Map<K,V>{

……

Set<K> keySet();

Collection<V> values();

Set<Map.Entry<K, V>> entrySet();

……

}

使用泛型接口:List接口的泛型类型E,在使用时指定为具体类型String

public static void main(String[] args) {

List<String> list = new ArrayList<>();// 指定泛型类型E=String

list.add("我只认识字符串");//boolean add(E e); 等价于boolean add(String e);

Iterator<String> iterator = list.iterator();//Iterator<E> iterator();

while (iterator.hasNext()){

String next = iterator.next();//不需要强转为String

System.out.println(next);

}

}

关于泛型接口Map<K,V> 集合怎么用,就自行编写感受下。

2.2.泛型类

普通泛型类

定义泛型类

public class DemoFx<D> {

private D dd;

public D getDd(){

return this.dd;

}

public void setDd(D dd){

this.dd = dd;

}

}

使用泛型类

public static void main(String[] args) {

DemoFx<String> stringDemoFx = new DemoFx<>();

stringDemoFx.setDd("我是字符串类型");

System.out.println(stringDemoFx.getDd());

}

泛型类的继承与实现

定义泛型类:以ArrayList 类为例,继承泛型抽象类和实现泛型接口:

public class ArrayList<E> extends AbstractList<E> 

implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

……

public E get(int index) {

rangeCheck(index);

return elementData(index);

}

……

}

使用泛型类

public static void main(String[] args) {

List<String> list = new ArrayList<String>();// 指定泛型类型E=String

list.add("我只认识字符串");

String s = list.get(0);// 返回值为String

}

2.3.泛型方法

定义泛型方法:还是ArrayList案例

public class ArrayList<E> extends AbstractList<E> 

implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

……

public <T> T[] toArray(T[] a) {

if (a.length < size)

// Make a new array of as runtime type, but my contents:

return (T[]) Arrays.copyOf(elementData, size, a.getClass());

System.arraycopy(elementData, 0, a, 0, size);

if (a.length > size)

a[size] = null;

return a;

}

……

}

使用泛型方法:public <T> T[] toArray(T[] a)

public static void main(String[] args) {

List<String> list = new ArrayList<String>();

list.add("s1");

list.add("s2");

list.add("sn");

// public <T> T[] toArray(T[] a)

String[] strings = list.toArray(new String[list.size()]);

System.out.println(Arrays.asList(strings));

}

3.类型通配符

3.1.使用类型通配符

通配符表示符号是问号<?>,它是未知类型,可以匹配任何类型,也称为无界通配符。

对比”通配符“和”泛型“创建的方法

// 通配符定义

public void foreach(List<?> list){

for (int i =0 ;i<list.size();i++) {

Object o = list.get(i);

System.out.println(o.toString());

}

}

// 泛型定义

public <T> void foreach2(List<T> list){

for(T t : list){

System.out.println(t.toString());

}

}

// 使用

public static void main(String[] args) {

List<String> list = new ArrayList<String>();

list.add("s1");

list.add("s2");

list.add("sn");

Demo demo = new Demo();

demo.foreach(list); // 通配符

demo.foreach2(list); // 泛型

}

通配符和泛型都可以实现相同的效果,并且泛型方法还可以使用本身定义的泛型类型,而通配符的”?“不可以当作数据类型来使用,所以通配符方法案例中只能用Object来接收list的元素,这也是通配符的缺点:无法确定未知类型是什么类型。

所以通配符的出现到底有什么用呢?

通配符为泛型的一种特例,无需定义既可在形参中使用的未知类型。

泛型和通配符的区别

  • Java编译器把泛型【T】推断成T类型,在代码块中允许出现 T类型变量;而把通配符【?】推断成未知类型,不存在 ?类型变量;

    以上是 Java泛型的那些事 的全部内容, 来源链接: utcz.com/z/392447.html

回到顶部