java基础学习笔记(七)-反射--注解

反射机制介绍 _Class 对象获取
 
  1. 反射机制是 Java 的动态性之一
    动态语言 : 在程序运行时,可以改变程序的结构或变量的类型。
    典型的动态语言 ”Python ruby JavaScripC,C++, Java 不是动态语言,但具有一定的动态性,可以称为” 准动态语言 ”, 具备类似动态语言的特性。传一块代码来动态的执行,动态的处理,Java 也能做,可以利用反射来实现类似的功能。
    Java 的动态性让编程变得更加的灵活,功能就更加的强大。
  2. 反射机制
    程序在运行的过程中加载一些“只知道相关名字”的类,
    以下代码,在程序运行时加载 User 类。
    Class c=Class.forName("com.zb.reflect.User");
    一个类被加载后, JVM 会创建一个对应类的 Class 对象,
    类的整个结构信息会被放到 Class 对象中。
    这个 Class 对象就像镜子一样,通过这面镜子,可以得到对应类的全部信息。
  3. 反射机制的常见作用
    1) 动态的加载类、动态的获取类的信息 ( 属性,方法,构造器)
    2) 动态构造对象
    3) 动态调用类和对象的任意方法、构造器
    4) 动态调用和处理属性
    5) 获取泛型信息
    6) 处理注解
  4. 获取 Class 对象的方式
    1) 通过字节码文件
    2) 对象的 getClass() 方法                                                                                                                                                            3) Class 类的静态方法 forName(….)
  5. public class Test1 {
        public static void main(String[] args) throws ClassNotFoundException {
            System.out.println(Integer.class);
            System.out.println(int.class);
            System.out.println(void.class);
            //维数相同和类型相同的数组共享同一个Class对象
            int [] array=new int[10];
            int [] array2=new int[30];
            System.out.println(array.getClass()==array2.getClass());
            //同一个类的N多对象,共享同一个Class对象
            User u1=new User();
            User u2=new User();
            System.out.println(u1.getClass()==u2.getClass());
            
            //获取Class对象的三种方法
            Class c1=u1.getClass();
            Class c2=User.class;
            Class c3=Class.forName("day07.reflect.User");
        }
    }

     


反射机制动态操作 _ 方法 _ 属性 _ 构造器
 
  1. 获取类的名字
    方法描述
    String getName()
    获得包名 + 类名
    String getSimpleName()
    获得类的名字
  2. 获得类的属性
    方法描述
    Field getField(String fieldName)
    得到公共的属性对象
    Field getDeclareField(String fieldName)
    得到指定名称的属性对象
    Field []c.getDeclaredFields()
    得到所有的属性对象
  3. 获得类的方法
    方法描述
    Method[] getDeclaredMethods()
    得到公共的方法对象
    Method[] c.getMethods()
    得到父类及本类中的公共的方法对象
    Method getDeclaredMethod(String methodName, Class …type)
    得到指定名称的本类中公共的方法
    Method getMethod(String methodName, Class type)
    得到本类或父类中的公共的方法对象
  4. 获得构造方法
    方法描述
    Constructor[] getDeclaredConstructors()
    得到公共的构造方法的对象
    Constructor [] getConstructors()
    得到公共的构造方法对象
    Constructor getDeclaredConstructor(Class...type)
    得到指定参数的公共的构造方法对象
  5. 动态的操作属性、方法、构造方法
  6. public class Test03 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
            Class c=Class.forName("day07.reflect.User");
            System.out.println(c.getName());//包名
            System.out.println(c.getSimpleName());//类名
            Class cSuper=c.getSuperclass();//得到父类
            Field [] fields1=c.getFields();//只能获取公共属性
            Field [] fields2=c.getDeclaredFields();//获取所有属性
            for(Field field:fields2){
                System.out.println(field);
                                        //访问权限             类型               方法名称
                System.out.println(field.getModifiers()+"\t"+field.getType()+"\t"+field.getName());
            }
            Method [] methods=c.getDeclaredMethods();
            for(Method m1:methods){
                System.out.println(m1);
                System.out.println(m1.getModifiers()+"\t"+m1.getReturnType()+"\t"+m1.getName());
                Class [] aPara=m1.getParameterTypes();//获取方法的参数也是Class类型
                for(Class cs:aPara){
                    System.out.println(cs.getTypeName());
                }
                Constructor [] constructors=c.getConstructors();
                c.getConstructor();//获取指定的构造方法
            }
    
    
        }
    }
    public class Test3 {
        public static void main(String[] args) throws Exception  {
            Class c= Class.forName("day07.reflect.User");
            //得到无参构造方法的对象
            Constructor con=c.getConstructor(null);
            User user=(User) con.newInstance();
            //动态操作属性
            Field field = c.getDeclaredField("userid");
            field.setAccessible(true);//这个属性不做安全检查,直接访问
            field.set(user,1001);
            System.out.println(field.get(user));
            //动态操作方法
           Method m= c.getDeclaredMethod("setUsername", String.class);
           m.invoke(user,"张三");
            Method m2= c.getDeclaredMethod("getUsername",null);
            System.out.println(m2.invoke(user));
        }
    }
    

     


