1、Java 反射(Reflection)使用场景
反射在以下情况下很有用:
1)需要访问Jar包数据中的注解时。
2)检查和实例化jar包中的类型。
3)在运行时构建新类型。
4)编译时根本无法预知该对象的类型,程序只能依靠运行时来发现对象和类的具体信息
5)执行后期绑定,访问在运行时创建的类型上的方法。可以动态调用执行方法。
6)可以动态生成类框架,如Gson。
7)Tomcat服务器是典型的反射机制应用
2、Java 反射(Reflection)的使用
1)获取Class对象
通过Java代码获取Class对象有四种方法,具体如下,
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
Class<?> class1 = null;
Class<?> class2 = null;
Class<?> class3 = null;
Class<?> class4 = null;
//调用Class的静态方法:forName(全类名)
class1 = Class.forName("java.util.Date");
//通过运行时类的对象的getClass方法
class2 = new java.util.Date().getClass();
//调用运行时类的属性
class3 = java.util.Date.class;
//ClassLoader中的loadClass(全类名)方式获取
ClassLoader classLoader = Main.class.getClassLoader();
class4 = classLoader.loadClass("java.util.Date");
System.out.println(class4);
System.out.println("类名称 " + class1.getName());
System.out.println("类名称 " + class2.getName());
System.out.println("类名称 " + class3.getName());
System.out.println("类名称 " + class4.getName());
System.exit(0); //success
}
}
2)9个预定义Class对象
byte
,short
,int
,long
,char
,float
,double
,boolean
和void
关键字,都有class
属性。例如,
int.class;
boolean.class;
int
的包装类是Integer
,Integer
和 int
不是同一种数据类型,8个基本数据类型的包装类中都有一个常量TYPE
,TYPE
表示的是该包装类对应的基本数据类型的Class
对象,
Integer.TYPE == int.class;//true
Integer.TYPE != Integer.class;//true
3)获取类中的构造器
获取所有公有构造器:Class对象的getDeclaredConstructors();
获取所有构造器:Class对象的getDeclaredConstructors();
获取单个公有无参构造器:Class对象的getConstructor(null);
获取单个指定公有构造器:Class对象的getConstructor(String.class);
获取单个指定构造器:Class对象的getDeclaredConstructor(String.class);
4)获取成员变量的方法
方法 | 描述 |
Field[] getFields() | 获取当前Class所表示类的所有public字段。 |
Field[] getDeclaredFields() | 获取当前Class所表示类的所有字段, 包括:private、protected、默认、public。 |
public Field getField(String fieldName) | 获取当前Class所表示类指定的public字段。 |
public Field getDeclaredField(String fieldName) | 获取当前Class所表示类的指定字段 (可以为private) |
public void set(Object obj,Object value) | 参数 obj:要设置的字段所在的对象, value:要为字段设置的值 |
5)获取类中的成员方法
方法 | 描述 |
public Method[] getMethods() | 获取当前Class所表示类和继承的所有public方法(包含了父类的方法也包含Object类)。 |
public Method[] getDeclaredMethods() | 获取当前Class所表示类的所有成员方法,包括私有的(不包括继承的,和访问权限无关)。 |
public Method getMethod (String name, Class... parameterTypes) | 获取当前Class所表示类的指定的public方法(包括继承的)。 |
public Method getDeclaredMethod (String methodName, Class... parameterTypes) | 获取当前Class所表示类的指定的成员方法(不包括继承的)。 参数 methodName:方法名, Class ... parameterTypes:形参的Class类型对象 |
6)调用执行方法
public Object invoke(Object obj,Object ... args)
:参数 obj:要调用方法的对象,args:调用方法时所传递的实参。
使用示例:
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Main{
public static void main(String[] args) throws Exception {
Sample s=new Sample();
s.setProp1("cjavapy.com");
s.setProp2(100);
Class clazz=Sample.class;//获取Class对象
String clazzName=clazz.getName();//获取类名,含包名
String clazzSimpleName=clazz.getSimpleName();//获取类名,不含包名
System.out.println("getName:"+clazzName+"\tgetSimpleName:"+clazzSimpleName);
int mod=clazz.getModifiers();//获取类修饰符
System.out.println("Modifier.isPublic:"+Modifier.isPublic(mod));//判断类修饰符
System.out.println("Modifier.isProtected:"+Modifier.isProtected(mod));//判断类修饰符
Package p=clazz.getPackage();//获取包
System.out.println("getPackage:"+p);
Class superClass=clazz.getSuperclass();//获取父类
System.out.println("getSuperclass:"+superClass);
Class[] interfaces=clazz.getInterfaces();//获取实现接口
System.out.println("getInterfaces:"+interfaces.length);
Constructor[] cons=clazz.getConstructors();//构造方法
System.out.println("getConstructors:"+cons.length);
Method[] methods=clazz.getMethods();//获取所有方法
System.out.println("getMethods:"+methods.length);
for(Method method:methods){
System.out.println("method.getName:"+method);
}
Method method=clazz.getMethod("getProp1", new Class[]{});//获取指定方法
System.out.println("getMethod(,):"+method);
Object methodVlaue=method.invoke(s, new Object[]{});//调用方法
System.out.println("method.invoke(,):"+methodVlaue);
Method method3=clazz.getMethod("setProp3",Double.class);//获取指定方法
System.out.println("getMethod(,):"+method3);
//调用setter方法,该方法没有返回值,所以methodVlaue3为null;此处注意参数2.0 ,不能用null
Object methodVlaue3=method3.invoke(s, 2.0);
System.out.println("method.invoke(,):"+methodVlaue3);
Field[] fields=clazz.getDeclaredFields();//获取变量
System.out.println("getDeclaredFields:"+fields.length);
for(Field field:fields){
field.setAccessible(true);
field.set(s,null);//设置字段的值
//获取实例属性名和值
System.out.println("field.getAnnotations:"+field.getAnnotations().length+"\tfield.getName:"+field.getName()+"\tfield.get:"+field.get(s));
}
Annotation[] annos=clazz.getAnnotations();//获取类注解
System.out.println("getAnnotations:"+annos.length);
}
}
class Sample {
private String prop1;
private Integer prop2;
private Double prop3;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public Integer getProp2() {
return prop2;
}
public void setProp2(Integer prop2) {
this.prop2 = prop2;
}
public Double getProp3() {
return prop3;
}
public void setProp3(Double prop3) {
this.prop3 = prop3;
}
}
3、Java 反射使用实例
1)反射调用执行main方法
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) {
try {
//获取Sample的字节码
Class clazz = Class.forName("Sample");
//获取main方法
Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,
//调用main方法
//第一个参数,对象类型,
//第二个参数是String数组,注意在jdk1.4时是数组,jdk1.5之后是可变参数,
//将 new String[]{"a","b","c"} 拆成3个对象,所以需要将它强转。
methodMain.invoke(null, (Object)new String[]{"p1","p2","p3"});//方法一
// methodMain.invoke(null, new Object[]{new String[]{"p1","p2","p3"}});//方法二
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Sample {
public static void main(String[] args) {
System.out.println("main方法执行");
}
}
2)使用反射调用 ArrayList对象的add方法
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws Exception{
ArrayList list = new ArrayList<>();
list.add("Java");
list.add("CJavaPy");
//获取ArrayList的Class对象,调用add()方法,添加数据
Class listClass = list.getClass(); //得到 list对象的字节码对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(list, "https://www.cjavapy.com");
//可以通过反射越过泛型检查的,添加整型的值
m.invoke(list,11);
//遍历集合
for(Object obj : list){
System.out.println(obj);
}
}
}
3)使用反射为对象赋值
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Main {
private String prop1;
private Integer prop2;
private Double prop3;
public String getProp1() {
return prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
public Integer getProp2() {
return prop2;
}
public void setProp2(Integer prop2) {
this.prop2 = prop2;
}
public Double getProp3() {
return prop3;
}
public void setProp3(Double prop3) {
this.prop3 = prop3;
}
/**
* 用于对类的字段赋值,无视private,project修饰符,无视set/get方法
* @param c 要反射的类
* @return
*/
@SuppressWarnings("unchecked")
public static Object setClassValue(Class c, Object source, Object object) {
try {
Class<?> obj = object.getClass();
Class<?> s = source.getClass();
Field[] fields = obj.getDeclaredFields();
Field[] sfields = s.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
for (int j = 0; j < sfields.length; j++) {
if (sfields[j].getName().equals(fields[i].getName())) {
fields[i].set(object, sfields[j].get(source));
break;
}
}
}
return object;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
try {
Main s = new Main();
s.setProp1("Java");
s.setProp2(11);
s.setProp3(22.00);
Main o = new Main();
setClassValue(o.getClass(), s, o);
System.out.println(o.getProp1()+" "+o.getProp2()+" "+o.getProp3());
} catch (Exception e) {
e.printStackTrace();
}
}
}
4)使用反射获取注解
import java.lang.annotation.*;
import java.lang.reflect.Method;
@SampleAnnotation(Value = "java", Name = "cjavapy")
public class Main {
public static void main(String[] args) {
Main s = new Main();
Class clazz = s.getClass();
Annotation[] annotations = clazz.getAnnotations();
for (Annotation anno : annotations) {
System.out.println("Annotation Type: " + anno.annotationType());
}
SampleAnnotation anno = (SampleAnnotation) clazz.getAnnotation(SampleAnnotation.class);
System.out.println("Anno Value : " + anno.Value());
System.out.println("Anno Name: " + anno.Name());
try {
Method m = clazz.getMethod("sayHi");
anno = m.getAnnotation(SampleAnnotation.class);
System.out.println("Anno Value : " + anno.Value());
System.out.println("Anno Name: " + anno.Name());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
s.sayHello();
}
@SampleAnnotation(Value = "Hi", Name = "Java")
public void sayHi() {
}
@SampleAnnotation(Value = "Hello", Name = "CJavaPy")
public void sayHello() {
try {
Method m = getClass().getMethod("sayHello");
SampleAnnotation anno = m.getAnnotation(SampleAnnotation.class);
System.out.println(anno.Value() + " " + anno.Name());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface SampleAnnotation {
String Name()default "Java";
String Value()default "web";
}