反射

作者: 我是许仙 | 来源:发表于2020-09-08 21:13 被阅读0次

定义

动态获取类的内容与动态调用对象的属性和方法和属性的机制,叫做反射。在java运行状态中

  1. 对于一个给定的类(class)对象,可以获取这个类的所有属性和方法。
  2. 对于一个给定的对象(new xxxObject()),可以调用它的任意一个属性和方法。
缺点 -很慢

每次newInstance都会做安全检查

获取类对象的4种方式

//new 对象获取
User user = new User();
Class<? extends User> clazz1 = user.getClass();
System.out.println(clazz1);

//通过Class提供的静态方法
try {
    Class clazz2 = Class.forName("com.javaDemo.reflection.User");
    System.out.println(clazz2);
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
//通过class文件获取
Class clazz3 = User.class;
System.out.println(clazz3);

//通过类加载器
Class class4 = ReflectionDemo.class.getClassLoader().loadClass("com.javaDemo.reflection.User");
System.out.println(class4);

获取类中的属性并赋值

定义一个属性类 与 父类
public class User  extends SuperEnty{
    public String age;
    public static String pubStaticName;

    private String userName;
    private static String priStaticName;
}
public class SuperEnty  {

    public String id;

    private String sid;
}
测试类
public class OptionTest {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        //通过反射实例化一个对象
        Class<User> userClass = User.class;
        User user = userClass.newInstance();

        //2中获取类中属性的方法的区别
        //1.
        Field[] fields = userClass.getFields();
        for (Field field : fields){
            System.out.println(field.getModifiers() + "-" + field.getName());
        }

        System.out.println("----------------");
        //2 
        Field[] declaredFields = userClass.getDeclaredFields();
        for (Field field : declaredFields){
            System.out.println(field.getModifiers() + "-" + field.getName());
        }

    }
}
返回结果
1-age
9-pubStaticName
1-id
----------------
1-age
9-pubStaticName
2-userName
10-priStaticName

Process finished with exit code 0

通过返回结果得到

  1. getFields() 获取的是本类与父类中 public修饰的属性。
  2. getDeclaredFields()获取的是本类中所有修饰的方法,但不包括父类。
那么如何获取父类中的私有属性呢

clazz.getSuperclass()获取父类的class对象,在获取属性

Class<User> clazz = User.class;
User user = clazz.newInstance();

Class superClass = clazz.getSuperclass();
Field[] fields = superClass.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

Field field = superClass.getDeclaredField("sid");
//私有属性需要强吻
field.setAccessible(true);
field.set(user,"1");

System.out.println(user.getSid());
操作静态属性

field.set()中对象设置为null就可以了

Class<User> clazz = User.class;

Field field = clazz.getDeclaredField("priStaticName");
field.setAccessible(true);
field.set(null,"testStaticName");

System.out.println(User.getPriStaticName());

操作方法

与Field一样

getMethod()获取本类与父类的共有方法

getDeclaredMethods()获取本类的所有的方法

//.vr
Class<User> userClass = User.class;
//获取父类与本类中的pub方法
Method[] methods = userClass.getMethods();
for (Method method : methods){
    System.out.println(method.getName());
}
System.out.println("-----------");
//获取本类中所有的方法
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method method : declaredMethods) {
    System.out.println(method.getName());
}
//调用私有方法
Method method = userClass.getDeclaredMethod("setPriStaticName", String.class);
method.setAccessible(true);
method.invoke(null, "testMethod");
System.out.println(User.getPriStaticName());

构造器

与上面一样

getConstructors() 只能获取本类的公共的构造器

getDeclaredConstructors() 获取本类的所有的构造器

 Class<User> userClass = User.class;
        //获取本类与父类的构造方法
        Constructor<?>[] constructors = userClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor.toString());
        }
        System.out.println("--------");
        //获取本类所有的构造方法
        Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            System.out.println(constructor.toString());
        }
        //使用
        //1. newInstance 源码就是调用的默认的null构造器创建对象
        User user = userClass.newInstance();
        //2 带参数构造器
        Constructor<User> declaredConstructor =   userClass.getDeclaredConstructor(String.class, String.class);
        declaredConstructor.setAccessible(true);
        User user1 = declaredConstructor.newInstance("test", "test");
        System.out.println(user1.toString());

