反射机制
通过java语言中的反射机制可以操作字节码文件。
类似于黑客(可以读和修改字节码文件)
通过反射机制可以操作代码片段(class文件)
反射机制的相关类在那个包下?
java.lang.reflect.*;
反射机制相关的重要的类有哪些
java.lang.Class: 代表整个字节码,代表一个类型,代表一个类
java.lang.reflect.Method:代表字节码中的方法字节码。
java.lang.reflect.Constructor:代表字节码中的构造方法字节码。
java.lang.reflect.Field:代表字节码中的属性字节码。
获取Class的三种方式
第一种方式:
package com.aaa.reflex;
import com.sun.media.jfxmediaimpl.HostUtils;
public class ReflectTest01 {
public static void main(String[] args) {
/*
* Class.forName(); 类的名称
* 1. 静态方法
* 2. 方法的参数是一个字符串
* 3. 字符串需要一个完整的类名
* 4.完整的类名包括包名。
* */
try {
Class c1=Class.forName("java.lang.String"); //获取到String的字节码文件,就是String类型
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
第二种方式 :
Object类中有一个getClass()方法
String s="abc";
Class aClass = s.getClass();
System.out.println(aClass);
第三种方式
Class z= String.class; //代表String类型
Class y=Date.class; //代表Date类型
package com.aaa.reflex;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
/*
*
* 验证反射机制的灵活性
* 这样写代码的好处是不修改源代码,只需要修改配置文件中的配置就可以实现不同的效果。
* */
public class ReflectTest03 {
public static void main(String[] args) throws Exception{
FileReader fileReader = new FileReader("java-05-reflex/src/classinfo.properties");
Properties properties=new Properties();
//加载classinfo.properties文件
properties.load(fileReader);
//关闭流
fileReader.close();
String className = properties.getProperty("className");
//使用反射机制来获取类的字节码文件
Class c1=Class.forName(className);
//使用反射机制来实例化对象
Object o = c1.newInstance();
System.out.println(o);
}
}
文件路径问题
package com.aaa.reflex;
/*
*
* */
public class ReflectTest04 {
public static void main(String[] args) {
//获取文件的绝对路径 通用的。前提是:文件需要在类路径下
/*
* Thread.currentThread():获取当前线程
* getContextClassLoader()是线程的方法,可以获取到当前线程的类加载器对象
* getResource() 获取资源 这是类加载器的方法,当前线程的类加载器默认从类的根目录(src)下加载资源
* */
String path = Thread.currentThread().getContextClassLoader().
getResource("classinfo2.properties").getPath();
System.out.println(path);
}
}
资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用这种方式,属性配置文件xx.properties必须放到类路径下。
//资源绑定器,只能绑定xxx.properties文件。并且这个文件必须在类路径下。文件扩展名也必须是properties
//并且在写路径的时候,路径后边的扩展名不能写。
import java.util.ResourceBundle;
public class ResourcBundTest {
public static void main(String[] args) {
//资源绑定器 只能绑定xxx.properties ,文件必须在类路径下
//文件的扩展名不能写。
ResourceBundle resourceBundle=ResourceBundle.getBundle("classinfo");
String className = resourceBundle.getString("className");
System.out.println(className);
}
}
类加载器有3个分别是启动类加载器,扩展类加载器,应用类加载器。
加载顺序 :启动类加载器加载不到,在使用扩展类加载类,否则使用应用类加载器。
java中为了保证类加载的安全,使用了双亲委派机制
优先从启动类加载器中加载,这个称为父
父加载不到,再从扩展类加载器中加载这个称为母。
双亲委派。如果都加载不到,才会考虑从应用加载器中加载。直到加载到为止。
获取Field
package com.aaa.reflex;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectFieldTest01 {
public static void main(String[] args) throws Exception {
Class studentClass=Class.forName("com.aaa.bean.Student");
//获取Field(属性)
//getFields()方法只能获取到 公用的属性
Field[] fields = studentClass.getFields();
//获取到属性的访问权限修饰符,类型,全限定类名
Field field=fields[0];
System.out.println(field);
System.out.println("================");
//返回所有的属性无论是不是公有的还是私有的等
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
//获取到属性的修饰符列表
int modifiers = declaredField.getModifiers();
//可以将这个“代号”数字转成字符串
String string = Modifier.toString(modifiers);
System.out.println(string);
//获取到属性的类型
Class type = declaredField.getType();
//获取到属性类型的完整名称
//String name = type.getName();
// System.out.println(name);
//获取到属性类型的简单名称
String simpleName = type.getSimpleName();
System.out.println(simpleName);
//获取到属性的名字
System.out.println(declaredField.getName());
}
}
}
反编译Field(了解)
package com.aaa.reflex;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
* 反编译类的属性
* */
public class ReflectFieldTest02 {
public static void main(String[] args) throws Exception{
StringBuilder s=new StringBuilder();
//获取class类对象
Class studentClass=Class.forName("com.aaa.bean.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(";");
s.append("\n");
}
s.append("}");
System.out.println(s);;
}
}
通过反射机制访问对象属性(重点)
package com.aaa.reflex;
import com.aaa.bean.Student;
import java.lang.reflect.Field;
/*
* 重点:
* 怎么通过反射机制访问一个java对象的属性?
* 给属性赋值set
* 获取属性的值get
*
*
* */
public class ReflexTest05 {
public static void main(String[] args) throws Exception{
//使用反射机制获取类
Class<Student> studentClass= (Class<Student>) Class.forName("com.aaa.bean.Student");
//通过反射机制获取的类来实例化这个对象
Student student = studentClass.newInstance();
//获取no属性(根据属性名来获取到属性)
Field no = studentClass.getDeclaredField("no");
//给student对象的no属性赋值
/*
* 虽然使用了反射机制,但是三要素缺一不可。
* 要素一:student对象
* 要素二:no属性
* 要素三:123值
* */
no.set(student,123);
//获取到student对象中no的属性值。
System.out.println(no.get(student));
}
}
Field name = studentClass.getDeclaredField("name"); name.setAccessible(true); //打破封装,可以访问不是public修饰的属性 name.set(student,"小兵"); System.out.println(name.get(student));
反射机制的缺点:打破封装,可能会给不法分子留下机会
反射Method(了解)
package com.aaa.reflex;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
/*
* 反射方法Method
* */
public class ReflectMethodTest {
public static void main(String[] args) throws Exception{
Class userServiceClass=Class.forName("com.aaa.service.UserService");
Method[] declaredMethods = userServiceClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
//获取方法的访问修饰符
String modifier = Modifier.toString(declaredMethod.getModifiers());
System.out.println("方法的访问修饰符"+modifier);
//获取方法的返回值
Class returnType = declaredMethod.getReturnType();
String name = returnType.getSimpleName();
System.out.println("方法的返回值类型"+name);
//获取方法的方法名
String methodName = declaredMethod.getName();
System.out.println(methodName);
//获取方法的形式参数
Class [] genericParameterTypes = declaredMethod.getParameterTypes();
for (Class genericParameterType : genericParameterTypes) {
String simpleName = genericParameterType.getSimpleName();
System.out.println("参数列表"+simpleName);
}
}
}
}
反射机制调用方法(重点,必须掌握)
package com.aaa.reflex;
import com.aaa.bean.User;
import com.aaa.service.UserService;
import java.lang.reflect.Method;
/*
*
* 使用反射机制调用方法
* */
public class ReflectMethodTest03 {
public static void main(String[] args) throws Exception {
//不使用反射机制怎么调用方法
UserService userService=new UserService();
userService.logout();
//首先我们需要把对象给实例化出来
Class users=Class.forName("com.aaa.service.UserService");
Object o = users.newInstance();
//获取方法 Method
Method login = users.getDeclaredMethod("login", String.class, String.class);
//调用方法
/*
* 调用方法 有几个要素?
* 要素一:对象
* 要素二:方法名
* 要素三:实参列表
* 要素四:返回值
* */
//invoke 调用
Object invoke = login.invoke(o, "admin", "admin");
System.out.println(invoke);
}
}
使用属性文件来动态的调用
className=com.aaa.service.UserService
name=admin
password=admin
package com.aaa.reflex;
import java.lang.reflect.Method;
import java.util.ResourceBundle;
/*
* 反射机制调用方法
* */
public class ReflectMethodTest04 {
public static void main(String[] args) throws Exception{
//资源绑定器,只能绑定xx.properties 属性文件
ResourceBundle resourceBundle=ResourceBundle.getBundle("classinfo");
String className = resourceBundle.getString("className");
Class users= Class.forName(className);
//实例化UserService
Object o = users.newInstance();
//获取到方法
//第一个参数填写方法名,第二个是可变长参数 填写形参的class类型
Method login = users.getDeclaredMethod("login", String.class, String.class);
//调用方法
//login方法在o这个对像中,login方法有两个实参列表
Object invoke = login.invoke(o, resourceBundle.getString("name"), resourceBundle.getString("password"));
System.out.println(invoke);
}
}
//这样写的好处是不需要修改源代码,只需要修改属性文件就可以做到动态的修改
反射Constructor
package com.aaa.reflex;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
/*
* 反射机制之构造
* Reflect Constructor
*
* */
public class ReflectConstructor {
public static void main(String[] args) throws Exception {
Class student=Class.forName("com.aaa.bean.Student");
//实例化对象
Object o = student.newInstance();
Constructor[] declaredConstructors = student.getDeclaredConstructors();
//类中构造方法的个数
System.out.println("构造方法的个数:"+declaredConstructors.length);
for (Constructor declaredConstructor : declaredConstructors) {
//获取构造方法的访问修饰符
String modifier = Modifier.toString(declaredConstructor.getModifiers());
System.out.println("访问修饰符:"+modifier);
//获取构造的名称
String name = student.getSimpleName();
System.out.println("构造方法的方法名:"+name);
Class[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println("参数的类型:"+parameterType.getSimpleName());
}
}
}
}
反编译Constructor(构造)
package com.aaa.reflex;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
* 反编译Constructor
* */
public class ReflectConstructorTest03 {
public static void main(String[] args) throws Exception {
Class student=Class.forName("com.aaa.bean.Student");
StringBuilder a=new StringBuilder();
//访问修饰符
String modifier = Modifier.toString(student.getModifiers());
a.append(modifier+" class "+student.getSimpleName()+"{\n");
//拼接中间部分
//拼接属性
Field[] fields = student.getDeclaredFields();
for (Field field : fields) {
a.append("\t");
a.append(Modifier.toString(field.getModifiers()));
a.append(" ");
a.append(field.getType().getSimpleName());
a.append(" ");
a.append(field.getName());
a.append(";\n");
}
//拼接构造方法
Constructor[] constructor = student.getDeclaredConstructors();
for (Constructor constructor1 : constructor) {
a.append("\t");
a.append(Modifier.toString(constructor1.getModifiers()));
a.append(" ");
a.append(student.getSimpleName());
a.append("(");
//拼接参数
Class[] parameterTypes = constructor1.getParameterTypes();
for (Class parameterType : parameterTypes) {
a.append(parameterType.getSimpleName());
a.append(",");
}
//删除最后下标位置上的字符
if (parameterTypes.length>0) {
a.deleteCharAt(a.length()-1);
}
a.append("){\n");
a.append("\t}\n");
}
a.append("\n }");
System.out.println(a);
}
}
反射机制调用Constructor
package com.aaa.reflex;
import com.aaa.bean.Student;
import java.lang.reflect.Constructor;
/*
* 通过反射机制调用构造方法
*
* */
public class ReflectConstructorTest05 {
public static void main(String[] args) throws Exception {
Class student=Class.forName("com.aaa.bean.Student");
Object o = student.newInstance();
//获取到这个有参数的构造方法。
Constructor constructor = student.getDeclaredConstructor(int.class,
String.class, double.class, int.class);
//调用构造方法new对象
Object admin = constructor.newInstance(11, "admin", 10, 12);
System.out.println(admin);
}
}
获取父类和父接口
package com.aaa.reflex;
import java.lang.reflect.AnnotatedType;
/*
* 给你一个类如何获取这个类的父类以及这个类实现了哪些接口
*
* */
public class ReflectTest06 {
public static void main(String[] args) throws Exception{
Class c=Class.forName("java.lang.String");
//获取这个类的父类
Class superclass = c.getSuperclass();
//获取父类的类型
System.out.println(superclass.getName());
//获取这个类的父接口
Class[] interfaces = c.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface);
}
}
}