Java获得泛型类型

Java代码

/*

* Copyright 2010 Sandy Zhang

*

* Licensed under the Apache License, Version 2.0 (the "License"); you may not

* use this file except in compliance with the License. You may obtain a copy of

* the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

* License for the specific language governing permissions and limitations under

* the License.

*/

/**

*

*/

package org.javazone.jroi.test.reflect;

import java.lang.reflect.Field;

import java.util.HashMap;

import java.util.Map;

/**

* @author Sandy Zhang

*/

public class Bean

{

public Map list = new HashMap();

public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException

{

Field c = Bean.class.getField("list");

Field f = Field.class.getDeclaredField("signature");

f.setAccessible(true);

System.out.println(((String) f.get(c)));

}

}

这个只是我最近在写一个反射调用的东西想到的问题,所以很无奈才必须要这样得到东西下面是结果

Java代码

Ljava/util/Map;

字符串都有了,你怕什么呢?呵呵!后话:这个方法并不应该被推荐,因为java api下并未提供任何方法实现,也就是说我们必须在特定环境和版本下才能这样干,至少得是1.5之后的版本以后sun(现在是oracle了)准备怎么改,这个是他的说法。。。--------------------------------OK,这个是一个引子,从这里我们看到了好些个玩意,也就是java其实提供了获取的方案的那么我们要进行私有操作的,这样对我们写代码养成这样的习惯可不好,没事就去拿私有的东西,那是不是应该有公共的方法呢?我们试一下将main里的调用修改一下

Java代码

Field c = Bean.class.getField("list");

System.out.println(c.toGenericString());

Java代码

public java.util.Map org.javazone.jroi.test.reflect.Bean.list

看看,我们拿到了什么,不需要setAccess了,呵呵哦,对了,你或许要问如果我不是字段呢?是方法怎么办。。于是乎

Java代码

package org.javazone.jroi.test.reflect;

import java.util.HashMap;

import java.util.Map;

/**

* @author Sandy Zhang

*/

public class Bean

{

public Map list = new HashMap();

public Map getList()

{

return list;

}

public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException

{

System.out.println(Bean.class.getMethod("getList").toGenericString());

}

}

Java代码

public java.util.Map org.javazone.jroi.test.reflect.Bean.getList()

---------------------------------字符串有了,我们考虑下,API里是不是应该也提供了方法直接获取泛型类型,参考下

Java代码

getGenericType

public Type getGenericType()返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。

如果 Type 是一个参数化类型,则返回的 Type 对象必须准确地反映源代码中使用的实际类型参数。

如果底层字段的类型是一个类型变量或者是一个参数化类型,则创建它。否则将解析它。

返回:

返回表示此 Field 对象所表示字段的声明类型的 Type 对象

抛出:

GenericSignatureFormatError - 如果一般字段签名不符合 Java Virtual Machine Specification, 3rd edition 中指定的格式

TypeNotPresentException - 如果底层字段的一般类型签名引用了不存在的类型声明

MalformedParameterizedTypeException - 如果底层字段的一般签名引用了一个因某种原因而无法实例化的参数化类型

从以下版本开始:

1.5

由此可见,在1.5之后添加了众多以Generic为关键字的方法,这些方法就是用来获取泛型参数的有效途径,但是或许表面上看不出来,因为他们都是返回的Type接口,而非ParameterizedType接口,所以我困惑了很久。OK,下面我们看一下怎么实现吧

Java代码

public class GenericTest

{

public List list = new LinkedList();

public static void main(String[] args) throws SecurityException, NoSuchFieldException

{

ParameterizedType pt = (ParameterizedType) GenericTest.class.getField(

"list").getGenericType();

System.out.println(pt.getActualTypeArguments().length);

System.out.println(pt.getActualTypeArguments()[0]);

}

}

1class java.lang.String这里是结果

-___________________________________________________________

