java Type及项目实践

java Type及项目实践

一. 泛型基础

泛型接口

public interface ITest {

}

泛型方法

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

匿名类

ITest t = new Itest {

}

泛型边界

// 下面定义的泛型为带边界的泛型
public interface ITestWithUpper {
}

泛型擦除

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

public class Test {
   public static void main(String[] args) throws Exception {
        ArrayList list = new ArrayList();
        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 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 中的 List
            Type listType = new ParameterizedTypeImpl(List.class, new Class[]{mResultClz});
            // 根据List生成完整的Result>
            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 p1,
                            Map p2,
                            List[] p3,
                            Map[] p4,
                            List p5,
                            Map 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[] 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,这个类型首先将由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 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 {}

TypeVariable[] types =  TypeTestClass.class.getTypeParameters();
System.out.println("type=" + types[0].getName());

//输出为:type=RESULT, 只能获取显示的泛型名,不能获取到真正的类型

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

posted @ 2020-01-14 18:55  NeilZhang  阅读( ...)  评论( ...)  编辑  收藏
刷新评论 刷新页面 返回顶部

你可能感兴趣的:(java Type及项目实践)