JAVA注解和反射

笔记基于:【狂神说Java】注解和反射_哔哩哔哩_bilibili

JAVA注解和反射

1.注解

1.1 内置注解

  • 不是程序本身,可以对程序作出解释
  • 可以被其他程序(如编译器)读取

格式:“@注释名”

使用位置:可以附加在package,class,method,field等上面,相当于添加额外的辅助信息,通过反射进行访问

常见注解

@Override 表示一个方法声明打算重写超类中的另一个方法

@Deprecated 不推荐程序员使用,但是可以使用

@SuppressWarnings() 镇压警告

1.2 元注解

**作用:**元注解的作用就是负责注解其他注解,java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明

  • @Target(ElementType.XXXX):用于描述注解的使用范围

    • ElementType.TYPE——接口、类、枚举、注解
    • ElementType.FIELD——属性上生效
    • ElementType.METHOD——方法
    • ElementType.PARAMETER——方法参数
    • ElementType.CONSTRUCTOR ——构造函数
    • ElementType.LOCAL_VARIABLE——局部变量
    • ElementType.ANNOTATION_TYPE——注解
    • ElementType.PACKAGE——包
  • @Retention(RetentionPolicy.XXXX):表示需要在什么级别保存该注解信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)

    • source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略
    • class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
    • runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
  • @Documented:表示是否将我们的注解生成在JAVAdoc中

  • @Inherited:子类可以继承父类的注解

@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention 表示注解什么时候有效
@Retention(value = RetentionPolicy.RUNTIME)
// 表示是否将我们的注解生成在JAVAdoc中
@Documented
//Inherited 子类可以继承父类的注解
@Inherited

1.3 自定义注解

  • @interface用来声明注解,格式:@interface 注解名{定义内容}
//自定义注解
public class test03 {
    //注解可以显示赋值,如果没有默认值,我们必须给注解赋值
    @MyAnnotation2()
    public void  test(){

    }
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    //注解的参数:参数类型+参数名称();
    String name() default "";
    int age() default 1;//
    int id() default -1;//如果默认值为-1,代表不存在
}

@interface MyAnnotation3{
    //如果只有一个参数建议使用value,可以不需要添加default就可以省略
    String value();
}

2.反射

2.1 JAVA反射概述

  • 动态语言

    时一类运行时可以改变其结构的语言:例如行动函数、对象、甚至代码可以被引进,已有的函数可以被删除或时在其他结构上的变化。

    主要动态语言:Object-C、C#、JavaScript、PHO、Python等

  • 静态语言

    运行时结构不可变的语言就是静态语言。如Java、C、C++

    Java不是动态语言,但是因为有反射机制,所以具有一定的动态性

什么是反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

优点:可以实现动态常见对象和编译,体现出很大灵活性

缺点:影响性能

反射主要API

java.lang.Class:代表一个类

java.lang.reflect.Method:代表类的方法

java.lang.reflect.Feld:代表类的成员变量

java.lang.reflect.Method:代表类的构造器

2.2 理解类并获取Class实例

什么是Class类:Class本身也是一个类,Class对象智能由系统建立对象,一个加载到类在JVM中只会由一个Class实列,一个类对象对应的是加载到JVM的一个.class文件,每个类的实例都会记得自己是由那个Class是咧所生成,通过Class可以完整的得到一个类中所有被加载的结构

Class对象常用方法:

在这里插入图片描述

获取class实例:

//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:通过forname获得
Class c2 = Class.forName("reflection.Student");
System.out.println(c1.hashCode());
//方式三:通过类名.class获得
Class c3 = Student.class;
System.out.println(c1.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);

2.3类的加载与ClassLoader

类的加载过程:

  • 类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成。
  • 类的链接:将类的二进制数据合并到JRE中
  • 类的初始化:JVM负责对类的初始化

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

  • 类的主动引用
    • 虚拟机启动先初始化main方法所在类
    • new一个类的对象
    • 调用类的静态成员(除了final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 当初始化一个类,如果其父类没有初始化,则先会初始化它的父类
  • 类的被动引用
    • 当访问一个静态域的时候,只有真正声明这个域的类才会被初始化。
    • 通过数组定义类引用,不会触发此类的初始化
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

类加载器

  • 引导类加载器:用C++编写的,是JVM自带的类加载器。负责Java平台核心库,用来装载核心类库。该加载器无法直接获取。
  • 扩展类加载器:负责jre/lib/ext目录下的jar包
  • 系统类加载器:负责java -classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的类加载器
//获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);

//获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);

//获取扩展类加载器的父类加载器-->根类加载器(C/C++编写)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);

//测试当前类是那个加载器加载的
ClassLoader c1 = Class.forName("reflection.test07").getClassLoader();
System.out.println(c1);

//测试JDK内部类加载器
ClassLoader c2 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(c2);

获取运行时类的完整结构

Class c1 = Class.forName("reflection.User");

System.out.println(c1.getName()); //获取包名+类名
System.out.println(c1.getSimpleName()); //获取类名

System.out.println("==========================");
//获取类的属性
Field[] field = c1.getFields();  //只能找到public属性
Field[] declaredFields = c1.getDeclaredFields(); //获取全部属性
for(Field file:field){
	System.out.println(file);
}
System.out.println("==========================");
for(Field file:declaredFields){
	System.out.println(file);
}

//获得类的方法
System.out.println("==========================");
//获取本类和父类所有方法
Method[] methods = c1.getMethods();
for(Method meth:methods){
	System.out.println(meth);
}
System.out.println("==========================");
//获取本类所有方法
Method[] declaredMethods = c1.getDeclaredMethods();
for(Method meth:declaredMethods){
	System.out.println(meth);
}

//获取指定类方法
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);

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

//获取构造器
Constructor[] constructors = c1.getConstructors();  //获取public的
for(Constructor cs:constructors){
	System.out.println(cs);
}
System.out.println("==========================");
Constructor[] declaredConstructors = c1.getDeclaredConstructors();  //获取所有
for(Constructor cs:declaredConstructors){
	System.out.println(cs);
}

2.4 创建运行时类的对象

Class c1 = Class.forName("reflection.User");
//构造对象
User user = (User)c1.newInstance();  //本质调用无参构造器
//通过构造器创建对象
Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
User user2 = (User)constructor.newInstance("wwj", 001, 18);
System.out.println(user2);
//通过反射调用普通方法
User user3 = (User)c1.newInstance();
//获取反射方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke:激活 (对象,“方法参数)
setName.invoke(user3,"wwj1");
System.out.println(user3.getName());
//通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true); //关闭权限检测
name.set(user4,"wwj2");
System.out.println(user4.getName());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值