Java泛型有这么一种规律:位于声明一侧的,源码里写了什么到运行时就能看到什么;位于使用一侧的,源码里写什么到运行时都没了。什么意思呢?“声明一侧”包括泛型类型(泛型类与泛型接口)声明、带有泛型参数的方法和域的声明。注意局部变量的声明不算在内,那个属于“使用”一侧。

Java代码

import java.util.List;

import java.util.Map;

public class GenericClass {                // 1

private List list;                     // 2

private Map map;               // 3

public U genericMethod(Map m) { // 4

return null;

}

}

上面代码里,带有注释的行里的泛型信息在运行时都还能获取到,原则是源码里写了什么运行时就能得到什么。针对1的GenericClass,运行时通过Class.getTypeParameters()方法得到的数组可以获取那个“T”;同理,2的T、3的java.lang.String与T、4的T与U都可以获得。这是因为从Java 5开始class文件的格式有了调整,规定这些泛型信息要写到class文件中。以上面的map为例,通过javap来看它的元数据可以看到记录了这样的信息:

Javap代码

private java.util.Map map;

Signature: Ljava/util/Map;

Signature: length = 0x2

00 0A

乍一看,private java.util.Map map;不正好显示了它的泛型类型被擦除了么?但仔细看会发现有两个Signature,下面的一个有两字节的数据,0x0A。到常量池找到0x0A对应的项,是:

Javap代码

const #10 = Asciz       Ljava/util/Map;;

也就是内容为“Ljava/util/Map;”的一个字符串。根据Java 5开始的新class文件格式规范,方法与域的描述符增添了对泛型信息的记录,用一对尖括号包围泛型参数,其中普通的引用类型用“La/b/c/D;”的格式记录,未绑定值的泛型变量用“Txxx;”的格式记录,其中xxx就是源码中声明的泛型变量名。类型声明的泛型信息也以类似下面的方式记了下来:

Javap代码

public class GenericClass extends java.lang.Object

Signature: length = 0x2

00 12

// ...

const #18 = Asciz       Ljava/lang/Object;;

详细信息请参考官方文档:http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf相比之下,“使用一侧”的泛型信息则完全没有被保留下来,在Java源码编译到class文件后就确实丢失了。也就是说,在方法体内的泛型局部变量、泛型方法调用之类的泛型信息编译后都消失了。

Java代码

import java.util.ArrayList;

import java.util.List;

public class TestClass {

public static void main(String[] args) {

List list = null;       // 1

list = new ArrayList(); // 2

for (int i = 0; i

}

}

上面代码中,1留下的痕迹是:main()方法的StackMapTable属性里可以看到:

Javap代码

StackMapTable: number_of_entries = 2

frame_type = 253 /* append */

offset_delta = 12

locals = [ class java/util/List, int ]

frame_type = 250 /* chop */

offset_delta = 11

但这里是没有留下泛型信息的。这段代码只所以写了个空的for循环就是为了迫使javac生成那个StackMapTable,让1多留个影。如果main()里用到了list的方法,那么那些方法调用点上也会留下1的痕迹,例如如果调用list.add("");,则会留下“java/util/List.add:(Ljava/lang/Object;)Z”这种记录。2留下的是“java/util/ArrayList."":()V”,同样也丢失了泛型信息。由上述讨论可知,想对带有未绑定的泛型变量的泛型类型获取其实际类型是不现实的,因为class文件里根本没记录实际类型的信息。觉得这句话太拗口的话用例子来理解:要想对java.util.List获取E的实际类型是不现实的,因为List.class文件里只记录了E,却没记录使用List时E的实际类型。想对局部变量等“使用一侧”的已绑定的泛型类型获取其实际类型也不现实,同样是因为class文件中根本没记录这个信息。例子直接看上面讲“使用一侧”的就可以了。知道了什么信息有记录,什么信息没有记录之后,也就可以省点力气不去纠结“拿不到T的实际类型”、“建不出T类型的数组”之类的问题了orz

java取得泛型,Java取得泛型类型相关推荐

