什么时反射,根据个人理解,就是通过一个类的字节码获取和使用这个类里面的方法、字段、构造方法等。
所以反射,首先是要获得类的字节码。其中获取字节码的方法有3种:
1.使用Class类的forName(String className)静态方法,className表示全限定名;如String的全限定名:java.lang.String。
2.调用某个对象的getClass()方法。该方法属于Object类。如Class<?> clz=new String().getClass。
3.调用某个类的class属性获取Class对象,如Date.class会返回Date类对应的Class对象(其实就是得到一个类的一份字节码文件);
接下来就是如何通过一个类的字节码获取和使用这个类里面的方法、字段、构造器。这就要涉及到java里提供的类:Constructor类、Method、Field、Annotation等类。
先说Constructor类,Constructor类用于描述类中的构造方法。
Class类中用于处理Constructor类的方法:
Constructor<T> getConstructor(Class<?>... parameterTypes);返回该Class对象表示类的指定的public构造方法;
Constructor<?>[] getConstructors();返回该Class对象表示类的所有public构造方法;
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);返回该Class对象表示类的指定的构造方法,和访问权限无关;
Constructor<?>[] getDeclaredConstructors();返回该Class对象表示类的所有构造方法,和访问权限无关;
newInstance();利用构造方法创建对象。(该方法属于Constructor类)
例子代码如下:
package bokedemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<ConstrutorDemo> clz=ConstrutorDemo.class;
//获取参数为int的构造器
Constructor<ConstrutorDemo> constructor=clz.getConstructor(int.class);
System.out.println(constructor);
//获取public修饰的构造方法
Constructor<?>[] constructors=clz.getConstructors();
for (Constructor<?> constructor2 : constructors) {
System.out.println(constructor2);
}
//获取参数String被private修饰的构造方法
Constructor<ConstrutorDemo> constructorprivate=clz.getDeclaredConstructor(String.class);
System.out.println(constructorprivate);
//获取所有构造方法包括private修饰的构造方法
Constructor<?>[] constructorsall=clz.getDeclaredConstructors();
for (Constructor<?> constructor2 : constructorsall) {
System.out.println(constructor2);
}
//设置使用时不检查该构造方法是否为私有
constructorprivate.setAccessible(true);
//利用获得的Constructor对象获得相应类的对象
ConstrutorDemo cdemo=constructorprivate.newInstance("hao");
}
}
class ConstrutorDemo
{
public ConstrutorDemo(){
System.out.println("public no param");
}
public ConstrutorDemo(int i){
System.out.println("public has param");
}
private ConstrutorDemo(String str){
System.out.println("private has param");
}
}
接着是Method类,Method类用于描述类中的方法。
Class类中用于Method类的方法有:
Method getMethod(String name, Class<?> ... parameterTypes):返回该Class对象表示类和其父类的指定的public方法;
Method[] getMethods():返回该Class对象表示类和其父类的所有public方法;
Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回该Class对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;
Method[] getDeclaredMethods(): 获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;
invoke(Object obj,Object ... args):obj表示调用底层方法的对象,后面的args表示传递的实际参数。如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 如果底层方法所需的形参个数为 0,则所提供的 args 数组长度可以为 0 或 null(不写,null,或 new Object[]{})。(该方法属于Method)
例子代码如下:
package bokedemo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//获取字节码
Class<?> clz=MethodDemo.class;
MethodDemo mdemo=(MethodDemo) clz.newInstance();
//通过反射获得参数为int和String的public修饰的名为methodpublic的方法。
Method method=clz.getMethod("methodpublic", new Class<?>[]{int.class,String.class});
//通过反射调用参数为int和String的public修饰的名为methodpublic的方法。
method.invoke(mdemo, new Object[]{1,"hao"});
//通过反射获取所有的public修饰的方法包括从父类继承的public方法。
Method[] methods=clz.getMethods();
for (Method method2 : methods) {
System.out.println(method2);
}
//通过反射获得参数为int被private修饰的名为methodprivate的方法。
Method methodprivate=clz.getDeclaredMethod("methodprivate", int.class);
//设置使调用时不被检查
methodprivate.setAccessible(true);
//通过反射调用参数为int被private修饰的名为methodprivate的方法。
methodprivate.invoke(mdemo, new Object[]{1});
// 获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;
Method[] methodall=clz.getDeclaredMethods();
for (Method method2 : methodall) {
System.out.println(method2);
}
}
}
class MethodDemo
{
public void methodpublic()
{
System.out.println("methodpublic1 no param");
}
public void methodpublic(int i)
{
System.out.println("methodpublic1 has one param int");
}
public void methodpublic(int i,String str)
{
System.out.println("methodpublic1 has two param int and string");
}
private void methodprivate()
{
System.out.println("methodprivate no param");
}
private void methodprivate(int i)
{
System.out.println("methodprivate has one param int");
}
private void methodprivate(int i,String str)
{
System.out.println("methodprivate has two param int and string");
}
}
然后是Field类,Field类用于描述类中的字段。
Class类中用于处理Field类的主要方法:
Field getField(String name) :返回该Class对象表示类和其父类的指定的public字段;
Field[] getFields() :返回该Class对象表示类和其父类的所有public字段;
Field getDeclaredField(String name):返回该Class对象表示类的指定的字段和访问权限无关,但不包括继承的字段;
Field[] getDeclaredFields():返回当前Class对象中公共、保护、默认(包)访问和私有字段,但不包括继承的字段;
get(Object object):返回指定字段的值。(该方法属于Field)
Setxxx(Object obj,xxx val):将obj对象的该Field字段设置成val值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用,void set(Object obj, Object value);(该方法属于Field)
最后是Annotation类,Annotation类用于描述类中的注释。
Class类中用于处理Annotation类的主要方法:
<A extends Annotation> A getAnnotation(Class<A> annotationClass):如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null;
Annotation[] getAnnotations():返回此元素上存在的所有注释;
Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释;
boolean isAnnotationPresent(Class<? extends Annotation> clz) :如果clz注释存在于此元素上,则返回 true,否则返回 false ;
|
|