反射机制
反射机制有什么用?
通过反射机制可以操作代码片段(class文件),可以让程序更加灵活
反射机制的相关类在哪个包下?
java.lang.reflect.*;
反射机制相关的重要的类有哪些?
java.lang.Class:代表整个字节码文件
java.lang.reflect.Method:代表字节码中的方法字节码
java.lang.reflect.Constructor:代表字节码中的构造方法字节码
java.lang.reflect.Field:代表字节码中的属性字节码,代表类中的成员变量(静态变量 + 实例变量)
获取Class的三种方式
第一种方式:
public static void main(String[] args) {
/*
Class.forName()
1.静态方法
2.方法的参数是一个字符串
3.字符串需要的是一个完整类名
4.完整类名必须带有包名,java.lang也不能省略
*/
Class c1 = null;
Class c2 = null;
try {
c1 = Class.forName("java.lang.String"); // c1代表String.class文件,或者说c1代表String类型
c2 = Class.forName("java.util.Date");// c2代表Date类型
Class c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
第二种方式:
//java中任何一个对象都有一个方法:getClass() String s = "abc"; Class x = s.getClass(); // x代表String.class字节码文件,x代表String类型 System.out.println(c1 == x);// true( == 判断的是对象的内存地址) Date time = new Date(); Class t = time.getClass(); System.out.println(t == c2);// true(c2和t中保存的内存地址都是一样的,都指向方法区当中的字节码文件)
第三种方式
//java语言中任何一种类型,他都有.class属性 Class a = String.class; //a代表String类型 Class b = Date.class; Class c = int.class; Class d = double.class; System.out.println(a == x); //true
获取Class之后,可以调用无参数构造方法来实例化对象
public static void main(String[] args) { try { // 通过反射机制获取Class,通过Class来实例化对象 Class u = Class.forName("com.cedric.java.been.User"); // newInstance()这个方法会调用User这个类的无参数构造方法,完成对象的创建 // 重点:newInstance()调用的是无参构造,必须保证无参构造是存在的 Object o = u.newInstance(); System.out.println(o); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } }
注意:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在才可以
如果只想让一个类的“静态代码块”执行的话,可以这样
Class.forName("该类的类名"); 这样类就加载了,类加载的时候静态代码块执行!!
关于路径问题?
String path = Thread.currentThread().getContextClassLoader(). getResourse("写相对路径,但是这个相对路径从src触发开始找").getPath() 这种方式是为了获取一个文件的绝对路径(通用方式,不会受到环境移植的影响) 但是该文件要求放在类路径下,也就是放在src下,src是类的根路径 直接以流的形式返回: InputStream in = Thread.currentThread().getContextClassLoader. getResourseAsStream("com/cedric/test.properties");
IO + Properties,怎么快速绑定属性资源文件?
public static void main(String[] args) { try { // 代码是灵活的,不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象 // 通过IO读取classinfo.properties文件 FileReader read = new FileReader("Reflex/classinfo.properties"); // 创建属性类对象Map Properties pro = new Properties(); // 加载 pro.load(read); // 关闭 read.close(); // 通过key获取value String s = pro.getProperty("className"); // 通过反射机制实例化对象 Class c = Class.forName(s); Object o = c.newInstance(); System.out.println(o); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } }
Filed
反射Student类中所有的Filed
public static void main(String[] args) { // 获取整个类 try { Class studentClass = Class.forName("com.cedric.java.been.Student"); //com.cedric.java.been.Student String scName = studentClass.getName(); System.out.println("完整类名:" + scName); // 简类名 String simpleName = studentClass.getSimpleName(); System.out.println("简类名:" + simpleName); // 获取到所有的public修饰的Filed Field[] files = studentClass.getFields(); System.out.println(files.length); // 测试数组中只有一个元素 // 取出这个Filed Field fileds = files[0]; // 取出这个Field他的名字 String s = fileds.getName(); System.out.println(s); // 获取所有的Field Field[] fs = studentClass.getDeclaredFields(); System.out.println(fs.length); //4 System.out.println("===================="); // 遍历 for(Field field : fs){ // 获取属性的修饰符列表 int i = field.getModifiers(); // 返回的修饰符是一个数字,每一个数字是修饰符的代号 System.out.println(i); // 将代号数字转换成字符串 String modifierString = Modifier.toString(i); System.out.println(modifierString); // 获取属性的类型 Class fieldType = field.getType(); //String fieldName = fieldType.getName(); String fieldName = fieldType.getSimpleName(); System.out.println(fieldName); // 获取属性的名字 System.out.println(field.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } }
反编译
通过反射机制,反编译一个类的属性Field
public static void main(String[] args) { try { StringBuilder s = new StringBuilder(); Class studentClass = Class.forName("com.cedric.java.been.Student"); s.append(Modifier.toString(studentClass.getModifiers()) + " " + "class" + " " + studentClass.getSimpleName() + "{" + '\n'); Field[] fields = studentClass.getDeclaredFields(); for(Field field : fields){ s.append('\t'); s.append(Modifier.toString(field.getModifiers())); s.append(" "); s.append(field.getType().getSimpleName()); s.append(" "); s.append(field.getName()); s.append(";\n"); } s.append("}"); System.out.println(s); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
反编译Method(反编译一个类的方法)
public static void main(String[] args) { try { StringBuilder s = new StringBuilder(); Class userServiceClass = Class.forName("com.cedric.java.been.UserService"); s.append(Modifier.toString(userServiceClass.getModifiers()) + " class " +userServiceClass.getSimpleName() + "{\n"); Method[] methods = userServiceClass.getDeclaredMethods(); for(Method method : methods){ s.append("\t"); s.append(Modifier.toString(method.getModifiers())); s.append(" "); s.append(method.getReturnType().getSimpleName()); s.append(" "); s.append(method.getName()); s.append("("); // 参数列表 Class[] parameterTypes = method.getParameterTypes(); for(Class parameterType : parameterTypes){ s.append(parameterType.getSimpleName()); s.append(","); } // 删除指定下标位置上的字符 s.deleteCharAt(s.length() - 1); s.append("){}\n"); } s.append("}"); System.out.println(s); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
反编译Constructor
public static void main(String[] args) { StringBuilder s = new StringBuilder(); try { Class vipClass = Class.forName("com.cedric.java.been.Vip"); s.append(Modifier.toString(vipClass.getModifiers())); s.append(" class "); s.append(vipClass.getSimpleName()); s.append("{\n"); // 拼接构造方法 Constructor[] constructors = vipClass.getDeclaredConstructors(); for(Constructor constructor : constructors){ s.append("\t"); s.append(Modifier.toString(constructor.getModifiers())); s.append(" "); s.append(vipClass.getSimpleName()); s.append("("); // 拼接参数 Class[] parameter = constructor.getParameterTypes(); for(Class parameterType : parameter){ s.append(parameterType.getSimpleName()); s.append(","); } if(parameter.length > 0){ // 删除最后下标位置上的字符 s.deleteCharAt(s.length() - 1); } s.append("){}\n"); } s.append("}"); System.out.println(s); } catch (ClassNotFoundException e) { e.printStackTrace(); }
怎么通过反射机制访问一个java对象的属性?
// 使用反射机制,怎么去获取一个对象的属性(set get) Class studentClass = Class.forName("com.cedric.java.been.Student"); Object obj = studentClass.newInstance(); // obj就是Student对象(底层调用无参数构造方法) // 获取name属性 Field noFiled = studentClass.getDeclaredField("name"); // 给obj对象(Student对象)的name属性赋值 noFiled.set(obj,"zhangsan"); // 给obj对象的no属性赋值1111 // 读取属性的值 System.out.println(noFiled.get(obj));
//打破封装 反射机制访问java私有属性: noField.setAccessible(true);
Method
// 获取类 Class userServiceClass = Class.forName("com.cedric.java.been.UserService"); // 获取所有的Method(包括私有的) Method[] methods = userServiceClass.getDeclaredMethods(); // 遍历Method for(Method method : methods){ // 获取修饰符列表 System.out.println(Modifier.toString(method.getModifiers())); // 获取方法的返回值类型 Class methodType = method.getReturnType(); System.out.println(methodType.getSimpleName()); // 获取方法名 System.out.println(method.getName()); // 方法的修饰符列表(一个方法的参数可能会有多个) Class[] parameterType = method.getParameterTypes(); for(Class parameter : parameterType){ System.out.println(parameter.getSimpleName()); }
通过反射机制怎么调用一个对象的方法
public static void main(String[] args) { /* 要素分析: 要素1:对象userService 要素2:login方法名 要素3:实参列表 要素4:返回值 */ // 使用反射机制来调用一个对象的方法该怎么做 try { Class userServiceClass = Class.forName("com.cedric.java.been.UserService"); // 创建对象 Object obj = userServiceClass.newInstance(); // 获取Method Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class); //调用方法 // 反射机制中最重要的方法 /* 四要素: loginMethod方法 obj对象 “admin”,“123”实参 retValue返回值 */ Object retValue = loginMethod.invoke(obj,"admin","123"); System.out.println(retValue);
通过反射机制调用构造方法实例化java对象
try { Class c = Class.forName("com.cedric.java.been.Vip"); // 调用无参构造 Object o = c.newInstance(); System.out.println(o); // 调用有参数构造方法 // 第一步:先获取到这个有参数的构造方法 Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class); // 第二步,调用构造方法new对象 Object obj = con.newInstance(110,"Jack","2001-01-01",true); System.out.println(obj); // 获取无参构造方法 Constructor con1 = c.getDeclaredConstructor(); Object obj1 = con1.newInstance(); System.out.println(obj1); } catch (ClassNotFoundException e) { e.printStackTrace(); }
给你一个类,怎么获取这个类的父类,已经实现了哪些接口?
// String try { Class stringClass = Class.forName("java.lang.String"); // 获取String的父类 Class stringSuper = stringClass.getSuperclass(); System.out.println(stringSuper); // 获取String类实现的所有接口 Class[] interfaces = stringClass.getInterfaces(); for(Class in : interfaces){ System.out.println(in.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); }
资源绑定器
/* java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容 使用以下这种方式的时候,属性配置文件xx.Properties必须放到类路径下 */ public class ResourceBundleTest { public static void main(String[] args) { // 资源绑定器,只能绑定xx.Properties文件,并且这个文件必须在类路径下,文件扩展名也必须是Properties // 并且在写路径的时候,路径后面的扩展名不能写 ResourceBundle bundle = ResourceBundle.getBundle("classinfo2"); String className = bundle.getString("className"); System.out.println(className); } }