Java 反射

1 什么是反射
反射机制允许程序在运行时透过Reflection 相关的API取得任何class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现interfaces(例如Serializable),Exceptions等,也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods。

2 反射的应用场景
1)IoC:IoC通过反射技术将xml配置文件中的信息注入到JavaBean中。
2)自动的在两个POJO间赋值,比如在VO和PO之间自动赋值。
3)将实现类放到配置文件中,然后读取配置文件通过反射机制实例化配置的实现类。开发时提供一个接口,实现类由使用者实现,也就是运行时才知道具体的实现类是谁。
4)ORM框架:ORM框架读取ResultSet对象,然后通过反射机制来构造返回的对象。
5)JUnit:JUnit也使用反射来获取测试类方法列表。

3 反射示例相关的类

public interface IHello {
    public void sayHello() throws Exception;
    public void sayHello(String greeting) throws Exception;
}


public class Hello extends SuperHello implements IHello{
//    private Hello(){}
    private String name;
    private int value;
    private int[] array;
    private Map<String,Integer> map ;
    public String publicFiled;

    public Hello(){}
    public Hello(String name,int value){
        this.name = name;
        this.value = value;
    }

    public void sayHello() throws Exception {
        System.out.println("hello");
    }

    public void sayHello(String greeting) throws Exception {
        System.out.println("hello"+greeting);
    }
    private void privateSayHello(){
        System.out.println("private hello");
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
    public String toString(){
        return "name="+name+",value="+value;
    }
}

public class SuperHello {
    private String privateSuperField;
    protected String protectedSuperField;
    public String publicSuperFiled;
    private void privateSuperMethod(){

    }
    protected void protectedSuperMethod(){

    }
    public void publicSuperMethod(){

    }
}




4 获取类名和类加载器名称
Hello hello = new Hello();
System.out.println(hello.getClass().getName());
System.out.println(hello.getClass().getClassLoader().getClass().getName());

输出:
org.frank1234.reflect.Hello
sun.misc.Launcher$AppClassLoader //属于应用类加载器


5 获取Class类型的对象
  Class clazz1 = Class.forName("org.frank1234.reflect.Hello");
  Class clazz2 = Hello.class;
  Class clazz3 = new Hello().getClass();




6 实例化
Class clazz = Hello.class;
Hello hello = (Hello)clazz.newInstance();
hello.setName("frank1234");
System.out.println(hello);

输出结果:
name=frank1234,value=0


7 获取接口
Class clazz = Hello.class;
Class[] interfaces = clazz.getInterfaces();
for(int i=0;i<interfaces.length;i++){
    System.out.println(interfaces[i].getName());
}

输出:
org.frank1234.reflect.IHello

8 获取超类
Class clazz = Hello.class;
Class superClazz = clazz.getSuperclass();
System.out.println(superClazz.getName());


输出:
org.frank1234.reflect.SuperHello




9 获取属性
9.1 getFields和 getDeclaredFields
Class clazz = Hello.class;
Field[] fields = clazz.getFields();
for(int i=0;i<fields.length;i++){
    System.out.println(fields[i].getName());
}
System.out.println("----------------");
Field[] declaredFields = clazz.getDeclaredFields();
for(int i=0;i<declaredFields.length;i++){
    System.out.println(declaredFields[i].getName());
}

输出结果:
publicFiled
publicSuperFiled
----------------
name
value
protectedField
publicFiled

由此可见通过子类的clazz.getFields()可以获得父类的public属性,子类的public属性, 并不能获取它继承自父类的protected属性。
通过子类的clazz.getDeclaredFields()可以获取子类的全部修饰符的属性,包括private ,protected以及public类型的,但是不能获取从父类继承的属性。


9.2 getField
Class clazz = Hello.class;
Field field = clazz.getDeclaredField("name");
//获取类型
System.out.println(field.getType().getName());
//获取修饰符
System.out.print(Modifier.toString(field.getModifiers()));


输出:
java.lang.String
private

9.3 操作属性
Class clazz = Hello.class;
Hello hello = (Hello)clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(hello,"frank1234");
System.out.println(hello);

输出结果:
name=frank1234,value=0



10 获取方法
10.1 获取方法
Class clazz = Hello.class;
Hello hello = (Hello)clazz.newInstance();
//获取不带参数的方法
Method method = clazz.getMethod("sayHello");
method.invoke(hello);
//获取方法的修饰符
System.out.println(Modifier.toString(method.getModifiers()));
//获取带参数方法
Method paramMethod = clazz.getMethod("sayHello",new Class[]{String.class});
paramMethod.invoke(hello,new Object[]{" frank1234"});
//获取方法的入参
Class[] classes = paramMethod.getParameterTypes();
for(int i=0;i<classes.length;i++){
    System.out.println(classes[i].getName());
}
//获取方法的出参
System.out.println(paramMethod.getReturnType());

输出结果:
hello
public
hello frank1234
java.lang.String
void

10.2 getMethods和getDeclaredMethods
同getDeclaredFields和getFields的区别相同

10.3 调用getter和setter
Class clazz = Hello.class;
Hello hello = (Hello)clazz.newInstance();
String filedname = "name";
//构造settter和getter方法名称
String setterMethodName = "set" + filedname.substring(0,1).toUpperCase()+filedname.substring(1,filedname.length());
String getterMethodName = "get" + filedname.substring(0,1).toUpperCase()+filedname.substring(1,filedname.length());
//获取setter方法,并赋值
Method setterMethod = clazz.getMethod(setterMethodName,String.class);
setterMethod.invoke(hello,"frank1234");
//获取getter方法,并获取返回值
Method getterMethod = clazz.getMethod(getterMethodName);
String name = (String)getterMethod.invoke(hello);
System.out.print(name);

输出结果:
frank1234



11获取构造方法
11.1 获取构造方法并实例化

Class clazz = Hello.class;
//获取默认构造方法,并实例化
Constructor constructor = clazz.getConstructor();
Hello hello = (Hello)constructor.newInstance();
System.out.println(hello);
//获取带参数的构造方法,并实例化
Constructor constructorParam = clazz.getConstructor(String.class,int.class);
Hello helloparam = (Hello)constructorParam.newInstance("frank1234",20);
System.out.println(helloparam);

输出结果:
name=null,value=0
name=frank1234,value=20

11.2 调用私有构造方法
同操作私有属性一样,需要先设置setAccessible(true);才可以调用

13 获取异常
Class clazz = Hello.class;
Method method = clazz.getMethod("sayHello");
for (Class<?> exception : method.getExceptionTypes()) {
    System.out.print(exception.getName());
}

输出结果:
java.lang.Exception



14 数组
Class clazz = Hello.class;
Hello hello = (Hello)clazz.newInstance();
Field field = clazz.getDeclaredField("array");
System.out.println(field.getType());
System.out.println(field.getType().getComponentType());

输出结果:
class [I
int

15 获取泛型类型
Class clazz = Hello.class;
Field mapField = clazz.getDeclaredField("map");
Type mapMainType = mapField.getGenericType();
if (mapMainType instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType)mapMainType;
    // 获取基本类型信息,即Map
    Type basicType = parameterizedType.getRawType();
    System.out.println(basicType);
    // 获取泛型类型的泛型参数
    Type[] types = parameterizedType.getActualTypeArguments();
    for (int i = 0; i < types.length; i++) {
        System.out.println("泛型类型是:"+types[i]);
    }
} else {
    System.out.println("获取泛型类型出错!");
}

输出:
基本类型为:interface java.util.Map
泛型类型是:class java.lang.String
泛型类型是:class java.lang.Integer


16 getTypeParameters
TypeVariable[] tValue = List.class.getTypeParameters();
for(TypeVariable value:tValue){
    System.out.println(value.getName());
}
TypeVariable[] map = Map.class.getTypeParameters();
for(TypeVariable value:map){
    System.out.println(value.getName());
}

输出:
E
K
V
见List和Map的接口定义:
public interface List<E> extends Collection<E>
public interface Map<K,V>



你可能感兴趣的:(反射)