欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

java泛型怎么用反射生成_Java 之 使用反射生成并操作对象

发布时间:2024/10/14 java 57 豆豆
生活随笔 收集整理的这篇文章主要介绍了 java泛型怎么用反射生成_Java 之 使用反射生成并操作对象 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

一、使用反射创建对象

通过反射来生成对象有如下两种方式:

方式一:

使用 Class 对象的 newInstance() 方法来创建 Class 对象对应类的实例,这种方法要求该 Class 对象的对应类有默认构造器,而执行 newInstance() 方法实际上是利用默认构造器来创建该类的实例。

方式二:

先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的newInstance(Object... args) 方法来创建该 Class 对象对应类的实例。通过这种方式可以选择使用某个类的指定构造器来创建实例。

通过第一种方式来创建对象是比较常见的情形,因为很多  JavaEE 框架中都需要根据配置文件信息来创建实例对象,从配置文件读取的只是某个类的字符串类名,程序就需要根据该字符串来创建对应的实例,就必须使用反射。

代码示例:

1 importjava.lang.reflect.Constructor;2

3 importorg.junit.Test;4

5 public classTestNewInstance {6 @Test7 public void test1() throwsException{8 Class> clazz = Class.forName("com.ks.reflect.Student");9 Object obj =clazz.newInstance();10 System.out.println(obj);11 }12

13 @Test14 public void test2() throwsException{15 Class> clazz = Class.forName("com.ks.reflect.Student");16 Constructor> constructor = clazz.getDeclaredConstructor(String.class);17 Object obj = constructor.newInstance("张三");18 System.out.println(obj);19 }20 }21 classStudent{22 privateString name;23

24 publicStudent(String name) {25 super();26 this.name =name;27 }28

29 publicStudent() {30 super();31 }32

33 @Override34 publicString toString() {35 return "Student [name=" + name + "]";36 }37 }

二、获取或设置某个对象的属性值

通过 Class 对象的 getFields() 等方法可以获取该类所包括的全部 Field(属性)或指定 Field。

而Field类除了提供获取属性的修饰符、属性类型、属性名等方法外,还提供了如下两组方法来访问属性:

public xxx getXxx(Object obj):获取obj对象该Field的属性值

public void setXxx(Object obj,Xxx value):设置obj对象该Field的属性值为value。

此处的XXX 对应 8 种基本数据类型,如果该属性的类型是引用数据类型,则直接使用get(Object obj) 方法或 set(Object obj, Object value) 方法。

当属性是 private不可访问时,还需要下面的方法:

public void setAccessible(boolean flag)启动和禁用访问安全检查的开关。

(1)值 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。

提高反射的效率,如果代码中必须用反射,而该句代码需要频繁的呗调用,那么请设置为 true

使得原本无法访问的私有成员也可以访问。

(2)值 false 则指示反射的对象应该实施 Java 语言访问检查。

Demo:获取或设置某个对象的属性值示例代码

1 importjava.lang.reflect.Field;2

3 public classTestField {4

5 public static void main(String[] args)throwsException {6 Class> clazz = Class.forName("com.ks.reflect.Circle");7 Object obj =clazz.newInstance();8 Field field = clazz.getDeclaredField("radius");9 field.setAccessible(true);10 field.set(obj, 1.2);11 Object value =field.get(obj);12 System.out.println(value);13 }14

15 }16 classCircle{17 private doubleradius;18 }

三、调用方法

当获得某个类对应的 Class 对象后,就可以通过该 Class 对象的 getMethods() 等方法获取全部方法或指定方法。

每个 Method 对象对应一个方法,获取 Method 对象后,程序就可以通过该 Method 对象的 invoke 方法来调用对应方法。

Object invoke(Object obj, Object... args):对带有指定参数的指定对象调用由此 Method 对象表示的底层方法

Demo:

1 importjava.lang.reflect.Method;2

3 public classTestMethod {4

5 public static void main(String[] args) throwsException {6 Class> clazz = Class.forName("com.ks.reflect.Utils");7 Object obj =clazz.newInstance();8 Method method = clazz.getMethod("check", String.class,String.class);9 Object value = method.invoke(obj, "tong","666");10 System.out.println(value);11 }12

13 }14 classUtils{15 public booleancheck(String user,String password){16 if("admin".equals(user) && "123".equals(password)){17 return true;18 }else{19 return false;20 }21 }22 }

注意:如果调用某个类的某个方法时,并不是传入对象,而是 null,表示调用静态方法。(即 invoke(null,参数列表))

四、操作数组

在java.lang.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过使用Array类来动态的创建数组,操作数组元素等。

Array 类提供了如下几个方法:

public static Object newInstance(Class> componentType, int... dimensions):创建一个具有指定的组件类型和维度的新数组

public static void setXxx(Object array,int index,xxx value):将array数组中[index]元素的值修改为value。

public static xxx getXxx(Object array,int index,xxx value):将array数组中[index]元素的值返回。

此处的 Xxx 对应 8 种基本数据类型,如果该属性的类型是引用数据类型,则直接使用 set(object arr,int index, Object value)方法或 get(Object array, int index) 方法。

Demo:

1 importjava.lang.reflect.Array;2