提高反射效率
反射机制对程序的运行在性能上有一定的影响,速度慢
如何提高反射的性能
1) 通过 setAccessible 提高性能
a) setAccessible 启用和禁用访问安全检查的开关,值为true 则指示反射的对象在使用时应该取消 Java 语言访问检查,值为 false 则指示反射的对象不实施 Java 语言访问检查,并不是为 true 就能访问为 false 就不能访问
b) 禁止安全检查,可以提高反射的运行速度
public class Test01 {
    public static void test01(){
        Object o=new Object();
        long starttime=System.currentTimeMillis();
        for(int i=0;i<1000000000L;i++){
            o.hashCode();
        }
        long endtime=System.currentTimeMillis();
        System.out.println("普通方法执行时间为:"+(endtime-starttime));
    }
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object o=new Object();
        Class c=o.getClass();
        Method method=c.getDeclaredMethod("hashCode",null);
        long starttime=System.currentTimeMillis();
        for(int i=0;i<1000000000L;i++){
            method.invoke(o,null);
        }
        long endtime=System.currentTimeMillis();
        System.out.println("反射方法执行时间为:"+(endtime-starttime));
    }
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object o = new Object();
        Class c = o.getClass();
        Method method = c.getDeclaredMethod("hashCode", null);
        method.setAccessible(true);
        long time1 = System.currentTimeMillis();
        for(int i=0;i<1000000000L;i++) {
            method.invoke(o, null);
        }
        long time2=System.currentTimeMillis();
        System.out.println("禁用安全检查反射方法执行时间为:"+(time2-time1));
    }
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }
}

反射操作泛型
 
  1. 泛型
    Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换的麻烦,但是一旦编译完成,所有与泛型有关的类型全部擦除。使用反射直接读取泛型,是读取不到的,因为反射是操作加载以后的类的。
  2. Java 新增的数据类型
    为了通过反射操作这些类型以迎合实际开发的需要
    1) ParameterizedType : 表示一种参数化的类型 , 比 如Collection<String>,可以获取 String 信息
    2) GenericArrayType :泛型数组类型
    3) TypeVariable :各种类型变量的公共父接口
    4) WildcardType :代表一种通配符类型表达式,比如? extends Number,? super Integer(Wildcard 是一个单词,就是通配符 )
    public class Test02 {
        public void test01(Map<String,User> map,List<User> list,String s){
            System.out.println("test01");
        }
        public Map<Integer,User> test02(){
            System.out.println("test02");
            return null;
        }
        public String test03(){
            System.out.println("test03");
            return null;
        }
        public static void main(String[] args) throws NoSuchMethodException {
            //获取test01方法的泛型参数信息
            Class c1=Test02.class;
            Method test01= c1.getMethod("test01",Map.class,List.class,String.class);
            //获取泛型参数的类型
            Type[] types=test01.getGenericParameterTypes();
            System.out.println(types.length);//3
            for(Type type:types){
                //System.out.println("#"+type);
                if(type instanceof ParameterizedType){//只获取带有泛型的参数
                    Type[] g=((ParameterizedType) type).getActualTypeArguments();
                    for(Type t:g){
                        //遍历每一个泛型参数中泛型的类型
                        System.out.println(t);//class java.lang.String  class day07.reflect.User
                    }
                    System.out.println("------------");
                }
            }
            System.out.println("test02方法返回值的泛型信息");
            Method me=c1.getMethod("test02",null);
            Type returnType=me.getGenericReturnType();
            //是否带有泛型
            if(returnType instanceof ParameterizedType){
                //返回值的泛型类型
                Type[] types1=((ParameterizedType) returnType).getActualTypeArguments();
                for(Type t:types1){
                    System.out.println("返回值的泛型类型:"+t);
                }
            }
            System.out.println("test03");
            Method m=c1.getMethod("test03",null);
            Type returnType1 = m.getGenericReturnType();
            System.out.println(returnType1 instanceof ParameterizedType);
        }
    }

     


