原文http://www.iteye.com/topic/585900
/* * 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<String, ListBean> list = new HashMap<String, ListBean>(); 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))); } }
这个只是我最近在写一个反射调用的东西想到的问题,所以很无奈才必须要这样得到东西
下面是结果
Ljava/util/Map<Ljava/lang/String;Lorg/javazone/jroi/test/reflect/ListBean;>;
字符串都有了,你怕什么呢?呵呵!
后话:这个方法并不应该被推荐,因为java api下并未提供任何方法实现,也就是说我们必须在特定环境和版本下才能这样干,至少得是1.5之后的版本以后sun(现在是oracle了)准备怎么改,这个是他的说法。。。
--------------------------------------------------------------------
OK,这个是一个引子,从这里我们看到了好些个玩意,也就是java其实提供了获取的方案的
那么我们要进行私有操作的,这样对我们写代码养成这样的习惯可不好,没事就去拿私有的东西,那是不是应该有公共的方法呢?我们试一下
将main里的调用修改一下
Field c = Bean.class.getField("list"); System.out.println(c.toGenericString());
public java.util.Map<java.lang.String, org.javazone.jroi.test.reflect.ListBean> org.javazone.jroi.test.reflect.Bean.list
看看,我们拿到了什么,不需要setAccess了,呵呵
哦,对了,你或许要问如果我不是字段呢?是方法怎么办。。于是乎
package org.javazone.jroi.test.reflect; import java.util.HashMap; import java.util.Map; /** * @author Sandy Zhang */ public class Bean { public Map<String, ListBean> list = new HashMap<String, ListBean>(); public Map<String, ListBean> getList() { return list; } public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException { System.out.println(Bean.class.getMethod("getList").toGenericString()); } }
public java.util.Map<java.lang.String, org.javazone.jroi.test.reflect.ListBean> org.javazone.jroi.test.reflect.Bean.getList()
---------------------------------------------------------------------
字符串有了,我们考虑下,API里是不是应该也提供了方法直接获取泛型类型,参考下
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,下面我们看一下怎么实现吧
public class GenericTest { public List<String> list = new LinkedList<String>(); 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]); } }
1
class java.lang.String
这里是结果
---------------------------------------------------------------------
于是乎,所有的问题都迎刃而解了。
似乎文章很长,我通过Debug的方式发现了代码的运行过程,最终找到了核心字符串,说明即使是檫除式的泛型java也会记录下这些东西,没道理拿不到