反射+【注解】总结

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

反射

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

什么是框架

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

什么是反射

将类的各个组成部分封装为其他对象,这就是反射机制
[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. 调用注解中的抽象方法获取配置的属性值
原文地址:https://www.cnblogs.com/biturd/p/12623172.html