参数化类型——Java泛型

参数化类型: 数据的类型会影响程序的行为。

类型限定: 程序支持的数据类型是有范围的。

Java里的泛型: GenericType 

当我们写出下面这样的代码时,Parent<T>是一个泛型类型,它的参数范围是从顶层类型Object向下到任意一个类型。Parent<Integer>不是泛型,它是ParameterizedType,它支持的数据类型只有Integer。

package example;

import java.lang.reflect.ParameterizedType;

public class GenericAndParameterized {

static class Parent<T>{}
static class Child extends Parent<Integer>{}

public static void main(String[]args){
System.out.println(Parent.class.getName());
System.out.println(Parent.class.getTypeParameters()[0].getName());
System.out.println(Child.class.getGenericSuperclass().getTypeName());
System.out.println( Child.class.getGenericSuperclass().getClass().getTypeParameters().length);
System.out.println( Child.class.getGenericSuperclass() instanceof ParameterizedType);
}
}

  

输出:

example.GenericAndParameterized$Parent
T
example.GenericAndParameterized$Parent<java.lang.Integer>
0
true

  

Java的泛型擦除:下面这个例子解释了什么是泛型的编译期检查,什么是泛型擦除。理解了这些就能明白为什么泛型通配符为什么是这样的含义。这里遗留的一个问题是:Java中ParamterizedType类型在什么时候生成。

package example;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class GenericDescription {

    static class Parent{}
    static class Child extends Parent{}
    static class Descriptor<T extends Parent>{
        public void describe(T t){}
    }
    public static  void main (String[]args){

        Child child = new Child();
        Parent parent = new Parent();
        Descriptor<Child> descriptor = new Descriptor<Child>();
        descriptor.describe(child);
//        编译检查不允许使用Parent类型
//        descriptor.describe(parent);
        try{
            Method method = Descriptor.class.getMethod("describe", Parent.class);
            method.invoke(descriptor, parent);
            System.out.println(" it's ok to describe parent type");
            method.invoke(descriptor, new Object());
        }catch (Exception e){
//            e.printStackTrace();
            String upperBoundTypeName = Descriptor.class.getTypeParameters()[0].getBounds()[0].getTypeName();
            System.out.println(" it can not describe an Object type " +
                    "because the type variable's upper bound is " + upperBoundTypeName);
        }
        System.out.println("所以,Java的泛型擦除是指 " +
                "把 泛型从编译期间的支持特定参数类型 解放到 运行期间的支持定义域内的全部类型");

        /**
         * 变量a,b满足关系a<=b时,如果函数f(x)满足f(a)<=f(b),那么f(x)是协变的
         * 变量a,b满足关系a<=b时,如果函数f(x)满足f(a)>=f(b),那么f(x)是逆变的
         * 变量a,b满足关系a<=b时,如果函数f(x)既不满足f(a)<=f(b),又不满足f(a)>=f(b),那么f(x)是不变的
         */

        Object[] objects;
        Integer[] integers = new Integer[10];
        objects = integers;
        System.out.println("this means 数组是协变的");

        List<Object> objectList = new ArrayList<>();
        List<Integer> integerList = new ArrayList<Integer>();
//        objectList = integerList;
        System.out.println("we can't refer objectList to integerList because 列表是不变的");
        System.out.println("Java泛型的编译期检查是针对特定类型的,这就可以解释下面的几种写法");

        List data = new ArrayList();
        data.add(new Child());
        List<? extends Child> listWithUpperBounds = data;
        List<? super Child> listWithLowerBounds = new ArrayList<>();
        listWithLowerBounds.add(listWithUpperBounds.get(0));
        System.out.println("we can't get an element from listWithLowerBounds " +
                "because we can't refer to elements with a upper bounds type");
        System.out.println("we can't put an element into listWithUpperBounds " +
                "because we can't convert parent type to one of children types");

        List<?> list = new ArrayList<>();
        list.add(null);
        listWithUpperBounds.add(null);
        System.out.println("but we always can put an null into a generic list" +
                "because any type's value can be null");

        List rawList = new ArrayList();
        rawList = integerList;
        Object everyThing = new Object();
        rawList.add(everyThing);
        System.out.println("using raw type is unsafe " +
                "because we have judge the meaning of codes subjectively " +
                "and sometimes it's hard to know the intentions of coders " +
                "and we lost protection from the compiler with inspections");

    }
    /**
     * 自限定和参数协变
     * java 已经支持 返回值协变
     * java 的参数协变可以使用泛型来实现
     * 更具体的类型,更丰富的操作
     */

    /**
     * 这个例子里,T是当前类型的子类,且T的父类是Direction<T>
     * @param <T>
     */
    abstract class Direction<T extends Direction<T>>{
        abstract T get();
        abstract void set(T t);
    }

    abstract class KeepDirection<T extends KeepDirection<T>> extends Direction<T>{
        @Override
        T get() {
            return null;
        }

        @Override
        void set(T t) {

        }
    }
    class WithDirection extends KeepDirection<WithDirection> {
        @Override
        WithDirection get() {
            return super.get();
        }

        @Override
        void set(WithDirection withDirection) {
            super.set(withDirection);
        }
    }


    class SameDirection extends Direction<SameDirection>{
        @Override
        SameDirection get() {
            return null;
        }

        @Override
        void set(SameDirection sameDirection) {

        }
    }
}

  

  

输出:

it's ok to describe parent type
it can not describe an Object type because the type variable's upper bound is example.GenericDescription$Parent
所以,Java的泛型擦除是指 把 泛型从编译期间的支持特定参数类型 解放到 运行期间的支持定义域内的全部类型
this means 数组是协变的
we can't refer objectList to integerList because 列表是不变的
Java泛型的编译期检查是针对特定类型的,这就可以解释下面的几种写法
we can't get an element from listWithLowerBounds because we can't refer to elements with a upper bounds type
we can't put an element into listWithUpperBounds because we can't convert parent type to one of children types
but we always can put an null into a generic listbecause any type's value can be null
using raw type is unsafe because we have judge the meaning of codes subjectively and sometimes it's hard to know the intentions of coders and we lost protection from the compiler with inspections

  

猜你喜欢

转载自www.cnblogs.com/afraidToForget/p/10727014.html