java注解与反射

这篇具有很好参考价值的文章主要介绍了java注解与反射。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java注解与反射

  • java注解与反射十分重要,是很多框架的底层

注解(Annotataion)

  • 注解的作用:

       1. 不是程序本身,可以对程序作出解释
       1. 可以被其他程序读取
    
  • 注解的格式:@注释名,如@override表示重写方法,而且有些还可以添加一些参数值,如@SuppressWarnings(value="unchecjed")

  • 注解可以附加在package,class,method,field等上面,相当于添加了额外的辅助信息。可以通过反射机制编程实现对这些元数据的访问

内置注解

  1. @Override:重写方法
  2. @Deprecated:表示不被鼓励使用或者已废弃已过时
  3. @SuppressWarning:用来抑制编译时的警告信息,但是需要添加一个或多个参数:如("all"),("unchecked")等,平时最好还是不要用这个

使用方法:

@Override
public  void run() {
}

其他类似。

元注解

  • 负责注解其他注解
  • 包括(@Target,@Retention,@Documented,@Inherited),分别表示
    1. 描述注解使用范围
    2. 需要上面级别保存该注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME,分别表示源代码,编译后的class文件,运行时)
    3. 说明该注解将被包含在javadoc中
    4. 说明子类可以继承父类中的该注解
//下面只能用到方法上,value的值可以取多个至于那些可以取CTRL+左键点击ElementType类去看,另外可以省略value=
@Target(value = ElementType.METHOD)
//只能存在于源码上。值有那些同上,自己点进去看RetentionPolicy类,一般取RUNTIME
@Retention(value = RetentionPolicy.SOURCE)
//这两个不多说
@Documented
@Inherited
//自定义注解
@interface MyAnnotation{

}

自定义注解

  • 使用@interface自定义注解,格式 public @interface 注解名{}
  • 其中每一个方法实际上是声明了一个配置参数
  • 方法名称就是参数名称
  • 返回值类型就是参数类型(返回值只能是基本类型或class,String,enum)
  • 可以用default来声明参数的默认值
  • 如果只有一个参数,一般参数名为value,只有一个参数时使用可以不写参数名=
  • 注解元素必须有值,我们定义注解元素时,经常使用空字符串,默认值为0
//元注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited
//自定义注解
@interface MyAnnotation{
//    注解参数:参数类型+参数名(),可以设置默认值,没默认值的话使用时必须传参
    String name() default "";
    int a();
    int c() default 1;
}

//使用
@MyAnnotation(name = "lihua",a = 1)

反射(Reflection)

java是一个静态语言(还有c,c++),因为它相对于动态语言来说,运行时结构不变,但是java可以利用反射来获得类似动态语言的特性,成为“准动态语言”。

动态语言就是运行时可以改变其结构的语言,如:c#,js,php,python等

  • 反射机制运行程序在执行的过程中通过反射取得任何类的内部信息,并且能够直接操作任意对象的内部属性及方法。

  • 主要API是Class

  • 反射是什么?

    java注解与反射

参考一下Class对象在java编译运行的那个部分:

java注解与反射

反射提供的部分功能:

java注解与反射

  • 优点与缺点

    优点:动态编译和创建,体现很大的灵活性

    缺点:对性能有影响

Class类

除了之前描述的,Class类还有一些特征:

  • Class 本身也是一个类
  • Class对象只能有系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由那个Class实例所生成的
  • 通过Class可以完整得到一个类中的所有被加载结构
  • Class类是反射的根源,,你要进行的任何针对类的动态加载运行等反射操作,都需要先得到该类的Class对象
public static void main(String[] args) throws ClassNotFoundException {
    /*1.下面是通过反射获取Class对象的一种方式,参数是文件路径
      2.一个类在内存中只有一个Class类,在多创建几个该类的Class
     也是同一个。
      3一个类被加载后,类的整个结构都会被封装在Class对象中
      4.我们经常用的Object的getClass方法就是返回一个Class对象,也是创建Class对象的一种常用方式
      5.反射在某种情况下可以理解为通过一个对象获得类
     */
    Class<?> aClass = Class.forName("com.xxx.MyThread");
    System.out.println(aClass);
}

//out:class com.xxx.MyThread

Class类的常用方法:

java注解与反射

Class类的四种创建方式

虽然上面可能已经描述过Class对象的创建方式的两种,这里还是再来具体写一下:

