zoukankan      html  css  js  c++  java
  • 反射

    1.反射机制介绍_Class 对象获取

    1.1 反射机制是 Java 的动态性之一

    动态语言:在程序运行时,可以改变程序的结构或变量的类型。

    举例:JavaScript

     Java 代码

    典型的动态语言”Python、ruby、JavaScrip

    •        C,C++,Java 不是动态语言,但具有一定的动态性,可以称为”准动态语言”,具备类似动态语言的特性。传一块代码来动态的执行,动态的处理,Java 也能做,可以利用反射来实现类似的功能。Java的动态性让编程变得更加的灵活,功能就更加的强大。

    1.2 反射机制


    程序在运行的过程中加载一些“只知道相关名字”的类,以下代码,在程序运行时加载 User 类。

    一个类被加载后,JVM 会创建一个对应类的 Class 对象,
    类的整个结构信息会被放到 Class 对象中。
    这个 Class 对象就像镜子一样,通过这面镜子,可以得到
    对应类的全部信息

    1.3 反射机制的常见作用

    • 1) 动态的加载类、动态的获取类的信息(属性,方法,构造
    • 器)
    • 2) 动态构造对象
    • 3) 动态调用类和对象的任意方法、构造器
    • 4) 动态调用和处理属性
    • 5) 获取泛型信息
    • 6) 处理注解

    1.4 获取 Class 对象的方式

    • 1) 通过字节码文件
    • 2) 对象的 getClass()方法
    • 3) Class 类的静态方法 forName(….)
    package com.bjsxt.entity;
    
    public class User {
        //类的属性
        private int userId;
        private String userName;
        private String password;
        //公有的取值,赋值方法
        public int getUserId() {
            return userId;
        }
        public void setUserId(int userId) {
            this.userId = userId;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        //构造方法
        public User() {
            // TODO Auto-generated constructor stub
        }
        public User(int userId, String userName, String password) {
            super();
            this.userId = userId;
            this.userName = userName;
            this.password = password;
        }
        
        
    }
    View Code
    package com.bjsxt.test;
    
    import com.bjsxt.entity.User;
    
    public class Test {
        public static void main(String[] args) throws ClassNotFoundException {
            System.out.println(int.class);
            System.out.println(void.class);
            int []arrA=new int[10];
            int[] arrB=new int[30];
            /**维数相同和类型相同的数组共享同一个Class对象*/
            System.out.println(arrA.getClass()==arrB.getClass());
            
            /**同一个类的N多对象,共享同一个Class对象*/
            User u1=new User();
            User u2=new User();
            System.out.println(u1.getClass()==u2.getClass());
            
            
            /**获取Class对象的三种方式*/
            //(1)通过对象的getClass()方法获取
            Class c1=u1.getClass();
            //(2)通过字节码文件获取
            Class c2=User.class;
            //(3)通过Class类的静态方法获取
            Class c3=Class.forName("com.bjsxt.entity.User");
            
            System.out.println((c1==c2)+"	"+(c1==c3));
            
            
        }
    }
    View Code

    2.反射机制动态操作_方法_属性_构造器

    2.1 获取类的名字

    2.2 获得类的属性

    公共的指的是public类型的

    2.3 获得类的方法

     

    2.4 获得构造方法

        

    JAVA 反射机制中,Field的getModifiers()方法返回int类型值表示该字段的修饰符。

    其中,该修饰符是java.lang.reflect.Modifier的静态属性。

    对应表如下:

    PUBLIC: 1
    PRIVATE: 2
    PROTECTED: 4
    STATIC: 8
    FINAL: 16
    SYNCHRONIZED: 32
    VOLATILE: 64
    TRANSIENT: 128
    NATIVE: 256
    INTERFACE: 512
    ABSTRACT: 1024
    STRICT: 2048

    2.5 动态的操作属性、方法、构造方法

    package reflect;
    
    public class User {
        //类的属性
        private int userId;
        private String userName;
        private String password;
        //公有的取值,赋值方法
        public int getUserId() {
            return userId;
        }
        public void setUserId(int userId) {
            this.userId = userId;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        //构造方法
        public User() {
            // TODO Auto-generated constructor stub
        }
        public User(int userId, String userName, String password) {
            super();
            this.userId = userId;
            this.userName = userName;
            this.password = password;
        }
        
        
    }
    View Code
    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class Test {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException {
            String path="reflect.User";
            //(1)获取类的名称
            Class c=Class.forName(path);
            System.out.println("类的全名称:"+c.getName());
            System.out.println("类的名称:"+c.getSimpleName());
            //(2)获取父类的class对象
            Class cSuper=c.getSuperclass();
            System.out.println(cSuper.getName());
            System.out.println(cSuper.getSimpleName());
            //获取类的属性信息
            //Field f=c.getField("userId");//只能获取公共属性
            //System.out.println(f);
            Field[] fields=c.getFields();//只能获取公共属性
            System.out.println(fields.length);
            
            Field[] fields2=c.getDeclaredFields();
            //System.out.println(fields2.length);
             for (Field field : fields2) {
                //System.out.println(field);//调用了tostring方法
                System.out.println(field.getModifiers()+"	"+field.getType()+"	"+field.getName());
                        
                
                
            }
            //获取类的方法信息
             Method[] methods=c.getDeclaredMethods();//本类中的公共方法对象
             System.out.println(methods.length);
             for(Method method:methods){
                 //System.out.println(method);
                 System.out.println("访问权限:"+method.getModifiers());
                 System.out.println("返回值类型:"+method.getReturnType());
                 System.out.println("方法的名称:"+method.getName());
                 //方法的参数
                 Class<?>[] cPara = method.getParameterTypes();
                 for (Class c1 : cPara) {
                    System.out.println(c1.getTypeName()+"	");
                }
                 System.out.println("
    -----------");
                 
             }
             
            //获取类的构造器
             Constructor[] cons = c.getConstructors();
             for(Constructor constructor:cons){
                 System.out.println(constructor);
             }
             //获取指定的构造方法
             Constructor con = c.getConstructor(null);
             
             System.out.println(con);
             Constructor con2=c.getConstructor(int.class,String.class,String.class);
             System.out.println(con2);
             
             
        }
    }
    View Code
    package reflect;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Test2 {
      public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
        //获取class类的对象
          Class c=Class.forName("reflect.User");
          //(1)得到无参构造方法的对象
          Constructor cons = c.getConstructor(null);
          //通过无参构造方法的对象,创建User类的对象
        User user =(User) cons.newInstance();
          
        
        //(2)动态操作属性
        Field field=c.getDeclaredField("userId");
        field.setAccessible(true);//这个属性不需要做安全检查了,可以直接访问
        field.set(user, 1001);
        System.out.println("取出userid这个属性的值"+field.get(user));//通过反射直接取值
        
        //(3)动态操作方法
        Method m = c.getDeclaredMethod("setUserName", String.class);
        //执行setUserName这个方法
          m.invoke(user, "张三");
          Method m2=c.getDeclaredMethod("getUserName", null);
          System.out.println(m2.invoke(user));
          
    }
    }
    View Code

    3.提高反射效率

    • 反射机制对程序的运行在性能上有一定的影响,速度慢

    3.1 如何提高反射的性能

    1) 通过 setAccessible 提高性能

    • a) setAccessible 启用和禁用访问安全检查的开关,值为true 则指示反射的对象在使用时应该取消 Java 语言访问检查,值为 false 则指示反射的对象不实施 Java 语言访问检查,并不是为 true 就能访问为 false 就不能访问
    • b) 禁止安全检查,可以提高反射的运行速度
    package reflect;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class TestAccessbile {
    
        public static void test01(){
            //User u=new User();
            Object obj=new Object();
            long startTime=System.currentTimeMillis();
            for (int i = 0; i < 1000000000; i++) {
                obj.hashCode();
            }
            long endTime=System.currentTimeMillis();
            System.out.println("调用普通方法,循环执行一亿次"+(endTime-startTime)+"ms");
        }
        public static void test02() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
            Object obj=new Object();
            Class c=obj.getClass();
            //获取指定的方法
            Method m=c.getDeclaredMethod("hashCode",null);
            long startTime=System.currentTimeMillis();
            for(int i=0;i<1000000000;i++){
                //执行这个方法
                m.invoke(obj, null);
                
            }
            long endTime=System.currentTimeMillis();
            System.out.println("调用反射,循环执行一亿次"+(endTime-startTime)+"ms");
        }
        public static void test03() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
            Object obj=new Object();
            Class c=obj.getClass();
            //获取指定的方法
            Method m=c.getDeclaredMethod("hashCode",null);
            m.setAccessible(true);//不执行安全检查
            long startTime=System.currentTimeMillis();
            for(int i=0;i<1000000000;i++){
                //执行这个方法
                m.invoke(obj, null);
                
            }
            long endTime=System.currentTimeMillis();
            System.out.println("调用反射,不启用安全检查循环执行一亿次"+(endTime-startTime)+"ms");
        }
        public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
            test01();
            test02();
            test03();
        }
    
    }
    View Code

    4.反射操作泛型

    4.1 泛型

          Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换的麻烦,但是一旦编译完成,所有与泛型有关的类型全部擦除。使用泛型直接读取泛型,是读取不到的,因为反射是操作加载以后的类的。

    4.2Java 新增的数据类型

    为了通过反射操作这些类型以迎合实际开发的需要

    • 1) ParameterizedType: 表 示 一 种 参 数 化 的 类 型 ,比 如Collection<String>,可以获取 String 信息
    • 2) GenericArrayType:泛型数组类型
    • 3) TypeVariable:各种类型变量的公共父接口
    • 4) WildcardType:代表一种通配符类型表达式,比如? extends Number,? super Integer(Wildcard 是一个单词,就是通配符)
      • package com.bjsxt.entity;
        
        public class User {
        
        }
        View Code
        package com.bjsxt.generice;
        
        import java.lang.reflect.InvocationTargetException;
        import java.lang.reflect.Method;
        import java.util.ArrayList;
        import java.util.List;
        
        public class Test {
            public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
                List<String> alist=new ArrayList<String>();
                Class c=alist.getClass();//得到Class对象
                Method m=c.getDeclaredMethod("add", Object.class);
                //执行添加方法
                m.invoke(alist, 123);
                //输出集合中元素的个数
                System.out.println(alist.size());
                
            }
        }
        View Code
        package com.bjsxt.generice;
        
        import java.lang.reflect.Method;
        import java.lang.reflect.ParameterizedType;
        import java.lang.reflect.Type;
        import java.util.List;
        import java.util.Map;
        
        import com.bjsxt.entity.User;
        
        public class TestGeneric {
            public void test01(Map<String,User> map,List<User> list,String s){
                System.out.println("TestGeneric.test01()");
            }
            public Map<Integer,User> test02(){
                System.out.println("TestGeneric.test02()");
                return null;
            }
            public String test03(){
                System.out.println("TestGeneric.test03()");
                return null;
            }
            public static void main(String[] args) throws NoSuchMethodException, SecurityException {
                //获取test01方法的泛型参数信息
                Class c=TestGeneric.class;
                Method test01=c.getMethod("test01", Map.class,List.class,String.class);
                
                //获取带泛型参数的类型
                Type [] tytes=test01.getGenericParameterTypes();
                System.out.println(tytes.length);
                for (Type type : tytes) {
                    //System.out.println("#"+type);
                    if (type instanceof ParameterizedType) {
                        Type[] genericType= ((ParameterizedType) type).getActualTypeArguments();
                        //遍历每一个泛型参数中泛型的类型  
                        for (Type genType : genericType) {
                            System.out.println("泛型类型:"+genType);
                        }
                        System.out.println("
        --------------------------");
                    }
                }
                
                System.out.println("
        ----------------------------
        ");
                //获取test02方法返回值的泛型信息
                Method m2=c.getMethod("test02", null);
                Type returnType=m2.getGenericReturnType();
                //判断是否带有泛型
                if(returnType instanceof ParameterizedType){
                    Type [] types=((ParameterizedType) returnType).getActualTypeArguments();
                    for (Type type : types) {
                        System.out.println("返回值的泛型类型:"+type);
                    }
                }
                
                System.out.println("
        ------------------------------
        ");
                Method m3=c.getMethod("test03", null);
                Type returnType3=m3.getGenericReturnType();
                //System.out.println(returnType3);
                System.out.println(returnType3 instanceof ParameterizedType);
            }
            
        }
        View Code

    5.注解

    5.1 注解的作用

    • 1) 不是程序本身,可以对程序作出解释。(这一点跟注释没什么区别)
    • 2) 可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别,如果没有注解信息处理流程,则注解毫无意义)


    5.2 注解的格式

    • 1) 注解是以”@注释名”在代码中存在,还可以添加一些参数值,例如@SuppressWarnings(value=”unchecked”)。


    5.3 注解在哪里使用

    • 1) 可以附加在 package,class,method,field 等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元素的访问。


    5.4 内置的注解

    • 1) @Override :标识方法是重写的方法
    • 2) @Deprecated :标识的方法不建议使用
    • 3) @SuppressWarnings:用来抑制编译时的警告信息
    • @SuppressWarinings 需要提供参数才能正常使用,这些参数都是已经定义好的,我们只需要选择就可以了。

    举例:

    • @SuppressWarnings("unchecked")
    • @SuppressWarnings(value={"unchecked","deprecation"}
    • package com.bjsxt.annotation;
      
      import java.util.ArrayList;
      import java.util.Date;
      import java.util.List;
      
      public class TestAnnotation {
          @Override
          public String toString() {
              // TODO Auto-generated method stub
              return super.toString();
          }
          
          @Deprecated
          public void show(){ 
              Date d=new Date();
              System.out.println(d.getYear());
          }
          @SuppressWarnings("all")
          public void method(){
              List list=new ArrayList();
          }
          @SuppressWarnings(value={"unchecked","path"})
          public static void main(String[] args) {
              new TestAnnotation().show();
          }
      }
      View Code

    6.自定义注解

    6.1 自定义注解的语法

    使 用 @interface 定 义 自 定 义 注 解 时 , 自 动 继 承 了java.lang.annotation.Annotation 接口

    • 1) @interface 用来声明一个注解
    • 2) 其中的每一个方法实际上是声明了一个配置参数

    • a) 方法的名称就是参数的名称
    • b) 返回值类型就是参数类型(返回值类型只能是基本类型、Class、String、enum)
    • c) 可以通过 default 来声明参数的默认值
    • d) 如果只有一个成员,一般参数名为 value

    注意事项:注解元素必须要有值。我们定义注解元素时,经
    常使用空字符串,0 作为默认值。
    也经常使用负数(比如-1)表示不存在的含义

    6.2 元注解


    元注解的作用就是负责注解其他注解。在 Java 中定义了 4
    个标准的 meta-annotation 类型,它们被用来提供对其它
    annotation 类型作说明
    这些类型和它们所支持的类在 java.lang.annotation 包中可
    以找到

    • 1) @Target
    • 2) @Retention
    • 3) @Documented
    • 4) @Inherited

    6.3 @Target


    作用:用于描述注解的使用范围(即被描述的注解可以用在什
    么地方)

    举例:
    @Target(value=ElementType.TYPE)

    6.4 @Retention


    作用:表示需要在什么级别保存该注解信息,用于描述注解的
    生命周期

    package com.bjsxt.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
            String stuName() default "";
            int age() default 0;
            String [] school () default {"清华大学","北京大学"};
    }
    View Code
    package com.bjsxt.annotation;
    
    //@MyAnnotation 该注解只能应用到方法上
    //@MyAnnotation2(value="aaaa")
    @MyAnnotation2("aaa")
    public class Test {
        @MyAnnotation(stuName="张小三")
        public void show(){
            
        }
        @MyAnnotation(stuName="王一一",age=23,school={"北京交通大学","北京广播学院"})
        public void method(){
            
        }
    }
    View Code
    package com.bjsxt.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation2 {
        String value();
    }
    View Code

    7.反射读取注解信息

    7.1ORM (Object Relationship Mapping)

    ORM:对象关系映射

    • 1) 类与表结构对应
    • 2) 属性和字段对应
    • 3) 对象和记录对应

    使用注解完成类和表结构的映射关系


    7.2 功能描述

    将Java中的Student类使用第三方程序通过读取注解生成数据库中的表

    7.3 实现步骤

    • 1) 编写 Student 类
    • 2) 编写注解
    • 3) 在类中使用注解
    • 4) 通过解析程序将注解读取出来 (通过框架解析)
    • 5) 拼接 SQL 语句,使用 JDBC 到数据库中执行创建表
    • package com.bjsxt.entity;
      
      import com.bjsxt.annotation.SxtField;
      import com.bjsxt.annotation.SxtTable;
      
      @SxtTable("tb_student")
      public class Student {
          //私有属性
          @SxtField(columnName="id",type="int",length=10)
          private int id;
          
          @SxtField(columnName="stuname",type="varchar",length=20)
          private String stuName;
          
          @SxtField(columnName="age",type="int",length=10)
          private int age;
          
          
          public int getId() {
              return id;
          }
          public void setId(int id) {
              this.id = id;
          }
          public String getStuName() {
              return stuName;
          }
          public void setStuName(String stuName) {
              this.stuName = stuName;
          }
          public int getAge() {
              return age;
          }
          public void setAge(int age) {
              this.age = age;
          }
          public Student(int id, String stuName, int age) {
              super();
              this.id = id;
              this.stuName = stuName;
              this.age = age;
          }
          public Student() {
              super();
          }
          
      }
      View Code
      package com.bjsxt.annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface SxtField {//属性的注解
          String columnName(); //数据库中列的名称
          String type();  //数据库中列的类型
          int length();   //类型的长度
      }
      View Code
      package com.bjsxt.annotation;
      
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
      
      @Target(ElementType.TYPE) //注解的使用范围
      @Retention(RetentionPolicy.RUNTIME) //在运行时起作用
      public @interface SxtTable {
          String value();
      }
      View Code
      package com.bjsxt.annotation.test;
      
      import java.lang.annotation.Annotation;
      import java.lang.reflect.Field;
      
      import com.bjsxt.annotation.SxtField;
      import com.bjsxt.annotation.SxtTable;
      
      public class Test {
          public static void main(String[] args) throws Exception {
              //(1)创建Student类的Class对象
              Class clazz=Class.forName("com.bjsxt.entity.Student");
              //(2)得到Student类的所有注解
              Annotation [] annotations=clazz.getDeclaredAnnotations();
              for (Annotation a : annotations) {
                  System.out.println(a);
              }
              System.out.println("
      ----------------------------");
              //(3)获取指定的注解
              SxtTable st=(SxtTable) clazz.getDeclaredAnnotation(SxtTable.class);
              System.out.println(st);
              System.out.println("
      ----------------------------");
              
              //(4)获取属性的注解
          
              Field field=clazz.getDeclaredField("stuName");
              SxtField sf=field.getDeclaredAnnotation(SxtField.class);
              System.out.println(sf.columnName()+"--"+sf.type()+"--"+sf.length());
              
              /**拼接SQL语句  DDL ,使用JDBC在数据库中执行,创建出了一张表,tb_student,表中的列就为id,stuname,age*/
              
          }
      }
      View Code
  • 相关阅读:
    android.os.NetworkOnMainThreadException的解决方案
    一些LinuxC的小知识点(一)
    一些LinuxC的小知识点(二)
    <assert.h>库学习
    <string.h>的学习
    Java异常的中断和恢复
    Java Collection或Map的同步
    Java经典实例:按字符颠倒字符串
    Java 经典实例: Unicode字符和String之间的转换
    Java经典实例:处理单个字符串
  • 原文地址:https://www.cnblogs.com/wq-9/p/10382791.html
Copyright © 2011-2022 走看看