什么是反射?

反射给人的第一感觉:

常规调用是obj.field. / obj.method()
反射则是field.get(obj). / method.invoke(obj)
执行的主体发生了变化,非常适合于对象未定义的场景下,例如框架等通用场景。

反射的定义:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为JAVA语言的反射机制。

反射的API:

// Class类 Constructor类
@Test
public void demo1() throws Exception {
    // Class.forName(String class). 用于加载类的.class文件并封装为Class对象
    Class class1 = Class.forName("com.imooc.reflect.test.Person");
    // 获得无参构造
    Constructor c = class1.getConstructor();
    // 实例化对象 返回Object
    Person person = (Person)c.newInstance();
    person.eat();
}

@Test
public void demo2() throws Exception{
    Class class2 = Class.forName("com.imooc.reflect.test.Person”);
    // 获得带参构造
    Constructor c = class2.getConstructor(String.class, String.class);
    Person person = (Person)c.newInstance("张三","男");
    person.eat();
}
// Field类
@Test
public void demo1() throws Exception{
    Class class1 = Class.forName("com.imooc.reflect.test.Person");
    // 只能获得公有属性
    Field field = class1.getField("name");
    Person p = (Person)class1.newInstance();
    // 设置对象属性值
    field.set(p, "李四”);
    // 获得对象属性值 返回Object
    Object obj = field.get(p);
    System.out.println(obj);

}

@Test
public void demo2() throws Exception{
    Class class1 = Class.forName("com.imooc.reflect.test.Person”);
    // 获得所有属性,不论公有还是私有
    Field field = class1.getDeclaredField("sex");
    Person p = (Person)class1.newInstance();
    // 私有属性要设置可访问的权限
    field.setAccessible(true);
    field.set(p,"男");
    Object obj = field.get(p);
    System.out.println(obj);
}
// Method类
@Test
public void demo1() throws Exception{
    Class class1 = Class.forName("com.imooc.reflect.test.Person");
    Person p = (Person)class1.newInstance();
    // 获得公有方法
    Method method = class1.getMethod("eat");
    method.invoke(p);

}

@Test
public void demo2() throws Exception{
    Class class1 = Class.forName("com.imooc.reflect.test.Person");
    Person p = (Person)class1.newInstance();
    // 获得私有方法
    Method method = class1.getDeclaredMethod("run”);
    // 私有方法执行前要设置权限
    method.setAccessible(true);
    method.invoke(p);

}

@Test
public void demo3() throws Exception{
    Class class1 = Class.forName("com.imooc.reflect.test.Person");
    Person p = (Person)class1.newInstance();
    // 获得私有带参方法
    Method method = class1.getDeclaredMethod("hello", String.class);
    method.setAccessible(true);
    System.out.println(method.invoke(p, "张三"));
}

思考:为什么要有反射机制?

JAVA是一个完全面向对象的语言,但对象往往是个性的,围绕着对象展开的代码也是个性的(对象代码),逻辑上有个性就会有共性,那如果要实现一些共性的场景比如框架,该怎么办?
共性的代码需要围绕着共性的实体展开,比如Class对象、Constructor对象、Field对象、Method对象,所有的类都具备这四种实体,所以这些是共性的。在共性的场景中,Class、Constructor等是行为主体,而个性的对象实例则成为行为客体,这是反射中的一个反转点。
除了行为主体不同,共性场景的实现还要求有足够的权限。由于个性实例是复杂多样的,共性代码想要包罗万象必然需要被授权访问这些实例的所有内容,这是反射的另一个要点。
有时我们觉得有了反射机制那封装和访问修饰符还有什么用吗?在我看来由于对象代码和反射机制针对的场景不同,所以不存在冲突。如果硬要在对象代码中使用反射,那可能是代码编写者出现了问题。

上一篇:嵌入资源第一讲:Dll嵌入到WPF中


下一篇:const 和 readonly 的区别