3 public classTestArray {4 public static voidmain(String[] args) {5 Object arr = Array.newInstance(String.class, 5);6 Array.set(arr, 0, "Hello");7 Array.set(arr, 1, "World");8 System.out.println(Array.get(arr, 0));9 System.out.println(Array.get(arr, 1));10 System.out.println(Array.get(arr, 2));11 }12 }

五、运行时获取注解信息

一个完整的注解,有三个要素:

(1)声明

(2)使用

(3)读取

像@Override,@SuppressWarings,@Deprecated等这些是JRE中声明的,也是由编译器读取的

像@Test,@Before...等这些注解是JUnit声明和读取的

像@author,@param...等这些注解是JRE中声明的,由javadoc.exe读取的

对于自定义的注解,声明和读取需要自己完成

1、声明注解

Demo:

1 //声明注解

2 @Target({TYPE,FIELD})3 @Retention(RetentionPolicy.RUNTIME)//只有生命周期是运行时,那么才可以被反射读取

4 @interfaceMyAnnotation{5 String value(); //如果配置参数只有一个,名称是value,在使用时,赋值的话就可以省略"value="

6 String name(); //也可以使用 default 给它们指定默认值

7 }

2、使用注解

Demo:使用自定义的注解

1 //使用注解

2 @MyAnnotation(value = "Annotation",name="Java")3 classMyClass{4 @MyAnnotation(value="String",name="Field")5 privateString info;6

7 }

3、读取注解

主要分为三步:

① 获取 Class 对象

② 获取注解对象

③ 获取注解的配置参数的值

Demo:

1 public classTestAnnotation {2 @SuppressWarnings("unchecked")3 @Test4 public voidtest01() {5 //(1)获取Class对象

6 Class clazz = MyClass.class;//四种方式之一7

8 //(2)获取注解对象

9 MyAnnotation annotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);10

11 //(3)获取注解的配置参数的值

12 String value =annotation.value();13 System.out.println("value = " +value);14

15 String name =annotation.name();16 System.out.println("name =" +name);17 }18

19 @SuppressWarnings("unchecked")20 @Test21 public void test02() throwsNoSuchFieldException, SecurityException {22 //(1)获取Class对象

23 Class clazz = MyClass.class;//四种方式之一24

25 //(2)获取属性对象

26 Field infoField = clazz.getDeclaredField("info");27

28 //(3)获取注解对象

29 MyAnnotation annotation = (MyAnnotation) infoField.getAnnotation(MyAnnotation.class);30

31 //(3)获取注解的配置参数的值

32 String value =annotation.value();33 System.out.println("value = " +value);34

35 String name =annotation.name();36 System.out.println("name =" +name);37 }38

39 }

六、运行时读取某个类的泛型实参

读取某个类的泛型实参主要分为三步:

(1)获取 Class 对象

(2)获取泛型父类

Type type = clazz.getGenericSuperclass();

ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass();

(3)获取类型实参

Type:代表Java的所有类型

(1)Class:代表的是普通的类型,没有泛型信息的

(2)ParameterizedType:参数化类型    例如:Father

(3)GenericArrayType:泛型数组类型   例如:T[]

(4)TypeVariable:类型变量    例如:T

(5)WildcardType:带?通配符的泛型的类型  例如:ArrayList>  或ArrayList super 下限> 或ArrayList extends 上限>

Demo:

1 //泛型类型形参:

2 class Father{3

4 }5 //泛型类型实参:

6 class Son extends Father{7

8 }9

10   @Test11 public voidtest01() {12 //获取Son类的泛型父类的类型实参13 //(1)获取Class对象

14 Class clazz = Son.class;15

16 //(2)获取泛型父类17 //获取普通父类18 //Class fu = clazz.getSuperclass();19 //System.out.println(fu);20

21 //获取泛型父类的参数

22 ParameterizedType type =(ParameterizedType) clazz.getGenericSuperclass();23

24 //(3)获取类型实参

25 Type[] types =type.getActualTypeArguments();26 for(Type t : types) {27 System.out.println(t);28 }29 }

对于泛型类、接口的类型形参,什么时候才能确定具体的类型呢?

(1)创建它的对象

(2)继承泛型类

(3)实现泛型接口

Demo:

1 class Tools{2 privateClass type;3

4 publicTools() {5 //在创建子类对象时,来确定type的代表类型6 //(1)获取正在new的对象的类型Class对象

7 Class clazz = this.getClass();8

9 //(2)获取泛型父类的信息

10 ParameterizedType t =(ParameterizedType) clazz.getGenericSuperclass();11

12 //(3)获取类型实参

13 type = (Class) t.getActualTypeArguments()[0];14 }15

16

17 public voidtest(){18 //这个方法中需要用到T的类型对象,即T的Class对象19 //Class c = T.class;//此时无法确定T的类型

20 System.out.println(type);21 }22

23 }24 class MyTools extends Tools{25

26 }27

28 @Test29 public voidtest02() {30 MyTools my = newMyTools();31 my.test(); //class java.lang.String32

33 }

总结

以上是生活随笔为你收集整理的java泛型怎么用反射生成_Java 之 使用反射生成并操作对象的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。