public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        Teacher teacher = new Teacher();
//        方式一:通过对象
        Class aClass = teacher.getClass();
        System.out.println(aClass);
//        方式二:forname
        Class<?> class1 = Class.forName("com.xxx.Teacher");
        System.out.println(class1);
//        比较两者
        System.out.println(aClass==class1);
//        方式三:通过类名.class获得
        Class<Teacher> teacherClass = Teacher.class;
        System.out.println(teacherClass);
//        比较
        System.out.println(teacherClass==class1);
//        方式四:基本数据类型的包装类的type属性
        Class<Integer> type = Integer.TYPE;
        System.out.println(type);
//        得到父类Class类型
        Class<?> superclass = class1.getSuperclass();
        System.out.println(superclass);
//     补充一下,获得注解和void和Class本身的Class对象
        // Override.class
        // void.class
        //Class.class

    }
}

class Teacher extends  Person{}

/*
class com.xxx.Teacher
class com.xxx.Teacher
true
class com.xxx.Teacher
true
int
class com.xxx.Person

那些类型可以有Class对象?

包括以下:

java注解与反射

注意:数组长度即使不一致,只要类型和维度一样,就是同一个Class

Class类的方法

获得类完整结构
public class MyThread {
    private  int a;
    public  void run(String a){}

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public MyThread(int a) {
        this.a = a;
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c1 = Class.forName("com.xxx.MyThread");
        //获取类名
        System.out.println(c1.getName());
        System.out.println(c1.getSimpleName());
//        获得类属性
        Field[] fields = c1.getFields();//只能找到public属性
        fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
//        获得类方法
        System.out.println("-----------------------");
        Method[] methods = c1.getMethods();//包括继承的方法
        methods=c1.getDeclaredMethods();//只包括本类的方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-------------------------------");
//        获得指定方法:没s,两个参数分别是方法名和方法参数类型的Class
        System.out.println(c1.getMethod("run",String.class));
//        获得构造器
        System.out.println("----------------");
        Constructor[] constructors = c1.getConstructors();//获得public构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
//        同理getDeclaredConstructors()获得的所有构造器,

        //获得指定的构造器,参数为构造器参数的Class
        System.out.println("--------------------------");
        Constructor constructor = c1.getConstructor(int.class);
        System.out.println(constructor);
    }
}
/*out:

public void com.xxx.MyThread.run(java.lang.String)
public void com.xxx.MyThread.setA(int)
public int com.xxx.MyThread.getA()
-------------------------------
public void com.xxx.MyThread.run(java.lang.String)
----------------
public com.xxx.MyThread(int)
--------------------------
public com.xxx.MyThread(int)
操作类结构
public class MyThread {
    private  int a;
    public  void run(String a){
        System.out.println(a);
    }

    public int getA() {
        return a;
    }

    public MyThread() {
    }

    public void setA(int a) {
        this.a = a;
    }

    public MyThread(int a) {
        this.a = a;
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.xxx.MyThread");
//        构建一个对象:本质是调用无参构造器,其该类必须有无参构造器
//        MyThread myThread = (MyThread)aClass.newInstance();
//        通过构造器创建对象,可以用有参构造函数
//       Constructor constructor= aClass.getDeclaredConstructor(int.class);
//       MyThread myThread1=(MyThread)constructor.newInstance(1);

//       通过反射调用方法
//        通过反射获取一个方法
        MyThread myThread = (MyThread) aClass.newInstance();
        Method setName = aClass.getMethod("run", String.class);
//        invoke:激活,参数:对象名,方法参数
        setName.invoke(myThread,"helloworld");

//        通过反射操作属性
        Field a=aClass.getDeclaredField("a");
//        取消安全检查,否则无法操作私有属性.method,field,consructor都有它,关闭也可以提高反射效率
        a.setAccessible(true);
        a.set(myThread,5);
        System.out.println(myThread.a);
    }
    
   /*out:
   helloworld
	5

类的加载过程

java注解与反射

java注解与反射

解释一下符号引用和直接引用:

符号引用你可以理解为要引用的类目前在内存中还没被加载出来,JVM当然不知道它在哪里。所以就用唯一的符号来表示就好像给它赋了一个变量,等到链接的时候类加载器解析地址完成变成直接引用

直接引用就是存储引用类在真实内存中的地址

总而言之还是这张图:

java注解与反射

什么时候会发生类的初始化

java注解与反射

主动引用比较好理解,下面只演示一下被动引用“

public class Main {
       //    初始化时执行一次静态代码块
    static {
        System.out.println("main函数所在类被加载了");
    }
    public static void main(String[] args) throws ClassNotFoundException {
       System.out.println(son.sonAge);
       /*
       out:
       main函数所在类被加载了
       父类被加载了
       子类被加载了
       10
        */
