java reflection list_Java基础系列之(一) - Reflection

本文详细介绍了Java反射机制,包括Class对象的获取、构造函数、成员变量、方法的访问,以及注解和泛型的使用。通过实例展示了如何获取和操作类的元数据,以及如何利用反射进行动态调用和参数设置。此外,还探讨了泛型在反射中的应用,如获取方法和变量的泛型类型。
摘要由CSDN通过智能技术生成

前段时间与一个新手谈论Java基础的时候提到反射,然后对反射的一些问题在这里基本介绍下。在介绍之前,这里了解几个反射的几个概念。

Class - class是对一个类进行描述的,你可以认为它是一个类的模型。

Constructor - constructor是一个Class的构造函数,一个Class可以允许重载多个构造函数。

Field - Filed是用来描述Class的成员变量的。

Method - method是描述一个Class的方法的。

Annotation - Annotation是描述Class的注解的,注解可以作用于Class,Method,Filed,Argument之上。

Generic - Generic指的是泛型,限制参数,返回类型的描述。

当然其他的还有参数,访问域等一些概念。

1、Class(类)

有多种方式如下:

Class clz = myobject.class;

动态加载也可以:

Class clz = Class.forName("类的全名");

(1) 下面描述的是可以通过Class对象获取构造函数、方法、成员变量、注解等,这里注意的是,这里获取得都是访问范围是public。

Class clz = Reflection1Test.class;//获取所有public的构造函数

Constructor[] constructors =clz.getConstructors();//获取参数是String类型的public构造函数

Constructor constructor = clz.getConstructor(new Class[]{String.class});//获取所有public方法

Method[] methods =clz.getMethods();//获取方法名称是"test",参数类型分别是List和String,而且是public的方法

Method method = clz.getMethod("test", new Class[]{java.util.List.class,String.class});//获取指定的枚举类型的枚举

Annotation annotation = clz.getAnnotation(Reflection1Test.class);//获取该类的所有枚举

Annotation[] annotations = clz.getAnnotations();

(2) 类的修饰范围

Class clz = Reflection1Test.class;int modifiers = clz .getModifiers();

这里返回的是一个int值,int里面存储的信息包含public,private,protected,final,abstract,interface,native,static,synchronized,Transient,Volatile。这里稍稍提下存储原理,基本原理采用的是二进制的占位思想,之前我的一篇文章bitmap里面也是用的是二进制占位的算法。public,private,protected,final,abstract,interface,native,static,synchronized,Transient,Volatile每个定义一个二进制的位置。例如:

public static final int PUBLIC = 0x00000001;public static final int PRIVATE = 0x00000002;

public static final int PROTECTED = 0x00000004;

public static final int STATIC = 0x00000008;

public static final int FINAL = 0x00000010;

public static final int SYNCHRONIZED = 0x00000020;

public static final int VOLATILE = 0x00000040;

public static final int TRANSIENT = 0x00000080;

public static final int NATIVE = 0x00000100;

public static final int INTERFACE = 0x00000200;

public static final int ABSTRACT = 0x00000400;

public static final int STRICT = 0x00000800;

这样的话,假如一个Class既是public,又是final,这个时候她的modifier值就是public+final。

当然你想判断它是否是public还是final,JDK提供一个modifier类专门处理,如下:

Modifier.isAbstract(intmodifiers);

Modifier.isFinal(intmodifiers);

Modifier.isInterface(intmodifiers);

Modifier.isNative(intmodifiers);

Modifier.isPrivate(intmodifiers);

Modifier.isProtected(intmodifiers);

Modifier.isPublic(intmodifiers);

Modifier.isStatic(intmodifiers);

Modifier.isStrict(intmodifiers);

Modifier.isSynchronized(intmodifiers);

Modifier.isTransient(intmodifiers);

Modifier.isVolatile(int modifiers);

2、Constructor(构造函数)

(1) 获取构造函数

上面已经提到过了。怎么获取构造函数:

//获取所有public的构造函数

Constructor[] constructors = clz.getConstructors();

上面返回的是一个public的构造函数数组。

如果你像返回指定的构造函数,需要提供构造函数的参数类型。

Constructor constructor = clz.getConstructor(new Class[]{String.class});

返回的也是public的构造函数,如果没有找到指定的构造函数,就会抛NoSuchMethodException。

(2) 构造函数的参数类型

Class[] cType = constructor.getParameterTypes();

(3) 构造函数实例化

我们都知道构造函数是一个对象实例化的入口,或者说是new的时候要首先调用的特殊方法。那么Constructor肯定能够实例化一个对象的。

