反射给人的第一感觉:
常规调用是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等是行为主体,而个性的对象实例则成为行为客体,这是反射中的一个反转点。
除了行为主体不同,共性场景的实现还要求有足够的权限。由于个性实例是复杂多样的,共性代码想要包罗万象必然需要被授权访问这些实例的所有内容,这是反射的另一个要点。
有时我们觉得有了反射机制那封装和访问修饰符还有什么用吗?在我看来由于对象代码和反射机制针对的场景不同,所以不存在冲突。如果硬要在对象代码中使用反射,那可能是代码编写者出现了问题。