zoukankan      html  css  js  c++  java
  • 反射机制总结篇

    反射

    ​   反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状 态或行为的一种能力, 并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和 相关的语义。Java 中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在 运行时装配,无需在组件之间进行源代码链接。反射允许我们在写与执行时,使我们的程序 代码能够接入装载到 JVM 中的类的内部信息,而不是源代码中选定的类协作的代码。这使反 射成为构建灵活的应用的主要工具。

    ​ 但需注意的是:如果使用不当,反射的成本很高。

    一:JAVA中的类反射

    ​ Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查, 或者说“自审”或“自省”,并能直接操作程序的内部属性。

     

    二:reflection的工作机制

    ​   程序运行时,java 系统会一直对所有对象进行所谓的运行时类型识别,这项信息记录了每个对 象所属的类。通过专门的类可以访问这些信息。用来保存这些信息的类是class 类,class 类为 编写可动态操纵的 java 代码程序提供了强大功能

      一个类在加载到内存中,就会存在一个表示当前类的Class类的对象(唯一的,不会变)

      Class对象中存在当前这个类的所有内容(属性,构造器,功能…)创建对象时,其实是拿到Class对象的镜像

      如果能够获取到表示一个类的Class对象,就可以进行各种操作…

      Class对象是反射的源头如果能够获取Class对象,就可以使用Class类的中的各种功能来操作

    构造 Class 对象有 3 种方式:

    1.Class.forName()

    try { 
    
         // 构造 Class 对象的第一种方法 
    
         Class clazz = Class.forName("java.lang.String"); 
    
         Object obj = clazz.newInstance(); 
    
         System.out.println(obj); 
    
     } catch ( ClassNotFoundException e ) { 
    
             e.printStackTrace(); 
    
     } catch (IllegalAccessException e) { 
    
             e.printStackTrace(); 
    
     } catch ( InstantiationException e) { 
    
             e.printStackTrace(); 
    
     } 

    2.类.Class

    try { 
    
     // 构造 Class 对象的第二种方法 
    
         Class stringClass = String.class; 
    
         System.out.println(stringClass); 
    
     } catch ( ClassNotFoundException e ) { 
    
             e.printStackTrace(); 
    
     } catch (IllegalAccessException e) { 
    
            e.printStackTrace(); 
    
     } catch ( InstantiationException e) { 
    
             e.printStackTrace(); 
    
     } 

    3.Object.getClass()

    try { 
    
         // 构造 Class 对象的第三种方法
    
        String s = "s"; 
    
         stringClass = s.getClass(); 
    
         System.out.println(stringClass); 
    
     } catch ( ClassNotFoundException e ) { 
        
         e.printStackTrace(); 
    
     } catch (IllegalAccessException e) { 
    
         e.printStackTrace(); 
    
     } catch ( InstantiationException e) { 
    
         e.printStackTrace();
    }

    类对象的比较:

    相同的类

    Class clazz = Class.forName("java.lang.String"); 
    
    Class stringClass = String.class; 
    
    System.out.println("字符串类对象的比较=" +(clazz == stringClass)); //true

    不同的类:

    Class stringClass = String.class; 
    
    Class intClass = int.class; 
    
    System.out.println("字 符 串类 对 象和 Int 类 对 象的 比较 =" +(stringClass ==  intClass)); //false

    三.Java反射机制可以实现的功能

    在运行时判断任意一个对象所属的类;

      ①在运行时判断任意一个对象所属的类;
      ②在运行时构造任意一个类的对象;
      ③在运行时判断任意一个类所具有的成员变量和方法;
      ④在运行时调用任意一个对象的方法;
      ⑤生成动态代理

    Class类等的使用:
      基本的常用的方法
      通过获取构造器->反射创建对象
      获取方法->调用方法
      获取属性–>操作属性

    public class ReflectDemo03 {
        public static void main(String[] args) {
            //getModifiers() 返回Java语言修饰符的类或接口,编码在一个整数。 
            Class<String> cls = String.class;
            System.out.println(cls.getModifiers());
                                                System.out.println(Modifier.toString(cls.getModifiers()));
                //String getName()  
            System.out.println(cls.getName());                      //java.lang.String
    System.out.println(cls.getSimpleName());  //String
    //getPackage() 这个类的包。 
    ​    System.out.println(cls.getPackage());
    ​    
    ​    //String getTypeName()  
    ​    System.out.println(cls.getTypeName());
        }
    
    }    
    public class RelectDemo04 {
        public static void main(String[] args) throws Exception {
            testConstructor(User.class);
        }
    /*
    - 反射获取构造器-->创建对象
    - 
    - Constructor<T> getConstructor(Class<?>... parameterTypes) 
      获取一个指定的公共额构造器对象
    
             Constructor<?>[] getConstructors()  获取所有的公共的构造器对象
             Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
                 所有权限的方法中的指定一个
             Constructor<?>[] getDeclaredConstructors()  所有的构造器
    
    ​    创建对象
    ​        1) Class类的newInstance() -->不推荐使用,默认调用空构造,没有就无法使用
    ​        2) Constructor类提供的newInstance(Object... initargs)方法创建对象,调用当前的构造器初始化信息
     */
    public static void testConstructor(Class<User> cls) throws Exception {
    ​    //获取某个指定的公共的构造器
    ​    Constructor<User> con = cls.getConstructor(int.class,String.class,String.class,String.class,Integer.TYPE);
    ​    System.out.println(con);
    ​    //所有的构造器
    ​    Constructor[] cons = cls.getDeclaredConstructors();
    ​    for(Constructor c:cons) {
    ​        System.out.println(c);
    ​    }
    ​    
    ​    //1.创建对象Class类的newInstance()
    ​    User obj = cls.newInstance();
    ​    System.out.println(obj);
    ​    
    ​    //2.Constructor类提供的newInstance(Object... initargs)
    ​    User obj2 = con.newInstance(1001,"lisi","lisi123","女",18);
    ​    System.out.println(obj2);
    ​    
    ​    //私有的,可以放开权限
    ​    cons[1].setAccessible(true);
    ​    User obj3 = (User) cons[1].newInstance("liaoliao","1234");
    ​    cons[1].setAccessible(false); //关闭权限
    ​    System.out.println(obj3);
    ​    }
    }

    四.Java 反射中的主要类和方法

      软件包 java.lang.reflect

      提供类和接口,以获取关于类和对象的反射信息。

    1.Constructor 构造函数对象

    class A { 
    
     public A() { 
    
      
    
     } 
    
     public A( String s ) { 
    
      
    
    } 
    
    }
    
    … 
    
    A a = new A(); 
    
    Class aClass = a.getClass(); 
    
    //得到类对象的所有公共的构造函数对象 
    
    Constructor[] constructors =     aClass.getConstructors(); 
    
    // 得到类对象特定的公共构造函数对象 
    
    Constructor c = aClass.getConstructor(String.class); 
    
    // 获取全部声明的构造方法 
    
    Constructor[] c1 = aClass.getDeclaredConstructors(); 
    
         for ( Constructor c1 : constructors ) { 
    
     System.out.println( "构造方法的名称=" + c1.getName() ); 
    
         System.out.println( " 构造方法的修饰符 =" +  
    
        Modifier.toString(c1.getModifiers()) ); 
    
         Class[] clazz1 = c1.getParameterTypes(); 
    
         for ( Class cs : clazz1 ) { 
    
             System.out.println("参数类型:"+cs.getName()); 
    
     } 
    
     }

    2.Method获取所有方法

    Method[] ms = aClass.**getDeclaredMethods**(); 
    
     for ( Method ms1 : ms ) { 
    
             System.out.println(); 
    
     System.out.println( "方法的名称=" + ms1.getName() ); 
    
             System.out.println( "方法的修饰符=" + ms1.getModifiers() + ":"  
    
    + Modifier.toString(ms1.getModifiers()) ); 
    
             System.out.println( " 方 法 的 修 饰 符 是 否 为 public=" +  
    
        Modifier.isPublic(ms1.getModifiers()) ); 
    
         Class[] clazz1 = ms1.getParameterTypes(); 
    
         for ( Class cs : clazz1 ) { 
    
     System.out.println("参数类型:"+cs.getName()); 
    
     } 
    
             System.out.println( "方法是否带有可变数量的参数=" +  ms1.isVarArgs() ); 
    
             System.out.println( " 方 法 的 返 回 类 型 : 
    
    "+ms1.getReturnType().getName()); 
    
     } 

    3.Field获取所有属性

    Field[] f = aClass.getDeclaredFields(); 
    
             B b = new B(); 
    
     for ( Field f1 : f ) { 
    
             System.out.println(); 
    
             System.out.println( "变量的名称=" + f1.getName() ); 
    
             System.out.println( " 变量的修饰符 =" +  
    
    Modifier.toString(f1.getModifiers()) ); 
    
             System.out.println( "变量的类型=" + f1.getType().getName() ); 
    
             System.out.println( "变量的值=" + f1.get(b) ); 
    
     }

    4、Class

    Class[] classes = aClass.getInterfaces(); 
    
         for ( Class c3 : classes ) { 
    
             System.out.println("接口名称:" + c3.getName()); 
    
     } 
    
         // 获取类对象的父类 
    
         Class c4 = aClass.getSuperclass(); 
    
             System.out.println("父类名称:" + c4); 
    
         // 获取类对象的包对象 
    
     String pName = String.class.getPackage().getName(); 
    
             System.out.println("String 所在的包名称:" + pName); 
    
             System.out.println("aClass 是否为接口:" + aClass.isInterface()); 
    
             System.out.println("C 是否为接口:" + C.class.isInterface()); 
    
             System.out.println("类名:" + String.class.getName()); 
    
             System.out.println("类名的简称:" + String.class.getSimpleName());

    五.实例化对象

      创建对象的方式,有new 、克隆、反序列化,再加一种,根据Class对象,使用newInstance() 或者构造器实例化对 象。

    //获取源头 
    
    Class<>clz=Class.forName("com.shsxt.ref.simple.User"); 
    
    //第一种:通过newInstance()创建对象 
    
        User user=(User)clz.newInstance(); 
    
        user.setUname("sxt"); 
    
        user.setUpwd("good"); 
    
    //第二种:通过getDeclaredConstructors()创建对象,取得全部构造函数(注意顺序) 
    
    Constructor<?>[] cons=clz.getDeclaredConstructors(); 
    
        for(Constructor<?>c:cons){ 
    
            System.out.println(c); 
    
        }
    
    //注意观察上面的输出结果,再实例化,否则参数容易出错 
    
    User u1=(User)cons[0].newInstance("shsxt","good"); 
    
    User u2=(User)cons[1].newInstance("sxt"); 
    
    User u3=(User)cons[2].newInstance(); 
    
    System.out.println(u1.getUname()+u1.getUpwd()); 

    注意:newInstance()调用空构造,如果空构造不存在,会出现异常。由此可知,使用其他构造器创建对象比较

    麻烦,使用空构造非常简单。确保空构造存在

    六.父类与接口

    Class<>clz=Class.forName("com.shsxt.ref.simple.User"); 
    
    //获取所有接口 
    
    Class<?>[] inters=clz.getInterfaces(); 
    
        for(Class<?> in:inters){ 
    
        System.out.println(in.getName()); 
    
        }
    
        //获取父类 
    
        Class<?> cls=clz.getSuperclass(); 
        
    System.out.println("继承的父类为:"+cls.getName());
  • 相关阅读:
    Map接口框架图
    Collection接口框架图
    Java集合框架源码(四)——Vector
    Java集合框架源码(三)——arrayList
    HashSet与HashMap的区别
    Java集合框架源码(二)——hashSet
    hashMap与hashTable的区别
    HashMap与ConcurrentHashMap的区别
    asp.net 项目Net4.0 在IE10、 IE 11 下出现 “__doPostBack”未定义 的解决办法
    C# 完整List例子
  • 原文地址:https://www.cnblogs.com/instead-everyone/p/13619849.html
Copyright © 2011-2022 走看看