try{

MyObject obj= (MyObject)constructor.newInstance(new Object[]{"123",new ArrayList()});

}catch(IllegalArgumentException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(InstantiationException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IllegalAccessException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(InvocationTargetException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

constructor.newInstance()需要提供一个可变的参数列表,提供的参数必须和声明的构造函数的值和类型都一一对应。

3、Field(变量)

(1)获取Field对象

//获取所有public成员变量

Field[] fields =clz.getFields();//获取名称是name的public的变量

Field field = clz.getField("name");

这里也一样,返回的都是public修饰符的变量,如果找不到指定匹配的变量名称,会抛NoSuchFieldException异常。

(2)获取Field的名称和类型

//获取变量的名称

String name =field.getName();//获取变量的类型

Class fieldType = field.getType();

(3)get/set Field的值

MyObject obj = newMyObject();

field= clz.getField("name");//获取obj对象的name变量的值

Object object =field.get(obj);//设置obj对象的变量name的值为123

field.set(obj, "123");

这里通过变量的对象来获取它的值,并且能修改它的值。当然这里依然遵照的是public的原则。

(4)访问私有变量

上面已经说过了,上面访问都是public的变量,那么,私有变量怎么访问呢?如下:

//获取所有声明的变量

Field[] declaredFields =clz.getDeclaredFields();

Field declaredField= clz.getDeclaredField("privateString");//私有变量必须先将访问权限设置为true

declaredField.setAccessible(true);

Object o= declaredField.get(test2);

declaredField.setAccessible(true)代码是关闭字段的访问检查。

4、Method(方法)

(1)获取Method对象

//获取所有public方法

Method[] methods =clz.getMethods();//获取方法名称是"test",参数类型分别是List和String,而且是public的方法

Method method = clz.getMethod("test", new Class[]{java.util.List.class,String.class});

如果没有找到指定匹配的Method,会抛NoSuchMethodException异常。

(2)获取Method的参数

//获取Method的参数类型

Class[] parameterTypes = method.getParameterTypes();

因为一个方法的参数可以是多个,所以返回的是一个数组。

(3)获取Method的返回值

//返回Method返回值的类型

Class returnType = method.getReturnType();

这里有人就问,如果没有返回值呢,如果是void的呢,其实void也可以看成一个返回值,空返回值的。所以void的方法返回的直接是void。

(4)Method调用

定义一个test方法,有两个参数,如下:

public voidtest(List s,String s1){

System.out.println("调用了Test");

}

Reflection1Test test = new Reflection1Test("");//调用Reflection1Test对象的test方法

Object returnValue = method.invoke(test, new Object[]{new ArrayList(),"123"});

这里有一个小细节,如果test是null的话,调用的是方法必须是static。

(5)访问私有方法

Reflection1Test test3 = new Reflection1Test("");//获取所有声明的方法

Method[] declaredMethods =clz.getDeclaredMethods();

Method declaredMethod= clz.getDeclaredMethod("test", new Class[]{java.util.List.class,String.class});

declaredMethod.setAccessible(true);

Object returnValue2= declaredMethod.invoke(test3, new Object[]{new ArrayList(),"123"});

与Field一样setAccessible(true)关闭反射的权限检查。

5、Annotation(注解)

注解的简单理解就是在类、方法、变量上打一个标签,这个标签为了具体说明它的实际意义,对类、方法、变量没有实际应用意义。

(1)定义注解

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Inherited

@Documentedpublic @interfaceAnnotationTest {

String value()default "";

}

注解定义是在interface前面带一个@符号,这就说明是一个注解,一般有几个定义规则。

@Retention - 定义注解存在的周期,RetentionPolicy有三个值,Source,Class,RUNTIME。

RetentionPolicy.Source 表示只是在源码中存在,编译的时候就被丢弃了。

RetentionPolicy.Class 表示编译的时候注入到Class中,但是VM加载的时候会丢弃。

RetentionPolicy.RUNTIME 表示注解会被VM加载进去,在运行期能够调用。

@Target -定义注解的作用范围,一般作用于类、方法、变量、构造函数。

ElementType.ANNOTATION_TYPE

ElementType.CONSTRUCTOR

ElementType.FIELD

ElementType.LOCAL_VARIABLE

ElementType.METHOD

ElementType.PACKAGE

ElementType.PARAMETER

ElementType.TYPE

其中,ANNOTATION_TYPE是针对注解用的,在注解定义上被应用的

@Inherited - 能够被子类复用。

@Inheritedpublic @interfaceMyAnnotation {

}

@MyAnnotationpublic classMySuperClass { ... }public class MySubClass extends MySuperClass { ... }

@Documented - 能够在文档显示的。

@Documentedpublic @interfaceMyAnnotation {

}

@MyAnnotationpublic class MySuperClass { ... }

(2)使用注解

1、类注解

@AnnotationTest(value="chs")public class Reflection1Test {...}

下面是访问类的注解的例子:

Class clz = Reflection1Test.class;//获取类的所有注解

Annotation[] annotations =clz.getAnnotations();//获取注解类型是AnnotationTest

Annotation annotation = clz.getAnnotation(AnnotationTest.class);if(annotation instanceofAnnotationTest){

AnnotationTest annotationTest=(AnnotationTest)annotation;

System.out.println(annotationTest.value());

}

2、方法注解

@AnnotationTest(value="chs2")publicReflection1Test(String s){

}

下面是访问方法注解的例子:

Method method = clz.getMethod("test", new Class[]{java.util.List.class,String.class});

Annotation[] annotations2=method.getAnnotations();

Annotation annotation2= method.getAnnotation(AnnotationTest.class);if(annotation instanceofAnnotationTest){

AnnotationTest annotationTest=(AnnotationTest)annotation;

System.out.println(annotationTest.value());

}

3、变量注解

@AnnotationTest(value="chs2")private String privateString;

下面是变量访问注解的例子:

Field field = clz.getField("name");

Annotation[] annotations3=field.getAnnotations();

Annotation annotation3= field.getAnnotation(AnnotationTest.class);if(annotation instanceofAnnotationTest){

AnnotationTest annotationTest=(AnnotationTest)annotation;

System.out.println(annotationTest.value());

}

4、参数注解

public voidtest(List s,@AnnotationTest String s1){

System.out.println("调用了Test");

}

下面是参数访问注解的例子:

Annotation[][] Annotations5 =method.getParameterAnnotations();

Class[] parameterTypes=method.getParameterTypes();int i=0;for(Annotation[] annotations21 : Annotations5){

Class parameterType= parameterTypes[i++];for(Annotation annotation12 : annotations21){if(annotation12 instanceofAnnotationTest){

AnnotationTest myAnnotation=(AnnotationTest) annotation12;

System.out.println("param: " +parameterType.getName());

System.out.println("value: " +myAnnotation.value());

}

}

5、Generic(泛型)

泛型的应用非常广,一般使用的时候,是在定义一个参数化(可变的)的类或者接口,说白了,你根本不知道运行的时候应该具体哪一种类型,但是你知道是一个可变参数。你不能再运行的时候知道被参数化的类的类型是什么,当你具体使用这个类的时候,你可以显示指定它。

总之是,定义的时候不知道具体类型,使用的时候需要指定具体的类型。

(1)返回值是一个泛型类型

public ListgetList(){return null;

}

下面是访问返回值的泛型类型的例子:

Method method = Reflection1Test.class.getMethod("getList", null);

Typereturn =method.getGenericReturnType();if(return instanceofParameterizedType){

ParameterizedType type= (ParameterizedType) return;

Type[] arguments=type.getActualTypeArguments();for(Type argument : arguments ){

Class argClz=(Class) argument ;

System.out.println("argClz = " +argClz );

}

}

(2)方法的参数是一个泛型类型

public void setList(Listlist){

}

下面是一个方法参数的泛型类型访问的例子:

Method method = Reflection1Test.class.getMethod("setList", List.class);

Type[] genericParameterTypes=method.getGenericParameterTypes();for(Type genericParameterType : genericParameterTypes){if(genericParameterType instanceofParameterizedType){

ParameterizedType pType=(ParameterizedType) genericParameterType;

Type[] argTypes=pType.getActualTypeArguments();for(Type parameterType : argTypes){

Class parameterArgClz=(Class) parameterType;

System.out.println("parameterArgClass = " +parameterArgClz);

}

}

}

(3)变量的类型是一个泛型类型

public List list;

下面是一个变量的泛型类型访问的例子:

Field field = Reflection1Test.class.getField("list");

Type genericType=field.getGenericType();if(genericType instanceofParameterizedType){

ParameterizedType pType=(ParameterizedType) genericType;

Type[] argTypes=pType.getActualTypeArguments();for(Type argType : argTypes){

Class argClz=(Class) argType;

System.out.println("Class = " +argClz);

}

}

至此,java反射基本介绍如此,下一张准备说下ArrayList、LinkedList、HashMap等数据结构的源码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值