内省与JavaBean
1、内省概述
IntroSpector,是对内部进行检查,了解更多的底层细节。
JavaBean进行操作。
2、JavaBean概念:JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要
用于访问私有的字段,且方法都符合某种特殊的命名规则。
Java类,其中的方法名称等,都符合特殊的规则。只要一个类中含有get和set打头的方法,
JavaBean使用。
3、JavaBean的作用:
JavaBean中,这种JavaBean的实例
Value Object,简称VO),这些信息在类中用私有字段来储存,如果读取或
设置这些字段的值,则需要通过一些相应的方法来访问。
4、JavaBean命名方式:
的属性是根据其中的setter和getter方法来确定的,而不是依据其中的变量,如方法名为setId,
Id,getId也是如此;去掉前缀,剩余部分就是属性名称,如果剩余部分的第二个字母
getAge/setAge-->age;gettime-->time;setTime-->time;getCPU-->CPU。
5、JavaBean的好处:
JavaBean特点的类当做普通类一样可以使用,但是把它当做JavaBean类用肯定有好处的:
1)在JavaEE开发中,经常要使用JavaBean。很多环境就要求按JavaBean的方式进行操作,别人都这么用,
那么就必须要求这么做。
2)JDK中提供了对JavaBean进行操作的API,这套API称为内省,若要自己通过getX的方式来访问私有x,
API,操作JavaBean要比使用普通的方式更方便。
注:
(1)一个类被当做JavaBean使用时,JavaBaan的属性是根据方法名推断出来的,它根本看不到Java类内部的成员变量。(2)字段和属性的区别:
private String name;等
Bean属性,是含有get或set方法的那些属性的字段,即这个变量的get属性,set属性等(3)为什么要使用JavaBean?
假如你写了一段计算这个人工资的逻辑,你发现写的不好。你要重写一个,或者发现原来需要的这个
人的信息不够,你还想知道这个人的比如工龄,你是不是要修改所有关于这个方法调用的地方,
person类,只要在person类中添加一个属性,并给set\get方法
person类(bean)却不用经常改。
代码演示
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
/**
* @param args
*/
/*
* public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
//"x"-->"X"-->"getX"-->MethodGetX-->
//内省的方式:
//属性描述符:PropertyDescriptor
//get属性信息
PropertyDescriptor pd =
new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
System.out.println(retVal);
//set属性信息
Object value = 7;
PropertyDescriptor pd2 =
new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,value);
System.out.println(pt1.getX());
}
*/
//上面的get或set代码分别通过选中要重构的代码,通过右击选重构获得get和set方法:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
//一般方式:"x"-->"X"-->"getX"-->MethodGetX-->
//内省方式:
//通过get和set方法获取属性值
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
Object value = 7;
setProperty(pt1, propertyName, value);
System.out.println(pt1.getX());
}
//设置属性值的方法 //此处的类型为Object,通用,下同
private static void setProperty(Object rf, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
//创建属性描述符对象,将属性名称和加载文件等信息写入其中
PropertyDescriptor pd =
new PropertyDescriptor(propertyName,rf.getClass());
//通过反射的方法类Method,获取属性所对应的set方法
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(rf, value);
}
//获取属性值的方法
private static Object getProperty(Object rf, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
//创建属性描述符对象,获取属性所对应的名称和加载文件等信息
PropertyDescriptor pd =
new PropertyDescriptor(propertyName,rf.getClass());
//通过反射的方法类Method,获取属性所对应的get方法
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(rf);
return retVal;
}
}
6、对JavaBean的复杂内省操作:
1)在IntroSpector类中有getBeanInfo(Class cls)的方法。
2)获取Class对象的Bean信息,返回的是BeanInfo类型。
3)BeanInfo类中有getPropertyDescriptors()的方法,可获取所有的BeanInfo的属性信息,
PropertyDescriptor[]。
4)在通过遍历的形式,找出与自己想要的那个属性信息。
上面演示示例中的getProperty方法用这种方法改写成:
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object value = null;
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertyName)){
Method methodGetX = pd.getReadMethod();
value = methodGetX.invoke(pt1);
break;
}
}
注:该例只做说明,开发还是用简单的
7、BeanUtils工具包:
、BeanUtils等工具包都是由阿帕奇提供的,为了便于开发。
、好处:
)提供的set或get方法中,传入的是字符串,返回的还是字符串,因为在浏览器中,用户输入到
文本框的都是以字符串的形式发送至服务器上的,所以操作的都是字符串。也就是说这个工具包
的内部有自动将整数转换为字符串的操作。
2)支持属性的级联操作,即支持属性链。如可以设置:人的脑袋上的眼镜的眼珠的颜色。这种级联
属性的属性连如果自己用反射,那就很困难了,通过这个工具包就可以轻松调用。
、可以和Map集合进行相互转换:可将属性信息通过键值对的形式作为Map集合存储(通过staticjava.util.Map describe(java.lang.Object bean)的方法),也可以将Map集合转
JavaBean中的属性信息(通过static voidpopulate(java.lang.Object bean, java.util.Map properties)的方法)。
演示代码
System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());
BeanUtils.setProperty(pt1, "x", "9");
System.out.println(pt1.getX());
/*
//java7的新特性
Map map = {name:"zxx",age:18};
BeanUtils.setProperty(map, "name", "lhm");
*/
BeanUtils.setProperty(pt1, "birthday.time", "111");
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
PropertyUtils.setProperty(pt1, "x", 9);
System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());
BeanUtils是以字符串的形式进行操作的;PropertyUtils是以传入值本身的类型进行操作的。
如果需要返回结果以字符串的形式表现,则用BeanUtils,如果以数据本身类型返回,用PropertyUtils。
二、注解(JDK1.5新特性)
、注解的概念:注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则没有某种标记。
、作用:添加注解以后,java编译器、开发工具和其他应用程序就可以用反射来了解自己的类及各种元素上有
无何种标记,有什么标记,就会做出相应的处理。
、注解的使用
1)格式:@注解类名()。如果有属性,则在括号中加上属性名(可省略)和属性值。
2)在java.lang包中提供了最基本的annotation,即注解。
3)标记可以加在包、类、字段、方法、方法参数,以及局部变量上等等。
、java中三种最基本的注解:
1)@SuppressWarning(”deprecation”)--->压制警告
是告知编译器或开发工具等提示指定的编译器警告;
是告知具体的信息即方法已过时。
(2)Deprecated--->提示成员等已经过时,不再推荐使用。
@Deprecated是在JDK1.5中作为内置的annotation引入的,用于表明类(class)、方法
、字段(field)已经不再推荐使用,并且在以后的JDK版本中可能将其删除,编译器在默认情况
下检测到有此标记的时候会提示警告信息。
例如:假定之前的某个类升级了,其中的某个方法已经过时了,不能够将过时的方法删除,因为可能会影响
到调用此类的这个方法的某些程序,这是就可以通过在方法上加这个注解。
(3)@Override--->提示覆盖(父类方法)
加上此注解,,可对自己类中的方法判断是否是要覆盖的父类的方法,典型的例子即在集合中
equals(Object obj)方法,其中的参数类型必须是Object,才能被覆盖,若不是,加上
此注解就会提示警告。
、注解的应用--->注解类:
(1)定义格式:@interface 名称{statement}
(2)元注解(注解的注解)
Retetion)和存放的位置(Taget),这就可以通过元注解说明。
:用于说明注解保留在哪个时期,加载定义的注解之上。
①一个注解的声明周期包含:
源程序--(javac)-->class文件--(类加载器)-->内存中的字节码
javac将java源程序编译为class文件,可能会把源程序中的
一些注解去掉,进行相应的处理操作,当我们拿到源程序的时候,就看不到这些注解了。
javac把这些注解留在了源程序中(或者说留在了class文件中),当运行此class
class文件加载内存中,此时有转换的过程,即把class文件中
的注解是否保留下来也不一定。
class文件中不是字节码,只有把class文件中的内部加载进内存,用类加载器加载处理后
(进行完整的检查等处理),最终得到的二进制内容才是字节码。
Reteton(枚举类)取值:(不用记忆)
:java源文件时期,如@Overried和@SuppressWarning
: class文件时期(默认阶段)
:运行时期,如@Deprecated
:用于说明注解存放在哪些成分上,默认值是任何元素
ElementType类中的任何一个,包括:包、字段、方法、方法参数、构造器、
类等值。取值为:
PACKAGE(包声明)
FIELD(字段声明)
ANNOTATION_TYPE(注释类型声明)
CONSIRUCTOR(构造器声明)
METHOD(方法声明)
PARAMETER(参数声明)
TYPE(类、接口(包含注释类型)或枚举声明)
LOCAL_VARIABLE(局部变量声明)
注意:其中代表类的值是TYPE。因为class、enum、interface和@interface等都是属
Type的。不可用CLASS表示。
、通过反射查看其它类中的注释:
1)注解应用结构图
2)过程:
注解类:@interfaceA{}
应用了“注释类”的类:@Aclass B{}
对“应用注释类的类”进行反射操作的类:class{...},操作如下:
判断是否存在此注解类
存在的话则得到这个注释类的对象
、为注解增加基本属性
属性:
一个注解相当于一个胸牌,但仅通过胸牌还不足以区别带胸牌的两个人,这时就需要给胸牌增加
一个属性来区分,如颜色等。
(2)定义格式:同接口中的方法一样:String color();
Stringvalue() default ”ignal”;
(3)应用:直接在注解的括号中添加自身的属性,如:
”red”)
@SuppressWarnings("deprecation")是一样的,其中的"deprecation"就是属性值
注:当只有一个属性时,可直接传入属性值。如”red”
default),也可以直接传入这个属性值。
8、为注解增加高级属性
(1)可以为注解增加的高级属性的返回值类型有:
、八种基本数据类型 b、String类型 c、Class类型
、枚举类型 e、注解类型 f、前五种类型的数组
(2)数组类型的属性:
int[]arrayArr() default {1,2,3}; //可不定义默认值
@MyAnnotation(arrayArr={2,3,4}) //可重新赋值
注:若数组属性中只有一个元素(或重新赋值为一个元素),这时属性值部分可省略大括号。
(3)枚举类型的属性:
TraffLamp,它是EnumTest的内部类,其值是交通灯的三色。
EnumTest.TrafficLamplamp();
@MyAnnotation(lamp=EnumTestTrafficLamp.GREEN)
(4)注解类型的属性:
MetaAnnotation,其中定义了一个属性:String value()
MetaAnnotationannotation() default @MetaAnnotation(”xxx”);
@MyAnnotation(annotation=@MetaAnnotation(”yyy”)) --> 可重新赋值
@MetaAnnotation是MyAnnotation类的一个实例对象,同样可以认为上面的
是MetaAnnotation类的一个实例对象,调用:
MetaAnnotation ma =MyAnnotation.annotation();
System.out.println(ma.value());
(5)Class类型的属性:
Class cls();
@MyAnnotation(cls=ItcastAnnotion.class)
.class必须是已定义的类,或是已有的字节码对象
(6)基本数据类型的属性(以int为例):
int val()default 3; -->可不定义默认值
@MyAnnotation(val=7) --> 可重新赋值
演示代码
package cn.itcast.text2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.itcast.text1.EnumText;
//将定义的注解的生命周期设置在运行时期
@Retention(RetentionPolicy.RUNTIME)
//定义注解的放置位置
@Target({ElementType.TYPE,ElementType.METHOD})
//自定义注解
public @interface ItcastAnnotation {
//定义属性
String str();
int val() default 1;
int[] arr() default {2,3,4};
Class cls() default AnnotionTest.class;
EnumText.TrafficLamp lamp() default EnumText.TrafficLamp.YELLOW;
MetaAnnotation annotation() default @MetaAnnotation("sss");
}
//测试注解类,用反射查看其属性
package cn.itcast.text2;
import cn.itcast.text1.EnumText;
@ItcastAnnotation(annotation=@MetaAnnotation("anntation"),Lamp=EnumText.TrafficLamp.RED,
arr=7,val=5,str="String",cls=ItcastAnnotation.class)
public class AnnotionTest {
@SuppressWarnings("deprecation")//表示压制警告的注解
@ItcastAnnotation(str = "yyy")//有缺省值可不用写缺省部分
public static void main(String[] args) {
//反射方式查看注解
//检查类上是否有注解
if(AnnotionTest.class.isAnnotationPresent(ItcastAnnotation.class)){
//通过反射获取到注解
ItcastAnnotation annotation = AnnotionTest.class.getAnnotation(ItcastAnnotation.class);
//打印查看属性值
System.out.println(annotation);
System.out.println(annotation.str());
System.out.println(annotation.val());
System.out.println(annotation.arr().length);
System.out.println(annotation.cls().getName());
System.out.println(annotation.lamp().nextLamp());
System.out.println(annotation.annotation().value());
}
}
}
//定义枚举类,交通灯
package cn.itcast.text1;
public class EnumText {
public static void main(String[] args) {}
//定义交通灯
public enum TrafficLamp{
//定义3个元素,即此类的子类,覆写抽象方法
RED(30){
@Override
public TrafficLamp nextLamp() {return GREEN;}},
GREEN(45){
@Override
public TrafficLamp nextLamp() {return YELLOW;}},
YELLOW(5) {
@Override
public TrafficLamp nextLamp() {return RED;}};
private int time;
//构造方法
private TrafficLamp(int time){this.time = time;}
//抽象方法,转为下个灯
public abstract TrafficLamp nextLamp();
}
}
三、泛型(JDK1.5新特性)
、泛型概述
1)泛型是在JDK1.5以后出现的新特性。泛型是用于解决安全问题的,是一个安全机制。
2)JDK1.5的集合类希望在定义集合时,明确表明你要向集合中装入那种类型的数据,无法加入指定
类型以外的数据。
注:
1)泛型是提供给javac编译器使用的可以限定集合中的输入类型说明的集合时,会去掉“类型”信息,
getClass()方法的返回值和原始类型完全一样。
(2)由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入
add方法即可。
、泛型定义格式:
<>来定义要操作的引用数据类型
ArrayList<String> //声明要存入集合中的元素只能为String类型
、泛型好处:
(1)使用泛型集合,可将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象;
ClassCastException转移到了编译时期,方便与程序员解决问题,
让运行时期问题减少,提高安全性。
(2)当从集合中获取一个对象时,编译器也可知道这个对象的类型,不需要对对象进行强制转化,
避免了强制转换的麻烦,这样更方便。
、ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
ArrayList<E>泛型类型
中的E称为类型变量或类型参数
ArrayList<Integer>称为参数化的类型
中的Integer称为类型参数的实例或实际类型参数
中的<>念着typeof
称为原始类型
parametered):已经将参数变为实际类型的状态。
、参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告,例如,
Collection<String> c = new Vector;
原始类型可以引用一个参数化类型的对象,编译报告警告,例如,
原来的方法接受一个集合参数,新的类型也要能传进去
JDK1.5以前的版本。
、使用泛型时注意:
1)参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>(); //错误!
不写<Object>没错,写了就是明知故犯
也错误!
2)编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型,
例如,下面语句有错误:
Vector<Integer> vectorList[] = new Vector<Integer>[10];
注:下面的代码会报错误吗?
Vector v1 = new Vector<String>();
Vector<Object> v = v1;
不会。因为编译器编译时只进行严格语法检查,以上两条语句都符合语法规则。
、泛型通配符(?)
?
1)泛型通配符?总结:
?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用
与参数化无关的方法,不能调用与参数化有关的方法。
演示示例如下
/*定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,该方法如何定义呢? */
错误方式:
public static void printCollection(Collection<Object> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
cols.add("string");//没错
cols = new HashSet<Date>();//会报告错误!
}
正确方式:
public static void printCollection(Collection<?> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
//cols.add("string");//错误,因为它不知自己未来匹配就一定是String
cols.size();//没错,此方法与类型参数没有关系
cols = new HashSet<Date>();
}
、泛型中的?通配符的扩展
1)限定通配符的上边界:
Vector<? extends Number> x = new Vector<Integer>();
Vector<? extends Number> x = new Vector<String>();
2)限定通配符的下边界:
Vector<? super Integer> x = new Vector<Number>();
Vector<? super Integer> x = new Vector<Byte>();
&符号限定边界为多个类的交集
注意:
限定通配符总是包括自己。
?只能用作引用,不能用它去给其他变量赋值
Vector<? extends Number> y = new Vector<Integer>();
Vector<Number> x = y;
Vector<Object > x11 = new Vector<String>();相似,
只能通过强制类型转换方式来赋值。
、泛型集合类的综合案例
public static void main(String[] args){
HashMap<String,Integer> hm = new HashMap<String,Integer>();
hm.put("zxx",19);
hm.put("lis",18);
Set<Map.Entry<String,Integer>> mes= hm.entrySet();
for(Map.Entry<String,Integer> me : mes) {
System.out.println(me.getKey() + ":" + me.getValue());
}
、定义泛型方法
1)java中的泛型方法定义
/*用泛型定义一个求和方法*/
private static <T> T add(T a, T b){
......
return null;
}
自动装箱和拆箱
取两个数的交集类型Number
去最大交集为Object
注:用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,
也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。
2)何时定义泛型方法:为了让不同方法可以操作不同的类型,而且类型不确定,那么就可以定义泛型方法
3)静态方法的泛型:静态方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定,
可以将泛型定义在方法上。
4)泛型方法的特点:
、位置:用于放置泛型的类型参数的<>应出现在方法的其他所有修饰符之后和在方法的返回类型之前,
也就是紧邻返回值之前,按照惯例,类型参数通常用单个大写字母表示。
、只有引用类型才能作为泛型方法的实际参数
、除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。
、普通方法、构造函数和静态方法中都可以使用泛型。
、可以用类型变量表示异常,称之为参数化的异常,可用于方法的throws列表中,但是不能
catch子句中。
、在泛型中可同时有多个类型参数,在定义它们的<>中用逗号分开。
下面是一个异常中的泛型演示代码
private static <T extends Exception> sayHello() throws T {
try{
}catch(Exception e){
throw (T)e;
}
}
、类型参数的类型推断
编译器判断范型方法的实际类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现
方法是一种非常复杂的过程。
根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:
1)当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用
方法时该处的实际应用类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时
传递的参数类型或返回值来决定泛型参数的类型,例如:
——> static <E> void swap(E[] a, int i, int j)
(2)当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时
这多处的实际应用类型都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:
——> static <T> T add(T a, T b)
3)当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时
这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数中的最
Number了,编译没问题,只是运行时出问题:
——> static <T> void fill(T[] a, T v)
4)当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时
这多处的实际应用类型对应到了不同的类型, 并且使用返回值,这时候优先考虑返回值的
Integer了,编译将报告错误,将变量x的类型
float,对比eclipse报告的错误提示,接着再将变量x类型改为Number,则没有了错误:
——> static <T> T add(T a, T b)
5)参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,
Vector类实例将类型变量直接确定为String类型,编译将出现问题:
——> static <T> void copy(T[] a,T[] b);
——>
static <T> void copy(Collection<T> a , T[] b);
、定义泛型类型
(1)如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持
同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,
语法格式如下:
public class GenericDao<T> {
private T field1;
public void save(T obj){}
public T getById(int id){}
}
(2)类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:
GenericDao<String> dao = null;
new GenericDao<String>();
注意:
1)在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
2)当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和
静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级
别的类型参数。
(3)举例:
Dao:Data Access Object,数据访问对象。
crud即增上删改查
javaEE的理解:13种技术。简单说就是对数据库的增删改查。
Dao类有五个基本方法:增删改查,其中查包含查单个和对同类型集合的查询,
如同性别或同地区的集合获取。
import java.util.*;
public class GenerticDao<T> {
public static <E> void staMethod(E e){}
public void add(T obj){}
public boolean delete(T obj){
return true;
}
public boolean delete(int id){
return true;
}
public T update(T obj){
return null;
}
public T findByUserName(String name){
return null;
}
public Set<T> findByPlace(String place){
Set<T> set = new TreeSet<T>();
//....
return set;
}
}
总结:
(1)定义泛型:当又不确定的类型需要传入到集合中,需要定义泛型
(2)定义泛型类:如果类型确定后,所操作的方法都是属于此类型,则定义泛型类
(3)定义泛型方法:如果定义的方法确定了,里面所操作的类型不确定,则定义泛型方法
四、拓展:通过反射获得泛型的参数化类型
class GenericTest{
public static void main(String[] args){
Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType.getRawType());
System.out.println(pType.getActualTypeArguments()[0]);
}
public static void applyVector(Vector<Date> v1){
}
}
总结:通过反射不能直接获取集合中的数据类型,只能逐个取得其中元素判断类型。
但是可以将集合作为某个方法的参数,
Method对象的getGenericParameterTypes方法取得原始类型,
ParameterizedType类型,即可通过getActualTypeArguments
方法取得集合的泛型类型。