//------------------------------------------------------
//        这就是第一条的意思
        System.out.println(son.fatherAge);
        /*
            out:
             main函数所在类被加载了
             父类被加载了
             23
         */
//--------------------------------------------------------
//      第二条:本质上只是开辟了一片空间
        son[] arr = new son[5];
        /*
        out:
        main函数所在类被加载了
         */
//--------------------------------------------------------
        //常量是不会引起初始化的
        System.out.println(son.M);
        /*
        out:
        main函数所在类被加载了
        1
         */
    }
}

class  father {
    static int fatherAge = 23;

    //    初始化时执行一次静态代码块
    static {
        System.out.println("父类被加载了");
    }
}
class son extends father{
    static  int sonAge = 10;
    static  final  int M = 1;
    static {
        System.out.println("子类被加载了");
    }
}

类加载器

  • 类加载的作用:将class文件字节码内容加载到内存中,并且将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class 对象,作为方法区中类数据的访问入口。简单来说,类加载器的作用就是把类(class)装进内存
  • 类缓存:标准的JavaSE类加载器可以按照要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段数据。不过JVM垃圾回收机制可以回收这些Class对象

java注解与反射

类加载器有那些?

java注解与反射

java的主要jar包就是rt.jar,引导类加载器就是加载这一类核心jar包

 public static void main(String[] args) throws ClassNotFoundException {
//        获取系统类的加载器
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);

//        获取系统类加载器的父类加载器-->拓展加载器
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);
//        获得拓展类加载器的父类加载器-->根加载器(c/c++):这个java是无法获得的
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);

        System.out.println("------------------------");

//        测试当前类是那个加载器加载的
        ClassLoader classLoader3 = Class.forName("com.xxx.MyThread").getClassLoader();
        System.out.println(classLoader3);
//        测试jdk内部类是谁加载的:根加载器,输出不出来
        ClassLoader classLoader4 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader4);

        //如何获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));

    }

