通过反射构造对象

有了Class对象就可以创建这个类的对象了,反射机制中有两种构造对象的方法:Class类.newInstance()和构造器.newInstance(参数)。前者调用的是无参构造器,后者调用的是有参构造器,参数是有参构造器需要的参数。

  1. @Test
  2. public void test() {
  3. User user = null;
  4. try {
  5. user = User.class.newInstance();
  6. } catch (InstantiationException | IllegalAccessException e) {
  7. e.printStackTrace();
  8. }
  9. System.out.println(user);
  10. }

image.png

  1. @Test
  2. public void test() {
  3. try {
  4. Constructor<User> constructor=User.class.getConstructor(Integer.class,String.class,String.class);
  5. User user = constructor.newInstance(6, "阿离", "123456");
  6. System.out.println(user);
  7. } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
  8. e.printStackTrace();
  9. }
  10. }

image.png
如果使用反射来创建数组,那么参数依次需要数组类型和数组长度,Class类则是Array类:

  1. @Test
  2. public void test() throws ClassNotFoundException {
  3. Class<?> clazz = Class.forName("java.lang.String");
  4. Object array = Array.newInstance(clazz, 25);
  5. //往数组里添加内容
  6. Array.set(array, 0, "Scala");
  7. Array.set(array, 1, "Java");
  8. Array.set(array, 2, "Groovy");
  9. Array.set(array, 3, "Scala");
  10. Array.set(array, 4, "Clojure");
  11. //获取某一项的内容
  12. System.out.println(Array.get(array, 3));
  13. }

通过反射调用方法

Class类除了可以创建对象,还可以调用指定的方法:可以先通过Class类的getDeclaredMethod方法获取指定的方法,并设置需要的参数,然后使用invoke方法进行激活该方法,并向该方法中传递要设置的obj对象的参数。Method类的invoke方法的语法:“方法(Method).invoke(Object obj , Object[] args)”。如果调用的方法是静态方法,那么obj设置为null;如果没有方法参数,则args设置为null。

如果调用的Method是private修饰的,在使用invoke方法之前必须先调用setAccessible方法,除了是设置访问权限,还关闭了安全检查(Java语言是安全的,这是因为它在编译和加载时都会进行安全检查。每次都进行检查,就像我们每次做事前都要准备一下,这样势必会降低我们的执行效率,因此这也是Java程序运行起来相比较C和C++慢的原因),如:

  1. public static void test02() throws Exception{
  2. User user = new User(1,"阿狸","123654");
  3. Class<? extends User> clazz = user.getClass();
  4. Method method = clazz.getDeclaredMethod("getName", null);
  5. method.setAccessible(true);
  6. Object result = method.invoke(user, null);
  7. System.out.println(result);
  8. }

image.png
注意这里的Method类如果是public修饰的,调用setAccessible(true)只是取消安全检查,设置为false依然可以访问,取消安全检查的目的是为了提高反射效率。

通过反射调用属性

Class类可以调用对象的属性:先通过getDeclaredField获取对象的属性,然后如果调用的属性是private的话,就需要使用setAccessible方法(参数设置为true)来获取权限(使用setAccessible方法还可以提高反射的运行速率)。
语法:使用“属性(Field).set(对象obj,“属性值”)”来改变属性值;使用“属性(Field).get(对象obj)”来访问属性。
通常的po类对象都是有getXxx、setXxx方法的,可以通过getXxx、setXxx访问属性,但是如果没有这些方法,就可以使用反射来访问类的属性了。

@Test
public void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
    User user = new User(1, "阿离", "123654");
    Class<? extends User> clazz = user.getClass();
    Field field=clazz.getDeclaredField("name");
    field.setAccessible(true);
    field.set(user,"小阿狸");
    Object result = field.get(user);
    System.out.println(result);
}

image.png
如果访问的是private属性,并且不调用setAccessible(true)则会抛出异常:
image.png