Java反射机制概述
Reflection
(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于
Reflection API
取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
正常方式: 引入需要的包名称 → 通过new实例化对象 → 取得实例化对象
反射方式: 通过实例化对象 → getClass()方法 → 得到完整的包名称
Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时获取泛型信息。
- 在运行时调用任意一个对象的成员变量和方法。
- 在运行时处理注解。
- 生成动态代理。
public class Person {private String name;public int age;public void show() {System.out.println(\"您好!世界\");}private String showNation(String nation){System.out.println(\"我的国际是:\" + nation);return nation;}private Person(String name) {this.name = name;}.....}public void test2() throws Exception {Class clazz = Person.class;// 1.通过反射,创建Person类的对象Constructor cons = clazz.getConstructor(String.class, int.class);Object obj = cons.newInstance(\"Tom\", 12);Person p = (Person) obj;System.out.println(p.toString());// 2.通过反射,调用指定的属性、方法、对象// 调属性Field age = clazz.getDeclaredField(\"age\");age.set(p,10);System.out.println(p.toString());// 调方法Method method = clazz.getDeclaredMethod(\"show\");method.invoke(p);// 通过反射是可以调用私有的属性、方法、构造器// 调用私有构造器Constructor cons1 = clazz.getDead8claredConstructor(String.class);cons1.setAccessible(true);Person p1 = (Person) cons1.newInstance(\"Jerry\");System.out.println(p1);// 调用私有方法Field name = clazz.getDeclaredField(\"name\");name.setAccessible(true);name.set(p1,\"Han\");System.out.println(p1);// 调用私有方法Method method1 = clazz.getDeclaredMethod(\"showNation\", String.class);method1.setAccessible(true);String invoke = (String) method1.invoke(p1, \"中国\");System.out.println(invoke);}
java.lang.Class类的理解
- 类的加载过程:程序经过java.exe命令以后,会生成一个或多个字节码文件(.class),接着使用java.exe命令对字节码进行解释运行。相当与将某个字节码文件加载到内存中,此过程称为类的加载。加载到内存中的类,我们称之为运行时类,此运行时类,就作为Class的一个实例。
- Class的实例就是对应着一个运行时类。
- 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同方式来获取从运行时类。
// 获取Class的实例的方法public void test3() throws ClassNotFoundException {// 方式一:调用运行时类的属性.classClass clazz1 = Person.class;// 方式二:通过运行时类的对象Person person = new Person();Class clazz2 = person.getClass();// 方法三:调用Class的静态方法forName(String classPath)Class clazz3 = Class.forName(\"com.tyt.java.Person\");// 方式四:类的加载器 ClassLoaderClassLoader classLoader = ReflectionTest.class.getClassLoader();Class clazz4 = classLoader.loadClass(\"com.tyt.java.Person\");System.out.println(clazz1 == clazz2);System.out.println(clazz2 == clazz3);System.out.println(clazz3 == clazz4);}
Class实例可以是那些结构的说明:
public void test5() {Class c1 = Object.class;Class c2 = Comparable.class;Class c3 = String[].class;Class c4 = int[][].class;Class c5 = ElementType.class;Class c6 = Override.class;Class c7 = int.class;Class c8 = void.class;Class c9 = Class.class;int[] a = new int[10];int[] b = new int[100];Class c10 = a.getClass();Class c11 = b.getClass();// 只要数组元素类型与维度一样,就是同一个ClassSystem.out.println(c10 == c11);// true}
使用Properties:用于读取配置文件。
// 目录结构// |--module// |---stc// |----com.tyt.java// |-----PropertiesTest.java// |-----jdbc1.properties// |--jdbc.propertiespublic void test2() {String user = null;String passwored = null;FileInputStream inputStream = null;try {Properties properties = new Properties();// 读取配置方式一:// inputStream = new FileInputStream(\"jdbc.properties\");// properties.load(inputStream);// 读取配置方式二:使用ClassLoader// 配置文件默认识别为:当前module的src下ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();InputStream inputStream1 = classLoader.getResourceAsStream(\"jdbc1.properties\");properties.load(inputStream1);user = properties.getProperty(\"user\");passwored = properties.getProperty(\"passwored\");System.out.println(\"user = \" + user + \",passwored = \" + passwored);} catch (IOException e) {e.printStackTrace();} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}}