zoukankan      html  css  js  c++  java
  • 反射+【注解】总结

    类加载的三个阶段:
    在这里插入图片描述

    反射

    非常非常重要,框架设计的灵魂

    什么是框架

    算一个半成品软件,帮我们完成了一部分工作。

    什么是反射

    将类的各个组成部分封装为其他对象,这就是反射机制
    [idea、eclipse就用的反射机制,只能提示]

    Java代码在计算机中的三个阶段

    • 1.source源代码阶段 .java、.class
    • 2.Class类对象阶段
    • 3.Runtime阶段

    优点

    • 1.在程序运行过程中,操作这些对象(编译器,智能提示)
    • 2.可以解耦,提高程序的扩展性

    获取class的方式

    在源代码阶段: Class.forName(“类名”)

    • 多用于配置文件,将类名定义在配置文件中。读取文件,加载类

    在Class类对象阶段:
    类名.class

    • 多用于参数传递

    Runtime运行时阶段:
    对象.getClass() [在Object类里面定义]

    • 多用于对象的获取字节码的方式
    public class PersonDemo {
        public static void main(String[] args) throws ClassNotFoundException {
            // 1. Class.forName("全类名")   source阶段获取对象
            Class clazz = Class.forName("domain.Person");
            System.out.println(clazz);
    
            // 2. 类名.class   类加载器阶段获得类
            Class clazz2 = Person.class;
            System.out.println(clazz2);
    
            // 3.对象.getClass()  运行时阶段获得类的对象
            Person p = new Person();
            Class clazz3 = p.getClass();
            System.out.println(clazz3);
            
            // 比较的是地址
            System.out.println(clazz == clazz2);
            System.out.println(clazz == clazz3);  
        }
    }
    

    同一个字节码文件在一次程序运行过程中只会被加载一次,三种方式获得的对象都是同一个

    错误类型

    Exception in thread "main" java.lang.ClassNotFoundException: domain.Person
    

    没有找到类,类名写错了,或者没有这个包。找不到class文件

    Class对象的功能

    获取功能

    • 获取成员变量
    • 获取构造方法
    • 获取成员方法
    • 获取类名
    	* Class对象功能:
    		* 获取功能:
    			1. 获取成员变量们
    				* Field[] getFields() :获取所有public修饰的成员变量
    				* Field getField(String name)   获取指定名称的 public修饰的成员变量
    
    				* Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
    				* Field getDeclaredField(String name)  
    			2. 获取构造方法们
    				* Constructor<?>[] getConstructors()  
    				* Constructor<T> getConstructor(类<?>... parameterTypes)  
    
    				* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)  
    				* Constructor<?>[] getDeclaredConstructors()  
    			3. 获取成员方法们:
    				* Method[] getMethods()  
    				* Method getMethod(String name, 类<?>... parameterTypes)  
    
    				* Method[] getDeclaredMethods()  
    				* Method getDeclaredMethod(String name, 类<?>... parameterTypes)  
    
    			4. 获取全类名	
    				* String getName()  
    
    
    	* Field:成员变量
    		* 操作:
    			1. 设置值
    				* void set(Object obj, Object value)  
    			2. 获取值
    				* get(Object obj) 
    
    			3. 忽略访问权限修饰符的安全检查
    				* setAccessible(true):暴力反射
    
    
    
    	* Constructor:构造方法
    		* 创建对象:
    			* T newInstance(Object... initargs)  
    
    			* 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
    
    
    	* Method:方法对象
    		* 执行方法:
    			* Object invoke(Object obj, Object... args)  
    
    		* 获取方法名称:
    			* String getName:获取方法名
    

    运行时动态扩展程序

    原文:
    https://www.cnblogs.com/junhuawang/p/7429322.html

    前提: 实体类和接口

    //首先定义一个接口来隔离类:
    public interface Operator
    {
    //    public java.util.List act(java.util.List params);
        public java.util.List act(String content,String content2,java.util.List params);
    }
    
    
    import java.util.*;
    
    public class Success implements Operator{
    
     public static void main(String[] args) {
        List list = new ArrayList();
        list.add("Success3");
        Operator op = new Success();
        System.out.println("act===" + op.act("Success1", "Success2", list));
    }
    
    
    // 实体类
    //实现接口的方法
    //       public java.util.List act(java.util.List params)
    public java.util.List act(String content, String content2,java.util.List params) {
        List result = new ArrayList();
        result.add(content);
        result.add(content2);
        result.add(params);
        return result;
    }
    
    }
    
    
    import java.util.*;
    public class Load implements Operator{
    
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("Load3");
        Operator op = new Load();
        System.out.println("act===" + op.act("Load1", "Load2", list));
    }
    
    //       public java.util.List act(java.util.List params)
    public java.util.List act(String content, String content2,java.util.List params)
    {
        List result = new ArrayList();
        result.add(content);
        result.add(content2);
        result.add(params);
        return result;
    }
    
    }
    

    面向Operator接口编写主程序,在需要用到类的时候 通过反射获得类

    import java.lang.reflect.*;
    import java.util.Properties;
    import java.io.FileInputStream;
    import java.util.List;
    //这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,
    
    就可以支持2000、3000做参数的调用
    //有了这样的反射机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,
    
    public class TestReflect
    {
    //加载配置文件,查询消息头对应的类名
    private String loadProtocal(String header)
    {
        String result=null;
        try
        {
        Properties prop=new Properties();
        //           FileInputStream fis=new FileInputStream("emp.properties");
        //           id = prop.getProperty(idString);
        //           prop.load(fis);
        //           fis.close();
        prop.load(getTCL().getResourceAsStream("emp.properties"));
        result=prop.getProperty(header);
        }catch(Exception e){
            System.out.println(e);
        }
    return result;
    }
    
    private static ClassLoader getTCL() throws IllegalAccessException,
    InvocationTargetException {
        Method method = null;
        try {
        method = Thread.class.getMethod("getContextClassLoader", null);
        } catch (NoSuchMethodException e) {
        return null;
        }
    return (ClassLoader)method.invoke(Thread.currentThread(), null);
    }
    
    //针对消息作出响应,利用反射导入对应的类
    public String response(String header,String content,String content2,List list)
    {
        String result=null;
        String s=null;
        try
        {
        /*
        * 导入属性文件emp.properties,查询header所对应的类的名字
        * 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离
        * 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议
        */
        s="org.bromon.reflect."+this.loadProtocal(header).trim();
        //加载类
        System.out.println("s==="+s);//打印 s===org.bromon.reflect.Success
        Class c=Class.forName(s);
        //java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类
        //           Method m[] = c.getDeclaredMethods();//
        //           for (int i = 0; i < m.length; i++)//
        //               System.out.println(m[i].toString());
        //  打印   public java.util.List org.bromon.reflect.Success.act(java.util.List)
        //创建类的事例
        Operator mo=(Operator)c.newInstance();
        System.out.println("mo==="+mo);
        //构造参数列表
        Class params[]=new Class[3];
        //           params[0]=Class.forName("java.util.List");
        params[0]=Class.forName("java.lang.String");
        params[1]=Class.forName("java.lang.String");
        params[2]=Class.forName("java.util.List");
        System.out.println("params[0]==="+params[0]);
        //           //查询act方法
        Method m=c.getMethod("act",params);
        System.out.println("method=="+m.toString());
        Object[] args=new Object[3];
        args[0]=content;
        args[1]=content2;
        args[2]=list;
        //           //调用方法并且获得返回
        Object returnObject=m.invoke(mo,args);//这个地方出问题了,抛异常~~~~
        //           System.out.println("returnObject==="+returnObject);
        List result2 = (List)returnObject;
        result = (String)result2.get(0);
        System.out.println("result2=="+result2);
        //
        }catch(Exception e) {
        System.out.println("Handler-response:"+e);
    
        //Handler-response:java.lang.IllegalArgumentException: argument type mismatch
        //IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明基础方法的类或接口(或其中的子类或实现程序)的实例;
        //如果实参和形参的数量不相同;如果基本参数的解包转换失败;或者如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。
        }
    return result;
    }
    
    public static void main(String args[])
    {
        TestReflect tr=new TestReflect();
        List list = new java.util.ArrayList();
        list.add("测试List");
        tr.response("2000","Load1","Load2",list);//1000是Success,2000是Load
        tr.response("1000","Success1","Success2",list);//1000是Success,2000是Load
    
    }
    }
    

    JavaBean的反射: 内省 [避免一些异常] 内省的再封装BeanUtils

    注解(Annotation)(元数据)

    • 概念:
      用来说明程序。给计算机看。

    • 注释:
      用文字描述程序的。给程序员看。

    • 作用分类:

      1. 编写文档: 生成文档.[doc文档]
      2. 代码分析: 对代码进行分析[使用反射]
      3. 编译检查:
        让编译器能够实现基本的编译检查[Override]

    JDK预定义的注解

    • @Override: 检测被该注解标注的方法是否是继承(接口也行)而来的
    • @Deprecated: 该注解标注的内容,表示已过时
    • @SuppressWarnings: 压制警告
      • 一般会传一个all参数 @SuppressWarnings(“all”)

    自定义注解

    格式:
    • 元注解
    • public @interface 注解名称{}
    本质

    编译+反编译 注解本质就是接口

    C:UsersAdministratorIdeaProjectsdefaultsrcannotation>javac MyAnno.java
    
    C:UsersAdministratorIdeaProjectsdefaultsrcannotation>
    C:UsersAdministratorIdeaProjectsdefaultsrcannotation>javap MyAnno.class
    Compiled from "MyAnno.java"
    public interface annotation.MyAnno extends java.lang.annotation.Annotation {
    }
    
    
    属性

    接口中可以定义的成员方法

    要求

    一、属性的返回值类型
    1. 基本数据类型
    2. String
    3. 枚举
    4. 注解
    5. 以上类型的数组
    
    二、定义了属性,在使用时需要给属性赋值
    
    使用注解时赋值, 用法类似属性 所以尽量命名注意一下
    @MyAnno(age = 12)
    
    1. 如果定义属性时,使用default关键
    字给属性默认初始值,则使用注解是,可
    以不进行属性的赋值
    
    2. 如果只有一个属性需要复制,并且属
    性的名称是value,则value可以省略,直
    接定义值即可
    
    3.数组赋值时,值使用{}包裹。如果数
    组只有一个值,则{}省略。
    
    
    

    元注解

    用于描述注解的注解[控制的都是注解所修饰的注解]
    在这里插入图片描述

    • @Target: 描述注解能够作用的位置
      • ElementType取值
        • TYPE: 可以作用在类上
        • METHOD: 可以作用于方法上
        • FIELD: 可以作用于成员变量上
    • @Retention:
      描述注解被保留的阶段(3个阶段)
      • RetentionPolicy(枚举类型)取值
        • SOURCE
        • CLASS
        • RUNTIME
    • @Documented: 描述注解是否被抽取到api文档中
    • @Inherited: 描述注解是否被子类继承

    在程序中使用(解析)注解

    注解只有属性。。

    使用当然就是获取注解中定义的属性值。

    • 注解就是将反射中配置文件的工作交给注解了

    在程序使用注解: 获取注解中定义的属性值

    1. 获取注解定义的位置的对象(Class,Method,Field)
    类上的注解
            Pro pro = Test.class.getAnnotation(Pro.class);  // 获取注解对象的接口
            System.out.println(pro.className());
    
    
    方法上的注解
            Method method = Test.class.getMethod("fun");
            Pro p = method.getAnnotation(Pro.class);
            return p.methodName();
    
    1. 获取指定的注解
    getAnnotation(Class)
    // 其实就是在内存中生成一个该注解接口的子类实现对象
        public class ProImpl implements Pro{
            public String ClassName(){
                return "cn.thatweknow.Demo"
            }
            public String methodName(){
                return "show";
            }
        }
        
    
    1. 调用注解中的抽象方法获取配置的属性值
  • 相关阅读:
    第四次作业
    第三次作业
    java第三次作业
    java第二次作业
    java作业
    第一次作业
    第十一次作业
    第十次作业
    第九次作业
    第八次作业
  • 原文地址:https://www.cnblogs.com/biturd/p/12623172.html
Copyright © 2011-2022 走看看