反射parameter field_深度分析:注解和反射,注解自定义与反射具体使用实例全帮你搞明白...

前言

注解就是源代码的元数据,通熟的讲就是代码中的标签。注解就有如下的特点:

  1. 注解是一个附属品,依赖于其他元素(包、类、方法、属性等等)存在。

  2. 注解本身没有作用,在恰当的时候由外部程序进行解析才会发生作用。

注解有哪些?

  1. 按来源分

  • JDK 自带注解,例如:@Override, @Deprecated, @SuppressWornings 。

  • 第三方注解。

  • 自定义注解。

按生命周期划分

  • SOURCE:只存在于源代码中,编译成 class 文件就不存在了。

  • Class:存在于源代码中和 class 文件中。

  • RUNTIME:注解保留到运行时。

什么是元注解?

元注解指的是用于构成注解的注解,包括如下几个:

  1. @Retention:指明 Annotation 的生命周期,传入的值是一个枚举类型,可选值为:

  • RetentionPolicy.SOURCE

  • RetentionPolicy.CLASS

  • RetentionPolicy.RUNTIME

@Target:指明 Annotation 可以修饰程序哪些元素,传入的值为ElemetType[] 类型,值可为:

  • ElementType.CONSTRUCTOR :构造器

  • ElementType.FIELD:属性

  • ElementType.LOCAL_VARIABLE:局部变量

  • ElementType.METHOD:方法

  • ElementType.PACKAGE:包

  • ElementType.PARAMETER:参数

  • ElementType.TYPE:类、接口(包括注解类型和 enum 声明)

@Documented:使用此修饰的注解将会被 javadoc 工具提取成文档,使用此注解,其 @Retention 必须被设置为 RetentionPolicy.RUNTIME 。

@Inherited:具有继承性。

如何自定义注解?

自定义注解需要注意的问题:

  1. 使用 @interface 关键字定义。

  2. 自动继承 java.lang.annotation.Annotation 接口。

  3. 配置参数的类型只能是八大基本类型、String、Class、enum、Annotation 和对应的数组类型。

  4. 配置参数声明的语法格式如下([] 表示可省略):

    类型 变量名() [default 默认值];

  5. 如果只有一个配置参数,其参数名必须为 value。

  6. 如果定义的注解含有配置参数,那在使用注解时,必须指定参数值,指定形式为:“参数名=参数值”。如果只有一个参数,直接写参数值即可,定义中指定了默认值的参数可以不指定值,但没有的一定要指定值。

  7. 没有成员的注解为标记,包含成员的称为元数据。

自定义注解实例(定义和使用)

参考代码:

