Java反射

Class类的使用

  • 所有类都是Class类的对象,这种对象有三种表示方式
// c1/c2/c3是Foo的类类型
// 一个类的类类型只有一个,即 c1==c2==c3
Class c1 = Foo.class;
Class c2 = foo.getClass();
Class c3 = Class.forName("Foo");
  • 可以通过类类型创建对象
Foo foo = (Foo)c1.newInstance(); // Foo需要有无参构造方法
  • 基本数据类型、void关键字都有类类型

方法的反射

  • Method类:一个方法就是一个Method对象。
  • 根据类类型获取方法
 // 获取public方法,包括父类方法
Method[] methods = c.getMethods();
// 获取当前类声明的方法,不论访问权限
Method[] methods = c.getDeclaredMethods();
  • 根据方法获取返回值类类型
Class returnClassType = method.getReturnType();
  • 获取方法名称
String methodName = method.getName();
  • 根据方法获取方法参数类类型数据
Class[] paramClassTypes = method.getParameterTypes();
  • 获取某一方法
// 获取带两个int类型参数的,名字为print的方法
Method method = c.getMethod("print",int.class,int.class) 
  • 方法的操作
    格式:method.invoke(obj,params[])
//调用a对象的print方法,传入两个参数
method.invoke(a,10,20);
//和直接调用方法效果一样
a.print(10,20);

成员变量的反射

  • Field类:一个成员变量就是一个Field对象。
  • 根据类类型获取成员变量
 // 获取public成员变量,包括父类成员变量
Field[] fields = c.getFields();
// 获取当前类声明的成员变量,不论访问权限
Field[] fields = c.getDeclaredFields();
  • 例子
// 修改字符串的内容而不修改地址
        //获取之前的值
        String s = new String("abc");
        System.out.println(s);
        String s1 = s;

        //利用反射属性修改值
        Field field = null;
        try {
            field = s.getClass().getDeclaredField("value");

            field.setAccessible(true);
            field.set(s,"abcd".toCharArray());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //修改后的值
        System.out.println(s);
        System.out.println(s1 == s);
  • 获取成员变量的类类型
Class fieldClassType = field.getType();
  • 获取成员变量名称
String fieldName = field.getName();

构造函数的反射

  • Constructor类:一个构造函数就是一个Constructor对象。
  • 根据类类型获取构造函数
 // 获取public构造函数,包括父类构造函数
Constructor[] constructors = c.getConstructors();
// 获取当前类声明的构造函数,不论访问权限
//建议使用,因为构造方法都需要自己声明
Constructor[] constructors = c.getDeclaredConstructors();
  • 获取构造函数名称
String methodName = constructor.getName();
  • 根据方法获取构造函数参数类类型数据
Class[] paramClassTypes = constructor.getParameterTypes();

Java类加载机制

  • 静态加载类:编译时加载类
    new对象是静态加载类,在编译时加载可能用到的类
  • 动态加载类:运行时加载类
    Class.forName得到类类型,通过类类型创建对象是动态加载

需求实例:程序中如果是World调用World的启动方法,如果是Excel调用Excel的启动方法,等等。
思路:如果直接在这个类中使用World、Excel等类,当某一个可能不会用到的类不存在时会报错,所以需要动态加载

1.抽象出公共功能:

public interface OfficeAble {
    void start();
}

2.实际类拥有功能:

public class World implements OfficeAble {
    @Override
    public void start() {
        System.out.println("World start...");
    }
}
public class Excel implements OfficeAble {
    @Override
    public void start() {
        System.out.println("Excel start...");
    }
}

3.实际使用:

public class OfficeTest {
    public static void main(String[] args) {
        try {
//            Class c = Class.forName("com.zp.zptest.reflect.World");
            Class c = Class.forName("com.zp.zptest.reflect.Excel");
            OfficeAble officeAble = (OfficeAble) c.newInstance();
            officeAble.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

用反射认识泛型的本质

  • 反射是编译后的操作
  • 编译后的集合是去泛型化的
  • Java泛型是为了防止错误输入,只在编译时生效
  1. 反射是去泛型化的:
        ArrayList list1 = new ArrayList();
        ArrayList list2 = new ArrayList();
        Class c1 = list1.getClass();
        Class c2 = list2.getClass();
        System.out.println(c1 == c2); // 结果为true
  1. 使用反射给c2添加整型元素:
        list2.add("hello");
        Method method = c2.getMethod("add",Object.class);
        method.invoke(list2,10);
        System.out.println(list2); // [hello,10]

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