注解
 
  1. 注解的作用
    1) 不是程序本身,可以对程序作出解释。(这一点跟注释没什么区别)
    2) 可以被其他程序(比如:编译器等)读取。 ( 注解信息处理流程,是注解和注释的重大区别,如果没有注解信息处理流程,则注解毫无意义)
  2. 注解的格式
    1) 注解是以 ”@ 注释名 在代码中存在,还可以添加一些参数值,例如@SuppressWarnings(value=”unchecked”)
  3. 注解在哪里使用
    1) 可以附加在 package,class,method,field 等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程
    实现对这些元素的访问。
  4. 内置的注解
    1) @Override : 标识方法是重写的方法
    2) @Deprecated :标识的方法不建议使用
    3) @SuppressWarnings :用来抑制编译时的警告信息 @SuppressWarinings 需要提供参数才能正常使用,这些参数都是已经定义好的,我们只需要选择就可以了。

自定义注解
 
  1. 自定义注解的语法
    使 用 @interface 定义自定义注解时,自动继承了 java.lang.annotation.Annotation 接口
    1) @interface 用来声明一个注解
    2) 其中的每一个方法实际上是声明了一个配置参数
    a) 方法的名称就是参数的名称
    b) 返回值类型就是参数类型 ( 返回值类型只能是基本类型、Class String enum)
    c) 可以通过 default 来声明参数的默认值
    d) 如果只有一个成员,一般参数名为 value
    注意事项:注解元素必须要有值。我们定义注解元素时,经常使用空字符串,0 作为默认值。也经常使用负数( 比如 -1) 表示不存在的含义
  2. 元注解
    元注解的作用就是负责注解其他注解。在 Java 中定义了 4个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明这些类型和它们所支持的类在 java.lang.annotation 包中可以找到
  3. @Target
    用于描述注解的使用范围 ( 即被描述的注解可以用在什么地方)
    所修饰范围
    取值 ElementType
    package 包 PACKAGE
    PACKAGE
    类、接口、枚举、 Annotation 类型
    TYPE
    类型成员(方法、构造方法、 成员变量、枚举值)
    CONSTRUCTOR: 用于描述构造器
    CONSTRUCTOR: 用于描述构造器
    FIELD: 用于描述域
    METHOD: 用于描述方法
    方法参数和本地变量
    LOCAL_VARIABLE: 用于描述局部变量
    PARAMETER: 用于描述参数
    @Target(value=ElementType.TYPE)
  4. @Retention
    表示需要在什么级别保存该注解信息 , 用于描述注解的生命周期
    取值作用
    SOURCE
    在源文件中有效 ( 即源文件中保留)
    CLASS
    class 文件中有效 ( class保留)
    RUNTIME
    在运行时有效 ( 即运行时保留), 被加载到程序中,可以被反射机制读取
    @Target(ElementType.METHOD)//使用范围在方法上
    @Retention(RetentionPolicy.RUNTIME)//注解的生命周期运行时有效,可以被反射机制读取
    public @interface MyAnnotation {
        //方法的名称就是参数名称,返回值类型就是参数类型,default声明参数的默认值
        String name() default "";
        int age() default 0;
        String[] schoolName() default {"山西大学","太原理工大学"};
    }
    public class Test04 {
        @MyAnnotation(name="weiwei",age=20,schoolName = {"山西大学","太原理工大学"})
        public static void test01(){
        }
    }

     


反射读取注解信息
 
  1. ORM (Object Relationship Mapping)
    1) 类与表结构对应
    2) 属性和字段对应
    3) 对象和记录对应
    使用注解完成类和表结构的映射关系
  2. 功能描述
    Java 中的 Student 类使用第三方程序通过读取注解生成数据库中的表
  3. 实现步骤                                                                                                                                                                                    1) 编写 Student
    2) 编写注解
    3) 在类中使用注解
    4) 通过解析程序将注解读取出来 ( 通过框架解析 )
    5) 拼接 SQL 语句,使用 JDBC 到数据库中执行创建表
  4. @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface sxtTable {
        String value();
    }
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface sxtField {
        String conlumeName();
        String type();
        int length();
    }
    @sxtTable("table_student")
    public class Student {
        @sxtField(conlumeName = "name",type="char",length=10)
        private String name;
        @sxtField(conlumeName = "age",type="int",length=10)
        private int age;
    }
    public class Test05 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
            Class c=Class.forName("day07.reflect.Student");
            System.out.println("获取类的注解");
            Annotation[] a=c.getDeclaredAnnotations();
            for(Annotation a1:a){
                System.out.println(a1);//@day07.reflect.sxtTable(value=table_student)
            }
            System.out.println("获取指定的注解");
            sxtTable sxtTable =(sxtTable)c.getDeclaredAnnotation(sxtTable.class);
            System.out.println(sxtTable);//@day07.reflect.sxtTable(value=table_student)
            System.out.println("获取属性的注解");
            Field field=c.getDeclaredField("name");
         //   SxtField s =field.getDeclaredAnnotations(SxtField.class);
          //  System.out.println(s);
        }
    }

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值