public class User  extends SuperEnty{

    public User() {
    }

    private User(String age,String userName) {
        this.age = age;
        this.userName = userName;
    }

    public String age;
    public static String pubStaticName;

    private String userName;
    private static String priStaticName;


    @Override
    public String toString() {
        return "User{" +
                "age='" + age + '\'' +
                ", userName='" + userName + '\'' +
                ", id='" + id + '\'' +
                '}';
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public static String getPubStaticName() {
        return pubStaticName;
    }

    public static void setPubStaticName(String pubStaticName) {
        User.pubStaticName = pubStaticName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public static String getPriStaticName() {
        return priStaticName;
    }

    public static void setPriStaticName(String priStaticName) {
        User.priStaticName = priStaticName;
    }
}

通过反射破坏单例模式

单例模式之所以在系统中只存在一个对象,是因为构造器私有了,不能通过new的方式创建出来,只能通过暴露出来的静态方法来获取对象。但是反射是可以获取到私有构造器从而创建对象的从而破坏了单例模式全局唯一的特性。

单例模式(不考虑多线程环境)
public class SimpleTest {

    private static SimpleTest simpleTest;

    private SimpleTest() {
    }

    public static SimpleTest getInstance() {
        if (null == simpleTest) {
            return new SimpleTest();
        }
        return simpleTest;
    }
  
   //每一次都是返回同一个对象
   public static void main(String[] args) {
        SimpleTest simpleTest1 = SimpleTest.getInstance();
        SimpleTest simpleTest2 = SimpleTest.getInstance();
        SimpleTest simpleTest3 = SimpleTest.getInstance();
        System.out.println(simpleTest1);
        System.out.println(simpleTest2);
        System.out.println(simpleTest3);
    }
}
结果
com.javaDemo.reflection.SimpleTest@2503dbd3
com.javaDemo.reflection.SimpleTest@2503dbd3
com.javaDemo.reflection.SimpleTest@2503dbd3
反射获取私有构造器生成对象,从而破坏单例
System.out.println("_______________");
Class<SimpleTest> simpleTestClass = SimpleTest.class;
//获取默认的构造器
Constructor<SimpleTest> declaredConstructor = simpleTestClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
SimpleTest simpleTest = declaredConstructor.newInstance();
System.out.println(simpleTest);

如何防止反射破坏单例

private SimpleTest() {
    if (null != simpleTest) {
        throw new RuntimeException("已经存在不可以再创建");
    }
}

在私有构造器中加入判断,如果已经实例化那么不可以通过任何的方式再次调用构造器创建对象。

相关文章

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • 镜面反射矩阵的推导

    镜面反射是以镜面作为反射平面,实物与反射物到反射平面的距离相等,实物与反射物方向相反,所以,反射矩阵由反射平面确定...

  • reflect.go包学习_之二 指针操作提高反射性能 反射应用

    reflect.go包学习_之二 指针操作提高反射性能 反射应用 反射创建实例 反射信息、反射调用方法、反射修改值...

  • Java互联网公司-经典面试题附答案

    基础:Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?优点:反射具有解耦性,缺点:反射属...

  • Java反射与joor反射库的使用

    java原生反射的使用 反射构造对象 反射方法 反射字段 joor反射库的使用 github:https://gi...

  • Java反射

    什么是反射? 反射的作用? 反射性能优化?

  • 反射三定律

    反射第一定律:反射可以将interface类型变量转换成反射对象 反射第二定律:反射可以将反射对象还原成inter...

  • 反射

    1.反射是什么?反射的定义,概念 2.为什么要学反射? 3.怎么使用反射?反射的使用

  • 一周岁前做好两件事,孩子就不会语言迟缓,保证口齿伶俐

    与语言发展相关的原始反射有四个:张口反射、足跖反射、抓握反射和手拉反射,每个反射的发生、发展和整合都是次第进行的,...

  • 面试官问go反射第一弹

    目录 反射概念 reflect包 反射类型(Type)和种类(Kind) 反射类型(Type)使用 反射类型对象(...

网友评论

      本文标题:反射

      本文链接:https://www.haomeiwen.com/subject/vtnjektx.html