• Class类与反射破坏了java的封装吗?


    声明:本文摘抄自:https://www.cnblogs.com/codespoon/p/13299568.html

    1.Class类与反射,反射破坏了封装吗?

      举个例子,把代码过程看作去一个目标地点,普通代码调用呢就是事先知道经纬度,然后你坐直升机直接就到了;而通过反射呢就像不知道具体的地点,只知道先去一个地点,然后前往下一个地点,一步步到达目标。这两种方法殊途同归,反射因为要“寻路”,所以会慢一些,但在找到目标地点后和直接调用是一样的。

      有时候我们需要在程序中创建新的对象或是调用一个方法,而对应的细节我们事先并不知道,也就是说要在运行中动态地获得类的信息和调用方法。下面介绍如何利用反射来实现。

    2.Class类:保存和类有关的信息的类

      2.1需要了解的概念

        RTTI(RunTime Type Information,运行时类型信息)能够在程序运行时发现和使用类型信息

        Class对象就保存着运行时类型信息RTTI,表示一个特定类的属性

        Class类实际上表示的是一个泛型类Class<?>

        当编译一个新类时JVM会调用类加载器把这个类加载到内存中

          类加载器首先会检查这个类的 Class 对象是否已经加载,如果尚未加载,默认的类加载器就会根据类名查找 .class 文件

          一旦某个类的 Class 对象被载入内存,它就可以用来创建这个类的所有对象

        JVM为每个类型管理一个Class对象

      利用Class类得到类的信息和实例化一个类.

        Class.getName()方法

          返回类的名字,如果类在一个包中还会加上包名

          使用getSimpleName()得到不带包名的类名

        Class.forName(String className)方法

          获得className类名对应的Class对象

        Object.newInstance()方法

          可以用来动态地创建一个类的实例

          方法调用类的默认构造器(没有参数的构造器),如果没有默认构造器,就会抛出一个异常

          如果要调用带参数的构造器,使用Constructor类中的newInstance方法

      实例:  

    System.out.println("静态创建一个新的对象");
    Employee ae = new Employee();
    System.out.println(ae);
    //使用getClass.getName得到类名
    String cName = ae.getClass().getName();
    //再用forName和newInstance动态创建一个对象
    System.out.println("getClass()+forName()动态创建一个新的对象");
    Object o = Class.forName(cName).newInstance();
    System.out.println(o.getClass());//会输出实际类型Employee
    System.out.println(o);
    
    //先定义一个类名 再新建对象
    String m = "CoreJava.c5_inheritance.Manager";
    System.out.println("先定义再forName()动态创建一个新的对象");
    Object am = Class.forName(m).newInstance();
    System.out.println(am.getClass());//会输出实际类型Manager
    System.out.println(am);

      结果:

      

     3.反射:分析类的能力,相对动态地执行一些方法

      利用Field类查看任意对象的数据域名称和类型

        首先获得要分析类的Class对象getClass()/forName()

        getField(String fieldName) 和 getFileds() 能获取Class对象的对应域(getDeclared(),getDeclaredFields()获取所有已声明域,包括私有域)

        Field.getName()能获取域名称,Field.getType()能获取域类型

      实例:

    System.out.println("利用反射获得所有域");
    Manager manager = new Manager();
    Class clazz = manager.getClass();//先得到类的运行时信息
    Field[] fields = clazz.getDeclaredFields();//获得所有声明的域(包括私有域)
    for (Field f : fields)
    System.out.println(f.getType() + " " + f.getName());

      结果:

      

       获得域中的值并修改

        Field.get(Object obj)

          可以获得obj对象中用Filed对象表示的域值(设 f 是Field的一个实例,表示Manager类中的salary域,那么f.get(m)可以获得Manager实例m中salary域的值)

          如果是私有域,需要先设置可访问标志为true : fild.setAccessible(true)

        Field.set(object obj, Object newValue)

          用一个新值设置obj对象中Field对象表示的域

      示例:

    //获得域中的值并修改
    System.out.println("利用反射获得域中的值并修改");
    System.out.println("使用类方法getSalary():" + manager.getSalary());
    Field managerSalaryField = clazz.getDeclaredField("salary");//注意异常处理
    managerSalaryField.setAccessible(true);//设置可访问标志为true,访问私有域
    System.out.println("使用反射获得salary:" + managerSalaryField.get(manager));//注意异常处理
    System.out.println("使用反射修改salary");
    managerSalaryField.set(manager, 999);
    System.out.println("修改后salary:" + manager.getSalary());

      结果:

      

       利用Method类获得任意方法名称和返回值

        Class.getMethod(String methodName, Class<?>[] paramTypes) 和 Class.getMethods() 分别能获得类的对应Method对象和所有Method对象

        Method.getName()获得方法名

        Methord.getReturnType()获得方法返回类型

      示例:

    System.out.println("利用反射获得所有方法");
    Method[] methods = clazz.getMethods();
    for (Method method : methods)
        System.out.println(method.getReturnType().getSimpleName() + " " + method.getName() + " ");

      结果:

      

       调用任意方法:

        Method.invoke(Object obj, Object... params)可以调用obj对象中Method对象表示的方法,params是方法参数。对于静态方法第一个参数可以传入null

      示例:

    System.out.println("利用反射调用任意方法");
    System.out.println("修改前salary:" + manager.getSalary());
    Method setManagerSalaryMethod = clazz.getMethod("setSalary", int.class);
    setManagerSalaryMethod.invoke(manager, 222);//第一个参数为执行对象,静态方法可传入null
    System.out.println("修改后salary:" + manager.getSalary());

      结果:

      

  • 相关阅读:
    清北学堂模拟赛d6t1 角谷猜想
    清北学堂模拟赛d4t1 a
    清北学堂模拟赛d3t6 c
    清北学堂模拟赛d3t5 c
    清北学堂模拟赛d3t4 a
    清北学堂模拟赛d3t3 c
    清北学堂模拟赛d3t1 a
    清北学堂模拟赛d2t3 逆序对(pair)
    Android(java)学习笔记176: 远程服务的应用场景(移动支付案例)
    Android(java)学习笔记175:Android进程间通讯(IPC)之AIDL
  • 原文地址:https://www.cnblogs.com/wk-missQ1/p/13304329.html
Copyright © 2020-2023  润新知