  1. java enum 泛型,Java Enum作为Enum中的泛型类型

    我正在尝试在抽象类中创建一个抽象方法,该方法将我自己的Enum作为参数.但我也希望Enum是通用的. 所以我宣布它是这样的: public abstract > void test(Enum c ...

  2. java 内部类泛型,java – 使用泛型强制转换为内部类

    请考虑以下代码: public class Outer { public class Inner{ } public static Outer.Inner get(){ Object o = new ...

  3. Java中泛型 Class<T>、T与Class<?>、 Object类和Class类、 object.getClass() 和 Object.class

    From:Java中泛型 Class<T>.T 与 Class<?>. Object类 和 Class类. object.getClass() 和 Object.class : ...

  4. java 获取泛型的type,如何获取泛型的Type类型

    开发中很多时候都遇到或使用到泛型.例如在json转换成bean对象或其他对象,而对象中存在泛型,这时候需要用到TypeToken. Type:是java里的 java.lang.reflect.Typ ...

  5. Java 理解泛型的基本含义

    Java 泛型 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所 ...

  6. 泛型java 代码讲解_Java泛型详解

    2516326-5475e88a458a09e4.png 一,打破砂锅问到底 泛型存在的意义? 泛型类,泛型接口,泛型方法如何定义? 如何限定类型变量? 泛型中使用的约束和局限性有哪些? 泛型类型的继 ...

  7. 聊聊Java的泛型及实现

    泛型基础 泛型是对Java语言类型系统的一种扩展,有点类似于C++的模板,可以把类型参数看作是使用参数化类型时指定的类型的一个占位符.引入泛型,是对Java语言一个较大的功能增强,带来了很多的好处: ...

  8. 【转载】java中泛型使用详解

    引入 Type接口 Class类 Method类 Field类 ParameterizedType接口 TypeVariable接口 类中定义泛型变量 方法中定义泛型变量 方法中泛型参数和泛型返回值 ...

  9. java关于泛型的实验代码_[改善Java代码]强制声明泛型的实际类型

    Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. importjava.util.Arr ...

最新文章

  1. Select和SelectMany之间的区别
  2. 【Machine Learning in Action --3】决策树ID3算法
  3. 大型网站架构技术一览
  4. oracle spm使用1
  5. (反射):获取一个类的父类和父类的泛型
  6. saltstack常用参数
  7. Unity Application Block 3月12 发布的版本
  8. 决策单调性Ⅱ:斜率优化(1597: [Usaco2008 Mar]土地购买)
  9. tar.xz如何解压:linux和windows下tar.xz解压命令介绍
  10. Atitit. js mvc 总结(2)----angular 跟 Knockout o99 最佳实践
  11. html5脑图_HTML5制作思维导图
  12. 敏捷史话(十三):我被 Facebook 解雇了——Kent Beck
  13. python打分系统_做一个Python颜值打分系统,比比看杨幂和杨超越到底谁更美?
  14. Guava学习之Splitter
  15. VtkCamera总结
  16. Adobe2023全家桶win及Mac系统安装包下载及安装教程ps、pr、ai、ae安装包下载
  17. 银从个人理财在线计算机怎么使用,2017银行从业个人理财计算器使用方法
  18. Tkinter:文本框Entry
  19. Perl的opendir
  20. 大数据时代,统计学方法有多大的效果?

热门文章

  1. session原理总结
  2. Shell 反引号、$() 和 ${} 的区别
  3. error: '[class name]' does not name a type
  4. 学习CGI之前,需要配置阿帕奇---windows
  5. k8s服务发现和负载均衡(转)
  6. 6.ZigZag Conversion
  7. 项目演化系列--分布式锁
  8. 开源Math.NET基础数学类库使用(03)C#解析Matlab的mat格式
  9. 代码复审1234跟我一起来
  10. debian的甘特图工具