zoukankan      html  css  js  c++  java
  • java Type及项目实践

    java Type及项目实践

    一. 泛型基础

    泛型接口

    public interface ITest<T> {
    
    }
    

    泛型方法

    public <T> T testMethod(T param) {
        return param;
    }
    

    匿名类

    ITest t = new Itest<String> {
    
    }
    

    泛型边界

    // 下面定义的泛型为带边界的泛型
    public interface ITestWithUpper<T extend List> {
    }
    

    泛型擦除

    Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。
    如在代码中定义List和List等类型,在编译后都会变成List,JVM看到的只是List,而由泛型附加的类型信息对JVM是看不到的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法在运行时刻出现的类型转换异常的情况.

    public class Test {
       public static void main(String[] args) throws Exception {
            ArrayList<Integer> list = new ArrayList<Integer>();
            list.add(1);  //这样调用 add 方法只能存储整形,因为泛型类型的实例为 Integer
            list.getClass().getMethod("add", Object.class).invoke(list, "asd");
    
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
        }
    }
    
    // 其实运行可以发现,上述代码“asd”是可以被添加到List中去的,说明List存储的是原始对象(Object)
    

    其实掌握以上基本上能cover住日常开发需求了。

    二. type相关需求介绍

    1. 客户端对网络请求进行了封装
    2. 网络真实返回数据格式形如Result,而业务希望获取的时Result里面的data
    Result<T> {
        T data;
        String code;
        String extra;
        String msg;
    }
    
    1. 返回数据使用Gson解
      data数据可能格式有两种:
      {"key1":"value1","key2":"value2"}
      [{"key1":"value1_0","key2":"value2_0"},{"key1":"value1_1","key2":"value2_1"}]

    假如RealResult

    public RealResult {
    @SerialName("key1")
    String key1;
    @SerialName("key2")
    String key2
    }
    
    1. 封装层需要支持以上两种数据的解析,并通过Gson一次完成数据解析
      解决方案:
    private Type getResponseType() {
            if (mListResult) {
                // 生成List<T> 中的 List<T>
                Type listType = new ParameterizedTypeImpl(List.class, new Class[]{mResultClz});
                // 根据List<T>生成完整的Result<List<T>>
                return new ParameterizedTypeImpl(Result.class, new Type[]{listType});
            } else {
                return new ParameterizedTypeImpl(Result.class, new Class[]{mResultClz});
            }
        }
    

    ParameterizedTypeImpl代码如下:

    public class ParameterizedTypeImpl implements ParameterizedType {
    
        private final Class mRaw;
        private final Type[] mArgs;
    
        public ParameterizedTypeImpl(Class raw, Type[] args) {
            this.mRaw = raw;
            this.mArgs = args != null ? args : new Type[0];
        }
    
        @Override
        public Type[] getActualTypeArguments() {
            return mArgs;
        }
    
        @Override
        public Type getRawType() {
            return mRaw;
        }
    
        @Override
        public Type getOwnerType() {
            return null;
        }
    }
    

    gson解析

    Gson.fromJson(String xxxx, getResponseType()) 即可获取到Result类型的数据,
    再将Result里面的data返回给业务。

    三. Type

    /**
     *Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
     *从JDK1.5开始使用。
     */
    
    public interface Type {
        /**
         * Returns a string describing this type, including information
         * about any type parameters.
         *
         * @implSpec The default implementation calls {@code toString}.
         *
         * @return a string describing this type
         * @since 1.8
         * @hide Pending tests
         */
        default String getTypeName() {
            return toString();
        }
    }
    
    原始类型:一般意义上的java类,由class类实现
    参数化类型:ParameterizedType接口的实现类
    数组类型:GenericArrayType接口的实现类
    类型变量:TypeVariable接口的实现类
    基本类型:int,float等java基本类型,其实也是class
    

    网上贴出了一个例子:

    public class TestReflect {
        public static void test(TestReflect p0,
                                List<TestReflect> p1,
                                Map<String,TestReflect> p2,
                                List<String>[] p3,
                                Map<String,TestReflect>[] p4,
                                List<? extends TestReflect> p5,
                                Map<? extends TestReflect,? super TestReflect> p6){
    
        }
    

    以下代码获取七个参数的type

    Method[] methods=TestReflect.class.getMethods();
    Type[] types=oneMethod.getGenericParameterTypes(); // 获取p0-p6 7个参数的type
    

    Class(原始类型/raw types)

    普通的java类(比如String,Integer,Method等等),
    数组,
    自定义类(比如我们自己定义的TestReflect类),
    8种java基本类型(比如int,float等)
    可能还有其他的类
    
    Class type0=(Class)types[0];
    System.out.println("type0:"+type0.getName());
    
    // 输出结果为: type0:com.selftest.test.testapp3.java_type.Types.TestReflect
    

    ParameterizedType

    当需要描述的类是泛型类时,比如List,Map等,不论代码里写没写具体的泛型,java会选择ParameterizedType接口做为Type的实现。
    真正的实现类是sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl。
    ParameterizedType接口有getActualTypeArguments()方法,用于得到泛型的Type类型数组。

    //第二个参数,List< TestReflect > p1
    Type type1=types[1];
    Type[] parameterizedType1=((ParameterizedType)type1).getActualTypeArguments();
    Class parameterizedType1_0=(Class)parameterizedType1[0];  // 如果有多个泛型都可以获取,如p2
    System.out.println(parameterizedType1_0.getName());
    
    //输出结果为:  parameterizedType1_0:com.selftest.test.testapp3.java_type.Types.TestReflect
    

    上述可以获取List中泛型的Type, 针对上面网络请求封装需求时使用的就是实现ParameterizedType,将泛型传给GSON,从而能直接从GSON中直接parse出泛型对象。

    GenericArrayType

    当需要描述的类型是泛型类的数组时,比如比如List[],Map[],type会用GenericArrayType接口作为Type的实现。
    真正的实现类是sun.reflect.generics.reflectiveObjects. GenericArrayTypeImpl。
    GenericArrayType接口有getGenericComponentType()方法,得到数组的组件类型的Type对象。

    //第四个参数,List<String>[] p3
    Type type3=types[3];
    Type genericArrayType3=((GenericArrayType)type3).getGenericComponentType();
    ParameterizedType parameterizedType3=(ParameterizedType)genericArrayType3;
    Type[] parameterizedType3Arr=parameterizedType3.getActualTypeArguments();
    Class class3=(Class)parameterizedType3Arr[0];
    System.out.println("class3:"+class3.getName());
    
    输出: class3:java.lang.String
    

    WildcardType

    当需要描述的类型是泛型类,而且泛型类中的泛型被定义为(? extends xxx)或者(? super xxx)这种类型,比如List<? extends TestReflect>,这个类型首先将由ParameterizedType实现,当调用ParameterizedType的getActualTypeArguments()方法后得到的Type就由WildcardType实现。
    真正的实现类是sun.reflect.generics.reflectiveObjects. WildcardTypeImpl。
    WildcardType接口有getUpperBounds()方法,得到的是类型的上边界的Type数组,实际上就是类型的直接父类,也就是extends后面的类型。显然在当前java的设定中,这个数组只可能有一个元素,因为java现在只能extends一个类。如果实在没写extends,那他的直接父类就是Object。

    WildcardType接口有getLowerBounds()方法,得到的是类型的下边界的Type数组,有super关键字时可能会用到,经测试不会得到类型的子类,而是只得到super关键字后面的类型,如果没写super关键字,则返回空数组。

     //第六个参数,List<? extends TestReflect> p5
    Type type5=types[5];
    Type[] parameterizedType5=((ParameterizedType)type5).getActualTypeArguments();
    Type[] parameterizedType5_0_upper=((WildcardType)parameterizedType5[0]).getUpperBounds();
    Type[] parameterizedType5_0_lower=((WildcardType)parameterizedType5[0]).getLowerBounds();
    System.out.println("upper=" + parameterizedType5_0_upper[0]);
    System.out.println("lower=" + parameterizedType5_0_lower.length);
    
    // 输出:
    // upper=class com.selftest.test.testapp3.java_type.Types.TestReflect
    // lower=0
    

    TypeVariable

    Type的最后一种实现形式是TypeVariable接口,这种实现形式是在泛型类中使用的。
    比如我们定义一个泛型类TestReflect,那么当调用Class.getTypeParameters()方法得到的Type数组,数组的元素就是由TypeVariable接口实现的。 可以通过getTypeParameters判断一个类是否为泛型类。
    真正的实现类是sun.reflect.generics.reflectiveObjects. TypeVariableImpl。

    public class TypeTestClass<RESULT> {}
    
    TypeVariable[] types =  TypeTestClass.class.getTypeParameters();
    System.out.println("type=" + types[0].getName());
    
    //输出为:type=RESULT, 只能获取显示的泛型名,不能获取到真正的类型
    

    https://www.jianshu.com/p/a8e883aa3351

  • 相关阅读:
    docker 原理之 mount namespace(下)
    docker 原理之 namespace (上)
    十种世界顶级思维方式
    Go 标准库 net
    斐波拉契序列的 Go 实现
    channel 是怎么走上死锁这条路的
    hello world 的并发实现
    使用链表和切片实现栈和队列
    非暴力沟通-读后感
    CCS
  • 原文地址:https://www.cnblogs.com/NeilZhang/p/12193596.html
  • Copyright © 2011-2022 走看看