09_反射

概述

通常能够分析类能力的程序称为反射(reflective)。程序员通过反射库(包括Class类,Constructor类等)完成业务功能,便是使用到了反射技术。反射的主要功能是在程序运行时分析类。一提到运行时分析类大家肯定第一个想到的是运行时多态。而反射也和运行时多态的功能一致,增强程序的可维护性和可拓展性。
运用反射技术来实现功能一般分为四步:获得Class对象、获得构造器、获得类的实例、运行。反射技术甚至可以获得私有信息。

获得Class对象

Class对象是在类加载时由Java虚拟机创建的封装某类型信息的对象。有三种获得方式:

public class TestClazz {
    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws ClassNotFoundException {
        //1、通过Object类的getClass()方法
        TestClazz tc = new TestClazz();
        Class clazz1 = tc.getClass();

        //2、通过类的静态class属性。
        Class clazz2 = TestClazz.class;

        //3、通过Class类中的方法构造。这种可拓展性更强,根本不需要知道类型,通过字符串就能获得。
        //但是也正是这个原因,可能发生ClassNotFoundException(main函数的此异常与前两者无关)
        Class clazz3 = Class.forName("com.first.TestClazz");
    }
}

获得构造器

  • 获得所有公共权限的构造方法(包括继承的):clazz.getConstructors();
import java.lang.reflect.Constructor;
public class TestClazz {
    public TestClazz(String msg) { System.out.println(msg); }
    public TestClazz() { }
    private TestClazz(int i) { System.out.println(i); }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");

        Constructor[] constructors = clazz.getConstructors();
        for(Constructor e:constructors)
            System.out.println(e);
        /*Console:
            public com.first.TestClazz(java.lang.String)
            public com.first.TestClazz()         */
    }
}
  • 获得指定参数的公共构造器(可以获得继承的):clazz.getConstructor((Class... parameterTypes);
import java.lang.reflect.Constructor;
public class TestClazz {
    public TestClazz(String msg) { System.out.println(msg); }
    public TestClazz() { }
    private TestClazz(int i) { System.out.println(i); }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");

        Constructor con1 = clazz.getConstructor();
        Constructor con2 = clazz.getConstructor(String.class);
        System.out.println(con1);
        System.out.println(con2);
        /*Console:
                public com.first.TestClazz()
                public com.first.TestClazz(java.lang.String)        */
    }
}
  • 获得所有的构造器(不包括继承的):clazz.getDeclaredConstructors();
import java.lang.reflect.Constructor;
public class TestClazz {
    private TestClazz(int i) { System.out.println(i); }
    public TestClazz(String msg) { System.out.println(msg); }
    public TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");

        Constructor []cons = clazz.getDeclaredConstructors();
        for(Constructor e : cons)
            System.out.println(e);
        /*Console:
                public com.first.TestClazz()
                public com.first.TestClazz(java.lang.String)
                private com.first.TestClazz(int)        */
    }
}
  • 获得指定的构造器(不包括继承的):clazz.getDeclaredConstructor((Class... parameterTypes);
import java.lang.reflect.Constructor;
public class TestClazz {
    private TestClazz(int i) { System.out.println(i); }
    public TestClazz(String msg) { System.out.println(msg); }
    public TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");

        Constructor con = clazz.getDeclaredConstructor(int.class);
        System.out.println(con);
        /*Console:
                private com.first.TestClazz(int)            */
    }
}

创建对象

  • 通过公共构造器创建对象:constructor.newInstance(Class... parameterTypes)方法。传入的参数类型和构造器的参数类型一致。
import java.lang.reflect.Constructor;

public class TestClazz {
    private TestClazz(int i) { System.out.println(i); }
    public TestClazz(String msg) { System.out.println(msg); }
    public TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Constructor con1 = clazz.getConstructor(String.class);
        Object obj1 = con1.newInstance("HelloWorld!");
        System.out.println(obj1);

        System.out.println("-----------------------");
        Constructor con2 = clazz.getConstructor();
        Object obj2 = con2.newInstance();
        System.out.println(obj2);
        /*Console:
                HelloWorld!
                com.first.TestClazz@7852e922
                -----------------------
                com.first.TestClazz@4e25154f             */
    }
}
  • 通过当前类不可访问的构造器创建对象:constructor.setAccessible(true);
import java.lang.reflect.Constructor;
public class TestClazz {
    private TestClazz(int i) { System.out.println(i); }
    public TestClazz(String msg) { System.out.println(msg); }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Constructor constructor = clazz.getDeclaredConstructor(int.class);

        //在本例中不写这句也能执行,因为被反射的类和当前类是同一个类,private的构造方法是可以被访问的
        //如果某个构造器是当前类不可访问的,此方法可以使其变成可访问的类型
        constructor.setAccessible(true);
        Object object = constructor.newInstance(1);
        System.out.println(object);
        /*Console:
                1
                com.first.TestClazz@7852e922         */
    }
}

快速获得对象

如果被反射的类有被当前类可访问的无参构造函数,可以直接使用clazz.newInstance();

import java.lang.reflect.Constructor;
public class TestClazz {
    private TestClazz(int i) { System.out.println(i); }
    public TestClazz(String msg) { System.out.println(msg); }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");

        Object object = clazz.newInstance();
        System.out.println(object);
        /*Console:
                com.first.TestClazz@7852e922         */
    }
}

获得成员变量

  • 获得所有公共类型的属性(包括继承的):clazz.getFields();