(1)Test01.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class Test01 {
@Info(name = "张三",address="北京")
public void test01(){

}
@One("value")
public void test02(){

}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@interface Info {
String name();
String address();

int age()default 18;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface One{
String value();
}
}

反射

什么是反射?

反射指的是程序在运行期间借助反射 API 取得任何类的内部信息,并通过这些内部信息去操作对应对象的内部属性和方法。

任何一个类,在第一次使用时,就会被 JVM 加载到堆内存的方法区中。JVM 加载类成功后,就会在方法区中产生一个对应的 Class 对象(一个类只要一个 Class 对象),这个 Class 对象包含被加载类的全部结构信息。

如何获取class对象?

(1)类的 class 属性

每一个类,都有一个 class 静态属性,这个静态属性就是类对应的 Class 对象。

1 Class<Person> cl1 = Person.class; 

(2)Object 对象 的 getClass() 方法

1 Person p1 = new Person();
2 Class<Person> cl2 = (Class<Person>) p1.getClass();

(3)通过 Class 类的 forName() 方法(最常用)

1 try {
2 Class cl3 = Class.forName("com.llm.hkl.Person");
3 } catch (ClassNotFoundException e) {
4 e.printStackTrace();
5 }

(4)通过 ClassLoader 类(不常用)

1 ClassLoader cl = Person.class.getClassLoader();
2 try {
3 Class cl4 = cl.loadClass("com.llm.hkl.Person");
4 } catch (ClassNotFoundException e) {
5 e.printStackTrace();
6 }

如何使用反射?

反射的基本使用包括创建对象,设置属性和调用方法。Class 对象中大多数 get 方法有 Declared 和无 Declared,他们的区别是:

  1. 无 Declared:只能获取到 public 修饰的,包括当前类和所有父类。

  2. 有 Declared:获取到当前类所有的(含有 private),但不包括其父类。

反射实例:

Person类和注解类(准备):
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Info(name = "张三", habbit = "编程")
public class Person {
@Filed("张三")
private String name;
public String habbit;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getHabbit() {
return habbit;
}

public void setHabbit(String habbit) {
this.habbit = habbit;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", habbit='" + habbit + '\'' +
", age=" + age +
'}';
}

private String say(String str) {
String str1 = name + "说:" + str;
System.out.println(str1);
return str1;
}

public void eat(String food) {
System.out.println(name + "吃" + food);
}

public Person() {

}

public Person(String name, String habbit, int age) {
this.name = name;
this.habbit = habbit;
this.age = age;
}

private Person(String name, String habbit) {
this.name = name;
this.habbit = habbit;
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@interface Info {
String name();

String habbit();

int age() default 18;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Filed{
String value();
}
}

reflect用法一(获取类的基本信息):

获得类的名字获得类的属性获得指定属性的值获得类的方法获得指定方法获取构造器获得指定的构造器

 Class<?> person = Class.forName("Person");
//获得类的名字
System.out.println("");
String name = person.getName();
System.out.println(name);

//获得类的属性
System.out.println("");
//仅public
System.out.println("");
Field[] fields = person.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("");
Field[] declaredFields = person.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}

//获得指定属性的值
System.out.println("");
Field name1 = person.getDeclaredField("name");
System.out.println(name1);

//获得类的方法
System.out.println("");
//仅public
System.out.println("");
Method[] methods = person.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("");
Method[] declaredMethods = person.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}

//获得指定方法
System.out.println("");
Method say = person.getDeclaredMethod("say",String.class);
System.out.println(say);

//获取构造器
System.out.println("");
System.out.println("");
//仅public
Constructor<?>[] constructors = person.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("");
Constructor<?>[] declaredConstructors = person.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//获得指定的构造器
System.out.println("");
Constructor<?> declaredConstructor = person.getDeclaredConstructor(String.class, String.class, int.class);
System.out.println(declaredConstructor);

reflect用法二(创建并操作对象):

反射方式创建对象调用无参构造器创建对象通过有参构造器通过私有的构造器通过反射设置公有属性通过反射设置私有属性通过反射调用方法通过反射调用私有方法

Class<?> person = Class.forName("Person");

// 反射方式创建对象
System.out.println("");
Person instance01 = (Person) person.newInstance();
System.out.println(instance01);

// 调用无参构造器创建对象
System.out.println("");
Constructor<?> noneConstructor = person.getDeclaredConstructor();
Person instance02 = (Person) noneConstructor.newInstance();
System.out.println(instance02);

// 调用有参构造器创建对象
System.out.println("");
Constructor<?> constructor = person.getDeclaredConstructor(String.class, String.class, int.class);
Person instance03 = (Person) constructor.newInstance("张三", "编程", 18);
System.out.println(instance03);

// 调用私有的构造器创建对象
System.out.println("");
java.lang.reflect.Constructor<?> privateConstructor = person.getDeclaredConstructor(String.class, String.class);
privateConstructor.setAccessible(true);
Object instance04 = privateConstructor.newInstance("张三", "编程");
System.out.println(instance04);

// 通过反射设置公有属性
System.out.println("");
Field habbit = person.getDeclaredField("habbit");
habbit.set(instance01, "编程");
System.out.println(instance01);

// 通过反射设置私有属性
System.out.println("");
Field name = person.getDeclaredField("name");
name.setAccessible(true);
name.set(instance01, "张三");
System.out.println(instance01);
// 通过反射调用公有方法
System.out.println("");
Method eat = person.getDeclaredMethod("eat", String.class);
eat.invoke(instance01,"饭");
// 通过反射调用私有方法
System.out.println("");
Method say = person.getDeclaredMethod("say", String.class);
say.setAccessible(true);
say.invoke(instance01,"呵呵");

reflect用法三(获取泛型信息):

Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器 Javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除。
为了通过反射操作这些类型,Java新增了 ParameterizedType, GenericArrayTypeType Variable和 WildcardType几种类型来代表不能被归一到class类中的类型但是又和原始类型齐名的类型。

ParameterizedType:表示一种参数化类型比如 Collection< String>

GenericArrayType:表示种元素类型是参数化类型或者类型变量的数组类型

TypeVariable:是各种类型变量的公共父接口

WildcardType:代表种通配符类型表达式

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Test03 {
public void test01(Map<String, Person> map, List<Person> list) {
System.out.println("test01");
}
public Map<String, Person> test02(){
System.out.println("test02");
return null;
}

public static void main(String[] args) throws Exception {
Class<Test03> test03 = Test03.class;

System.out.println("");
Method test01 = test03.getDeclaredMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = test01.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}

System.out.println("");
Method test02 = test03.getDeclaredMethod("test02");
Type genericReturnType = test02.getGenericReturnType();
System.out.println(genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}

运行结果:

7b60105828531887bc7f79d5f3a2b523.png

reflect用法四(获取注解信息):

获取类上的注解获取属性上的注解获取方法上的注解

        Class<?> person = Class.forName("Person");
System.out.println("");
//获取类上的注解
Info annotation = person.getAnnotation(Info.class);
System.out.println(annotation.name());
System.out.println(annotation.habbit());
System.out.println(annotation.age());

System.out.println("");
//获取属性上的注解
Field name = person.getDeclaredField("name");
Person.Filed file = name.getAnnotation(Person.Filed.class);
String value = file.value();
System.out.println(value);
//获取方法上的注解 略。。。

运行结果:

41d68f87f2392d78665cbba23b853245.png

最后

感谢你看到这里,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

5e9091587f9b370730d730725a64602a.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值