/*out:
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
jdk.internal.loader.ClassLoaders$PlatformClassLoader@5594a1b5
null
------------------------
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
null
本处按道理来说应该输出所有jar包路径,但是只说出了文件根目录,可能是因为jdk版本的原因,不确定,本处存疑

反射操作泛型

java注解与反射

public class MyThread {
   public void test01(Map<String,MyThread> map, List<MyThread> list){
   }
   public  Map<String,Map> test02(){
       return  null;
   }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
       //获得参数泛型
       Method method = MyThread.class.getMethod("test01", Map.class,List.class);
       //得到的是方法的参数Map,List
        Type[] genericExceptionTypes = method.getGenericParameterTypes();
        for (Type genericExceptionType : genericExceptionTypes) {
            if(genericExceptionType instanceof ParameterizedType){
                System.out.println(genericExceptionType);
                //得到的是方法参数的泛型
                Type[] actualTypeArguments = ((ParameterizedType) genericExceptionType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        //获得返回值泛型
        Method method1 = MyThread.class.getMethod("test02");
        Type genericReturnType = method1.getGenericReturnType();
        if(genericReturnType instanceof  ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }

}

/*
java.util.Map<java.lang.String, com.xxx.MyThread>
class java.lang.String
class com.xxx.MyThread
java.util.List<com.xxx.MyThread>
class com.xxx.MyThread
class java.lang.String
interface java.util.Map

反射操作注解

ORM->对象关系映射文章来源地址https://www.toymoban.com/news/detail-464998.html

public class MyThread {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.xxx.Teacher");
//        通过反射获得注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
//        获得注解的value值
        Table table = (Table) aClass.getAnnotation(Table.class);
        String value = table.value();
        System.out.println(value);

//        获得类指定注解
        Field f = aClass.getDeclaredField("id");
        Table annotation = f.getAnnotation(Table.class);
        System.out.println(annotation.value());


    }
}
@Table(value = "aaa")
class Teacher{
    @Table2(value = "aaa")
    private int id;
    @Override
    public String toString() {
        return super.toString();
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
        }
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Table2{
    String value();
}

/*
@com.xxx.Table(value="aaa")
aaa

到了这里,关于java注解与反射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java高级技术:单元测试、反射、注解

    目录 单元测试 单元测试概述 单元测试快速入门 单元测试常用注解 反射 反射概述 反射获取类对象 反射获取构造器对象 反射获取成员变量对象 反射获取方法对象 反射的作用-绕过编译阶段为集合添加数据 反射的作用-通用框架的底层原理 注解 注解概述 自定义注解 元注解

    2024年01月16日
    浏览(49)
  • Java中的反射(通过反射获取类的结构、invoke方法、获取注解)

    创建运行时类的对象是反射机制应用最多的地方。创建运行时类的对象有两种方式: 方式1:直接调用Class对象的newInstance()方法 要求: 1)类必须有一个无参数的构造器。 2)类的构造器的访问权限需要足够。 方式一的步骤 : 1)获取该类型的Class对象 2)调用Class对象的 new

    2024年02月04日
    浏览(49)
  • JAVA使用反射机制和注解实现对信息的处理-----JAVA入门基础教程

    import java.lang.annotation.Annotation; import java.lang.reflect.Field; public class AnnotationTest { public static void main(String[] args) throws Exception { Class c = Class.forName(\\\"Customer\\\"); c = Customer.class; Table table = (Table)c.getDeclaredAnnotation(Table.class); System.out.println(table.value()); Annotation[] annotations = c.getDeclaredAnnotatio

    2024年02月15日
    浏览(44)
  • Day20-【Java SE高级】单元测试 反射 注解 动态代理

    就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。 1. 咱们之前是如何进行单元测试的?有啥问题? 只能在main方法编写测试代码,去调用其他方法进行测试。 无法实现自动化测试,一个方法测试失败,可能影响其他方法的测试。 无法得到测试的报告,需要程

    2024年04月17日
    浏览(50)
  • Java进阶(1)——JVM的内存分配 & 反射Class类的类对象 & 创建对象的几种方式 & 类加载(何时进入内存JVM)& 注解 & 反射+注解的案例

    1.java运行时的内存分配,创建对象时内存分配; 2.类加载的顺序,创建一个唯一的类的类对象; 3.创建对象的方式,new,Class.forName,clone; 4.什么时候加载.class文件进入JVM内存中,看到new,Class.forName; 5.如何加载?双亲委托(委派)机制:安全;AppClassLoader; 6.反射实质:能

    2024年02月14日
    浏览(41)
  • java语法(二)线程并发、Juit单元测试、反射机制、注解、动态代理、XML解析、JVM

    正则表达式验证网站 1、 ? :表示前边这个字符可以出现0次或者1次。例如下边 /used? 既可以匹配 use 也可以匹配 used 。 2、 * :匹配0个或者多个字符, * 号代表前边这个字符可以出现0次或者多次。例如 /ab*c 可以匹配 ac、abc、abbbbc 3、 + :与 * 号不同的是, + 需要前面这个字符

    2024年02月06日
    浏览(49)
  • 搜索在计算机中的地位十分重要

    无论是在内部系统还是在外部的互联网站上,都少不了检索系统。数据是为了用户而服务。计算机在采集数据,处理数据,存储数据之后,各种客户端的操作pc机或者是移动嵌入式设备都可以很好的获取数据,得到 想要的数据服务。 检索分为SQL过滤查询和全文检索。数据都是

    2024年02月09日
    浏览(39)
  • 单元测试&反射&注解

             就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试。             可以用来对方法进行测试,它是由Junit公司开源出来的            反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。             

    2024年02月07日
    浏览(38)
  • 注解和反射

    Annotation是从JDK5.09开始引入的新技术 Annotation的作用: 不是程序本身,可以对程序做出解释 可以被其他程序(如编译器等)读取 例如:JUint框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。 Annotation的格式:注解以 @注释名

    2024年02月15日
    浏览(63)
  • Kotlin基础(十一):反射和注解

    本文主要讲解kotlin反射和注解。 Kotlin文章列表 Kotlin文章列表: 点击此处跳转查看 在Kotlin中,反射是一种能够在运行时动态地获取、检查和操作类、属性、方法等结构的能力。Kotlin为反射提供了一组API,这些API允许你在运行时获取类的信息并与其交互,而不需要在编译时知道

    2024年02月14日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包