有关反射的异常:
- InstantiationException 实例化异常:通常由没有构造方法,或没有public构造方法产生的异常,有此异常也会有IllegalAccessException 该异常。
- IllegalAccessException 非法访问异常:通常由访问修饰符不是public产生
- ClassNotFoundException 找不到类异常:通常由路径写错或类名写错产生
一:反射的作用
- 动态的创建一个对象,不需要new创建一个对象(更灵活,忽略访问权限)
- 操作的是运行编译后的对象
在java.lang包下有Reflec类
反射的api
invoke调用
二:反射的运行流程
- 第一步:由Java编译器进行源代码编译,得到相应类的字节码.class文件。
- 第二步:生成class文件之后,通过ClassLoader类加载器加载进内存,Java字节码由JVM执行解释给目标计算机。
- 第三步,目标计算机将结果呈现给我们计算机用户;因此,Java并不是编译机制,而是解释机制.class文件才可以在不同平台上运行加载。
三:利用反射机制获取类的三种方式
第一种:new一个对象,使用如下方式获取
Person person01=new Person();Class clazz=person01.getClass();
第二种:直接获取
Class clazz=类名.class;
第三种:使用Class.forName(“”)方法
Class clazz=Class.forName("包名.类名");
第四种:使用类加载器的方式获取
ClassLoader classLoader = RelfectTest.class.getClassLoader();Class<?> clazz = classLoader.loadClass("com.java.Person");
四:利用反射机制获取一个类的构造方法和属性
Class的 newInstance()方法创建对象 创建对象的前提条件:必须要有构造方法,权限必须为public
package com.java;import org.junit.Test;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class RelfectTest {@Testpublic void Test() {Person person = new Person("hanmeimei", 20);person.showAge(161);System.out.println(person.toString());}@Testpublic void Test01() throws Exception {Class clazz = Person.class;/*通过反射创建对象*/Constructor cons = clazz.getConstructor(String.class, Integer.class);//创建运行时实例Person person = (Person) cons.newInstance("tom", 12);System.out.println(person.toString());/*通过反射调用对象指定的属性,方法*///调用age属性,调用公共的属性Field age = clazz.getDeclaredField("age");//允许调用私有属性和方法age.setAccessible(true);age.set(person, 23);//调用name属性System.out.println(person.toString());/*调用公共方法*/Method showAge = clazz.getDeclaredMethod("showAge", Integer.class);/*调用方法,invoke调用的意思*/showAge.invoke(person, 20);/*调用私有的构造器*/Constructor cons1 = clazz.getDeclaredConstructor(String.class);//允许调用私有的属性和方法cons1.setAccessible(true);Object person1 = cons1.newInstance("lili");System.out.println(person1.toString());//调用私有方法Method showName = clazz.getDeclaredMethod("showName");showName.setAccessible(true);showName.invoke(person1);}}
1. 反射动态创建一个对象的应用
public Object getNewInstance(String path) throws ClassNotFoundException, IllegalAccessException, InstantiationException {Class<?> aClass = Class.forName(path);Object newInstance = aClass.newInstance();return newInstance;}@Testpublic void Test04() {for (int i = 1; i < 100; i++) {Random random = new Random();int num = random.nextInt(3);String path = " ";switch (num) {case 0:path = "java.util.Date";break;case 1:path = "com.java.Person";break;case 2:path = "java.lang.Object";default:break;}Object newInstance = null;try {newInstance = getNewInstance(path);System.out.println(newInstance);} catch (Exception e) {e.printStackTrace();}}}
2.通过反射获取一个类的所有信息(包含private,但不包含父类和实现类)和他的父类实现类的public信息
@Testpublic void Test05() {Class<Person> clazz = Person.class;//获取所有公共的属性Field[] fields = clazz.getFields();for (Field field : fields) {System.out.println(field);}}@Testpublic void Test06() {Class<Person> clazz = Person.class;//获取当前实例中所有属性(私有公有全部获取),不包含父类的Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {System.out.println(field);}}@Testpublic void Test07() {Class<Person> clazz = Person.class;//获取当前实例中所有属性(私有公有全部获取),不包含父类的Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {//获取权限修饰符int modifiers = field.getModifiers();System.out.println(Modifier.toString(modifiers));//获取数据类型Class<?> type = field.getType();System.out.println(type);//获取变量名String name = field.getName();System.out.println(name);}}@Testpublic void Test08() {Class<Person> clazz = Person.class;//获取当前类的所有公共的方法(包含父类的,实现类的)Method[] methods = clazz.getMethods();for (Method method : methods) {Parameter[] parameters = method.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter.getName());}}//获取当前类的所有方法(不包含继承的,实现的,忽略访问权限)Method[] declaredMethods = clazz.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}}@Testpublic void Test09() {Class<Person> clazz = Person.class;//获取当前类的所有方法(不包含继承的,实现的,忽略访问权限)Method[] declaredMethods = clazz.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {//获取访问修饰符int modifiers = declaredMethod.getModifiers();System.out.print(Modifier.toString(modifiers) + "\t");//获取返回值类型Class<?> returnType = declaredMethod.getReturnType();System.out.print(returnType + "\t");//获取方法名String name = declaredMethod.getName();System.out.print(name);System.out.print("(");//获取参数类型Class[] parameterTypes = declaredMethod.getParameterTypes();String parameterName = "";Parameter[] parameters = declaredMethod.getParameters();if (!(parameterTypes == null && parameterTypes.length == 0)) {for (int i = 0; i < parameterTypes.length; i++) {for (int j=0;j<parameters.length;j++) {parameterName = parameters[j].getName();System.out.print(parameterName);}if (i == parameterTypes.length - 1) {System.out.print(parameterTypes[i].getName() +" "+ parameterName);break;}System.out.print(parameterTypes[i].getName()+" "+parameterName + ",");}System.out.print(")");}//获取异常Class<?>[] exceptionTypes = declaredMethod.getExceptionTypes();if (exceptionTypes.length > 0) {System.out.print(" throws ");for (int i = 0; i < exceptionTypes.length; i++) {String name1 = exceptionTypes[i].getName();if (i == exceptionTypes.length - 1) {System.out.print(name1);break;}System.out.print(name1 + ",");}}System.out.println();}}
五:Class类的运用(对对象的描述的类)
六:加载配置文件的两种方式
@Testpublic void Test02() throws IOException {/*** 读取配置文件的方式一,默认在moudle下* 通过流的方式读取文件* 优点:只要路径对,可以加载任意位置的文件*///创建配置文件对象Properties properties=new Properties();//获取配置文件流InputStream inputStream = new FileInputStream("src\\main\\resources\\jdbc1.properties");//加载配置文件properties.load(inputStream);/*** 读取配置文件的方式二* 使用ClassLoader* 缺点:默认加载的是src下的文件*/ClassLoader classLoader = RelfectTest.class.getClassLoader();InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc1.properties");properties.load(resourceAsStream);//获取配置文件的内容并打印String user = properties.getProperty("password");System.out.println(user);}
