zoukankan      html  css  js  c++  java
  • 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());

      结果:

      

  • 相关阅读:
    c#自动更新+安装程序的制作
    VS2013项目受源代码管理向源代码管理注册此项目时出错
    WinDbg配置和使用基础
    InstallShield Limited Edition for Visual Studio 2013 图文教程(教你如何打包.NET程序)
    PowerDesigner 如何生成数据库更新脚本
    用户故事(User Story)
    Troubleshooting Record and Playback issues in Coded UI Test
    Coded UI
    compare two oracle database schemas
    How to: Use Schema Compare to Compare Different Database Definitions
  • 原文地址:https://www.cnblogs.com/wk-missQ1/p/13304329.html
Copyright © 2011-2022 走看看