泛型

来源:互联网 发布:中国人才流失严重知乎 编辑:程序博客网 时间:2024/05/02 04:57

一.泛型入门

1.java的参数化类型被称为泛型。在集合接口,类增加尖括号,尖括号里放一个数据类型。即表明这个数据类型只能保存特定类型的对象。

2.泛型的菱形语法,java允许在构造器后不需要带完整的泛型信息,只要给出对尖括号<>即可,java既可以推断尖括号应该是什么泛型信息。

public class DiamondTest {    public static void main(String[] args) {        List<String> books = new ArrayList<>();        books.add("ass");        books.add("bcc");        books.forEach(ele -> System.out.println(ele.length()));        Map<String,List<String>> schoolmap = new HashMap<>();        List<String> schools = new ArrayList();        schools.add("abb");        schools.add("dsfa");        schoolmap.put("数组", schools);        schoolmap.forEach((key,value) -> System.out.println(key+"--"+ value));}}

二.深入泛型

所谓泛型就是允许在定义类,接口,方法时使用类型参数,这个类型参数将在声明变量,创建对象,调用方法时动态的指定。

1.定义泛型类接口

public interface List<E>{    void add(E x);    Iterator<E> iterator();}

泛型的实质允许在定义接口,类时声明类型形参,类型形参在整个接口,类体内可以当成类型使用。当创建带泛型声明的定义类为该类定义构造器时,构造器名还是原来的类名,不要增加泛型声明,调用构造时却可以使用泛型<>形式。

2.从泛型类派生子类

当创建了带泛型声明的接口父类之后,可以为该接口创建实现类或从该父类派生子类,需要指出的是当使用这些接口,父类不能包含形参类型。定义类接口方法时可以声明类型形参,使用类接口应该为类型形参传入实际的类型。使用类接口也可以不为类型形参传入实际的类型形参。

不管泛型的实际类型参数是什么,它们在运行时总有同样的类。在内存中也只占用一块内存空间,因此在静态方法,静态初始化块或者静态变量的声明和初始化中不允许使用类型形参。

3.类型通配符

如果foo是bar的子类型,而G是具有泛型声明的类或者接口G<foo>并不是G<bar>的子类型

 为了表示各种泛型list的父类,即可以使用类型通配符,类型通配符是一个问号作为类型的实参传给List集合。List<?>

public void test(List<?> c){   for (int i = 0;i < c.size() ; i++ ){       c.get(i);       }}

因为无法确定c集合中的元素,所以不能向其中添加对象。唯一的例外是null,它是所有引用类型的实例

三.设定类型通配符的上限

List<? extends A>此处代表的未知类型一定是A的子类型,因此A称为通配符的上限,类似也不能添加对象。

abstract class Shape{    public abstract  void draw(Canvas c);}class Circle extends Shape{    public void draw(Canvas c) {    System.out.println(""+c);    }}class Renctangle extends Shape{    public void draw(Canvas c) {        System.out.println(""+c);    }}public class Canvas {    //设置类型通配符的上限List<? extends Shape>    //类型通配符下限使用List<? super Type>表示只能是Type本身或者Type的父类    //虽然Circle是Shape 的子类,但List<Circle> 不是 List<Shape>的子类    public void drawAll(List<? extends Shape> shape) {        for (Shape s : shape) {            s.draw(this);        }    }    public static void main(String[] args) {        List<Circle> ListCircle = new ArrayList<>();        ListCircle.add(new Circle());        ListCircle.add(new Circle());        List<Renctangle> ListRenctangle = new ArrayList<>();        ListRenctangle.add(new Renctangle());        ListRenctangle.add(new Renctangle());         Canvas canvas = new Canvas();         canvas.drawAll(ListCircle);         canvas.drawAll(ListRenctangle);    }}

5.设定类型形参的上限

定义类型形参设定上限用于表示传给该类型形参的实际类型要么是上限类型要么是该上限类型的子类。

public class A<T extends B>

5.泛型方法

定义类接口时可以使用类型形参,在该类的方法定义和成员变定义,接口的方法定义中这些类型形参可以被当作普通类型使用。

所谓泛型方法就是在声明方法时定义一个或者多个类型形参

public class GenericMethodTest {    //声明一个泛型方法,该方法带一个T类型形参    static <T> void fromArrayToCollection(T[] a,Collection<T> c) {        for(T o : a) {            c.add(o);        }    }    //如果形参A的类型或返回值的类型依赖于另一个形参B,则不应该使用泛型方法    static <T> void  fromArrayToCollection(T[] a,Collection<? extends T> c,String str) {    }    public static void main(String[] args) {        String[] str = new String[]{"a","b","c"};        Collection<String> c = new ArrayList<>();        fromArrayToCollection(str,c);        System.out.println(c);        Integer[] integer = new Integer[]{5,8,1,55,59};         Collection<Integer> c1 = new ArrayList<>();        fromArrayToCollection(integer,c1);        System.out.println(c1);    }}

在方法中声明的形参只能在该方法中使用,而接口类中声明的形参可以在整个接口类中使用。方法中泛型参数无需显示传入实际类型参数。

6.泛型方法和类型通配符的区别。

如果一个形参的类型或返回值的类型依赖于另一个形参的类型,则形参的类型声明不应该使用通配符。

类型通配符既可以在方法签名中定义形参的类型,也可以用于定义变量的类型,但泛型方法中的类型形参必须在对应的方法中声明。

7.泛型构造器

定义泛型构造器接下来在调用构造器时就就可以根据数据形参来推断类型形参的类型,也可以显式地为构造器的类型形参指定实际的类型。

class foo{    public <T> foo (T t){        System.out.println(t);    }}public class GenericConstructor{    public static void main(String[] args){        new foo("abc");        new foo(66);    }}

菱形语法允许在调用构造器后使用一对尖括号来代表泛型信息,如果显式指定泛型构造器的实际类型,则不可以使用菱形语法。

8.设置通配符下限

<? super Type>这个通配符表示它必须是Type本身或者是Type的父类

9.擦出和转换

当把一个具有泛型信息对象赋给一个没有泛型信息的变量时所有尖括号的类型信息将被擦除。

原创粉丝点击