反射讲解
概念:
在java程序运行状态中,类对象(class对象)可以动态获取类的相关信息,以及动态调用类的属性和方法
优缺点
反射的优缺点
优点
增加程序的灵活性,避免固有逻辑写死到程序中
代码相对简洁,可以提高程序的复用性
缺点
相比于直接调用反射有比较大的性能销毁
内部暴露和安全隐患
另外反射对性能会有损耗,这是为什么呢?
每次newInstance都会做安全检查 比较耗时
基本操作
获取类对象的四种方式// 获取类对象的四种方式
Class clazz1 = User.class;
Class<?> clazz2 = Class.forName(“com.gupao.edu.fs.User”);
Class<? extends User> clazz3 = new User().getClass();
Class<?> clazz4 = Demo03.class.getClassLoader().loadClass(“com.gupao.edu.fs.User”);
基本信息操作
获取类的相关结构
System.out.println(clazz1.getModifiers()); // 获取类的修饰符
System.out.println(clazz1.getPackage());
System.out.println(clazz1.getName());
System.out.println(clazz1.getSuperclass());
System.out.println(clazz1.getClassLoader());
System.out.println(clazz1.getSimpleName());
System.out.println(clazz1.getInterfaces().length); // 获取类似实现的所有的接口
System.out.println(clazz1.getAnnotations().length);
字段的操作
public static void main(String[] args) throws Exception {
Class userClass = User.class;
// 获取User对象
User user = userClass.newInstance();
// 获取类型中定义的字段 共有的字段以及父类中共有的字段
Field[] fields1 = userClass.getFields();
for(Field f:fields1){
System.out.println(f.getModifiers() + " " + f.getName());
}
System.out.println("--------------------");
// 可以获取私有的字段 只能够获取当前类中
Field[] fields2 = userClass.getDeclaredFields();
for(Field f:fields2){
System.out.println(f.getModifiers() + " " + f.getName());
}
// 获取name字段对应的Field
Field nameField = userClass.getDeclaredField(“name”);
// 如果要修改私有属性信息那么我们需要放开权限
nameField.setAccessible(true);
nameField.set(user,“test”);
System.out.println(user.getName());
// 如果对静态属性赋值
Field addressField = userClass.getDeclaredField(“address”);
addressField.set(null,“汪汪汪”);
System.out.println(User.address);
}
类中的方法操作
public static void main(String[] args) throws Exception {
User user = new User();
Class userClass = User.class;
// 可以获取当前类及其父类中的所有的共有的方法
Method[] methods = userClass.getMethods();
for (Method m : methods) {
System.out.println(m.getModifiers() + " " + m.getName());
}
System.out.println("**********");
// 获取本类中的所有的方法 包括私有的
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method m:declaredMethods){
System.out.println(m.getModifiers() + " " + m.getName());
}
Method jumpMethod = userClass.getDeclaredMethod(“jump”);
// 放开私有方法的调用
jumpMethod.setAccessible(true);
jumpMethod.invoke(user);
Method sayMethod = userClass.getDeclaredMethod(“say”, String.class);
// 静态方法调用
sayMethod.invoke(null,“111”);
}
构造器的操作
public static void main(String[] args) throws Exception {
Class userClass = User.class;
// 获取所有的公有的构造器
Constructor<?>[] constructors = userClass.getConstructors();
for (Constructor c:constructors){
System.out.println(c.getModifiers() + " " + c.getName() );
}
System.out.println("************************");
// 获取所有的构造器
Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor c:declaredConstructors){
System.out.println(c.getModifiers() + " " + c.getName() );
}
// 1.直接通过newInstance创建对象
User user = userClass.newInstance();
// 2.获取对应的Construcator对象获取实例
Constructor declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
// 私有的构造器调用需要放开权限
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor.newInstance(“gupao”,“男”));
}
解决反射单例的漏洞
产生的原因是:反射可以调用私有的构造器造成的
怎么解决呢?
我们在私有构造器加逻辑代码,逻辑就是第一次调用正常创建,后面在调用私有构造器就会扔出运行时异常
public class SingleTest {
private static SingleTest singleTest;
public static Boolean flag=true;
private SingleTest() {
//第一次调用
if(flag==true){
}else {
throw new RuntimeException("111111");
}
flag=false;
}
public static SingleTest getInstance(){
if(singleTest==null){
singleTest=new SingleTest();
}
return singleTest;
}
}