import java.lang.reflect.Field;
public class TestClazz {
    public String msg;
    private int i;

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Field[] fields = clazz.getFields();
        for(Field f : fields)
            System.out.println(f);
        /*Console:
                public java.lang.String com.first.TestClazz.msg         */
    }
}
  • 获得指定公共类型的属性(包括继承的):clazz.getField(String name);
import java.lang.reflect.Field;
public class TestClazz {
    public String msg;
    private int i;

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Field field = clazz.getField("msg");
        System.out.println(field);
        /*Console:
                public java.lang.String com.first.TestClazz.msg         */
    }
}
  • 获得所有的属性(不包括继承的):clazz.getDeclaredFields();
import java.lang.reflect.Field;
public class TestClazz {
    public String msg;
    private int i;

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Field []fields = clazz.getDeclaredFields();
        for(Field f : fields)
            System.out.println(f);
        /*Console:
                public java.lang.String com.first.TestClazz.msg
                private int com.first.TestClazz.i                       */
    }
}
  • 获得指定的属性(不包括继承的):clazz.getDeclaredField(String name);
import java.lang.reflect.Field;
public class TestClazz {
    public String msg;
    private int i;

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Field field = clazz.getDeclaredField("i");
        System.out.println(field);
        /*Console:
                private int com.first.TestClazz.i                       */
    }
}

设置成员变量的值

  • 设置可访问的变量的值:field.set(Object obj, Object value);
import java.lang.reflect.Field;
public class TestClazz {
    public String msg;
    private int i;
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        TestClazz object = (TestClazz)clazz.newInstance();
        Field field = clazz.getDeclaredField("msg");
        field.set(object, "HelloWorld!");
        System.out.println(object.msg);
        /*Console:
                HelloWorld!                     */
    }
}
  • 设置不可访问的变量的值:field.setAccessible(true);
import java.lang.reflect.Field;
public class TestClazz {
    public String msg;
    private int i;
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        TestClazz object = (TestClazz)clazz.newInstance();
        Field field = clazz.getDeclaredField("i");
        //在本例中不写这句也能执行,因为被反射的类和当前类是同一个类,private的属性是可以被访问的
        //如果某个属性是当前类不可访问的,此方法可以使其变成可访问的类型
        field.setAccessible(true);
        field.set(object, 65535);
        System.out.println(object.i);
        /*Console:
                65535                       */
    }
}

获得成员方法

  • 获得所有公共的方法(包括继承的和构造器):clazz.getMethods();
import java.lang.reflect.Method;

public class TestClazz {
    private int getI() { return i; }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Method[] methods = clazz.getMethods();
        for(Method m : methods)
            System.out.println(m);
        /*Console:
                public static void com.first.TestClazz.main(java.lang.String[]) throws java.lang.Exception
                public final void java.lang.Object.wait() throws java.lang.InterruptedException
                public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
                public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
                public boolean java.lang.Object.equals(java.lang.Object)
                public java.lang.String java.lang.Object.toString()
                public native int java.lang.Object.hashCode()
                public final native java.lang.Class java.lang.Object.getClass()
                public final native void java.lang.Object.notify()
                public final native void java.lang.Object.notifyAll()                       */
    }
}
  • 获得指定的公共方法(包括继承的,不包括构造器):clazz.getMethod(String name, Class<?>... parameterTypes);
import java.lang.reflect.Method;

public class TestClazz{
    public void show(String msg) { System.out.println(msg); }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Method m = clazz.getMethod("show", String.class);
        System.out.println(m);
        /*Console:
                public void com.first.TestClazz.show(java.lang.String)                  */
    }
}
  • 获得所有的方法(不包括继承的,不包括构造器):clazz.getDeclaredMethods();
import java.lang.reflect.Method;
public class TestClazz{
    private int getI() { return i; }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Method[] methods = clazz.getDeclaredMethods();
        for(Method m : methods)
            System.out.println(m);
        /*Console:
                public static void com.first.TestClazz.main(java.lang.String[]) throws java.lang.Exception
                private int com.first.TestClazz.getI()                  */
    }
}
  • 获得指定的方法(不包括继承的,不包括构造器):clazz.getDeclaredMethod(String name, Class<?>... parameterTypes);
import java.lang.reflect.Method;
public class TestClazz{
    private void show(String msg) { System.out.println(msg); }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Method m = clazz.getDeclaredMethod("show", String.class);
        System.out.println(m);
        /*Console:
                public void com.first.TestClazz.show(java.lang.String)                  */
    }
}

执行方法

  • 执行公共方法:method.invoke(Object obj, Object... args);
import java.lang.reflect.Method;
public class TestClazz{
    public void show(String msg) { System.out.println(msg); }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Object object = clazz.newInstance();
        Method m = clazz.getDeclaredMethod("show", String.class);
        m.invoke(object, "HelloWorld!");
        /*Console:
                HelloWorld                  */
    }
}
  • 执行私有方法:method.invoke(Object obj, Object... args);
import java.lang.reflect.Method;
public class TestClazz{
    private void show(String msg) { System.out.println(msg); }
    TestClazz() { }

    @SuppressWarnings("rawtypes")
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.first.TestClazz");
        Object object = clazz.newInstance();
        Method m = clazz.getDeclaredMethod("show", String.class);
        m.setAccessible(true);
        m.invoke(object, "HelloWorld!");
        /*Console:
                HelloWorld                  */
    }
}

总结

使用放射可以降低程序的耦合性,提升可拓展性和可维护性。配合配置文件、工厂模式、多态可实现IOC。

猜你喜欢

转载自blog.csdn.net/qq_38206090/article/details/82499037
今日推荐