前言
注解就是源代码的元数据,通熟的讲就是 代码中的标签。注解就有如下的特点:
- 注解是一个附属品,依赖于其余元素(包、类、办法、属性等等)存在。
- 注解自身没有作用,在失当的时候由内部程序进行解析才会产生作用。
注解有哪些?
-
按起源分
- JDK 自带注解,例如:@Override, @Deprecated, @SuppressWornings。
- 第三方注解。
- 自定义注解。
-
按生命周期划分
- SOURCE:只存在于源代码中,编译成 class 文件就不存在了。
- Class:存在于源代码中和 class 文件中。
- RUNTIME:注解保留到运行时。
什么是元注解?
元注解指的是用于形成注解的注解,包含如下几个:
-
@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:具备继承性。
如何自定义注解?
自定义注解须要留神的问题:
- 应用 @interface 关键字定义。
- 主动继承
java.lang.annotation.Annotation
接口。 - 配置参数的类型只能是八大根本类型、String、Class、enum、Annotation 和对应的数组类型。
-
配置参数申明的语法格局如下([] 示意可省略):
类型 变量名() [default 默认值];
- 如果只有一个配置参数,其参数名必须为 value。
- 如果定义的注解含有配置参数,那在应用注解时,必须指定参数值,指定模式为:“参数名 = 参数值”。如果只有一个参数,间接写参数值即可,定义中指定了默认值的参数能够不指定值,但没有的肯定要指定值。
- 没有成员的注解为 标记 ,蕴含成员的称为 元数据。
自定义注解实例(定义和应用)
参考代码:
(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,他们的区别是:
- 无 Declared:只能获取到 public 润饰的,包含以后类和所有父类。
- 有 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("<-----------------getFields----------------->");
Field[] fields = person.getFields();
for (Field field : fields) {System.out.println(field);
}
System.out.println("<-----------------getDeclaredFields----------------->");
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("<-----------------getMethods----------------->");
Method[] methods = person.getMethods();
for (Method method : methods) {System.out.println(method);
}
System.out.println("<-----------------getDeclaredMethods----------------->");
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("<-----------------getConstructors----------------->");
// 仅 public
Constructor<?>[] constructors = person.getConstructors();
for (Constructor<?> constructor : constructors) {System.out.println(constructor);
}
System.out.println("<-----------------getDeclaredConstructors----------------->");
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("<--------test01---------->");
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("<--------test02---------->");
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);
}
}
}
}
运行后果:
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);
// 获取办法上的注解 略。。。
运行后果:
最初
感激你看到这里,看完有什么的不懂的能够在评论区问我,感觉文章对你有帮忙的话记得给我点个赞,每天都会分享 java 相干技术文章或行业资讯,欢送大家关注和转发文章!