注解和反射
注解 Annotation
注解又称 Annotation
,是JDK 5.0
开始引入的技术
通俗的讲注解相当于程序的解释说明,注解可以通过反射被读取
Annotation格式:@“注释名”,当然可以添加一些参数值(形如:@Retention(RetentionPolicy.RUNTIME)
)
注解可以使用在package
、class
、method
、field
等上面
最典型的例子就是重写注解了
@override
public void run(){...}
元注解
元注解的作用就是负责注解其他注解
Java定义了四个标准的meta-annotation
类型,它们被用来提供对其他annotation
类型做说明。
所在包 java.langannotation
-
@Target
用于描述注解的使用范围,描述被注解的注解可以用在什么地方
-
@Retention
表示需要在什么级别保存该注解信息,用于描述注解的生命周期
注解级别:
SOURCE
(源代码)<CLASS
(字节码) <RUNTIEM
(运行时) -
@Document
说明该注解将被包含在
javadoc
中 -
@Inherited
说明子类可以继承父类中的该注解
内置注解
定义在系统中java.lang.*
包内
-
@Override
此注释只适用于修饰方法,表示声明一个方法打算重写超类中的另一个方法。
-
@Deprecated
此注释只适用于修饰方法,属性,类,表示不支持使用这样的元素
-
@SupperWarnings
用来屏蔽警告信息,需要添加一个参数才能正确使用
@SuppressWarnings("all") @SuppressWarnings("unchecked") @SuppressWarnings(value={"unchecked","deprecation"})
自定义注解
自定义注解允许自定义注解名称和注解参数
使用自定义注解时,自动继承了java.lang.annotation.Annotation
接口
@Target(value = {ElementType.TYPE,ElementType.METHOD}) //作用于 方法和类 可省略
@Retention(RetentionPolicy.RUNTIME) //作用于 运行时 可省略
public @interface MyAnnotation{
String value() default "null";//default 代表默认值
...
}
@Myannotation("Test")
public class Test{...}
反射 Reflection
Java反射(Reflection)是Java非常重要的动态特性
通过使用反射我们不仅可以获取到任何类的成员方法、成员变量、构造方法等信息
还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。
注解和反射是各种java web
框架的底层实现机制与灵魂
Class类
Class类是一个描述类的类,是反射的根源。
一个在内存中加载的类在JVM
中只会有一个对应的Class的实例化对象,通过Class可以完整的得
到一个类中所有被加载的结构。
[了解] 类的常用方法
1.getName():返回String形式的该类的名称。
2.newInstance():根据某个Class对象产生其对应类的实例,它调用的是此类的默认构造方法(没有默认无参构造器会报错)
3.getClassLoader():返回该Class对象对应的类的类加载器。
4.getSuperClass():返回某子类所对应的直接父类所对应的Class对象
5.isArray():判定此Class对象所对应的是否是一个数组对象
6.getComponentType() :如果当前类表示一个数组,则返回表示该数组组件的 Class 对象,否则返回 null。
7.getConstructor(Class[]) :返回当前 Class 对象表示的类的指定的公有构造子对象。
8.getConstructors() :返回当前 Class 对象表示的类的所有公有构造子对象数组。
9.getDeclaredConstructor(Class[]) :返回当前 Class 对象表示的类的指定已说明的一个构造子对象。
10.getDeclaredConstructors() :返回当前 Class 对象表示的类的所有已说明的构造子对象数组。
11.getDeclaredField(String) :返回当前 Class 对象表示的类或接口的指定已说明的一个域对象。
12.getDeclaredFields() :返回当前 Class 对象表示的类或接口的所有已说明的域对象数组。
13.getDeclaredMethod(String, Class[]) :返回当前 Class 对象表示的类或接口的指定已说明的一个方法对象。
14.getDeclaredMethods() :返回 Class 对象表示的类或接口的所有已说明的方法数组。
15.getField(String) :返回当前 Class 对象表示的类或接口的指定的公有成员域对象。
16.getFields() :返回当前 Class 对象表示的类或接口的所有可访问的公有域对象数组。
17.getInterfaces() :返回当前对象表示的类或接口实现的接口。
18.getMethod(String, Class[]) :返回当前 Class 对象表示的类或接口的指定的公有成员方法对象。
19.getMethods() :返回当前 Class 对象表示的类或接口的所有公有成员方法对象数组,包括已声明的和从父类继承的方法。
20.isInstance(Object) :此方法是 Java 语言 instanceof 操作的动态等价方法。
21.isInterface() :判定指定的 Class 对象是否表示一个接口类型
22.isPrimitive() :判定指定的 Class 对象是否表示一个 Java 的基类型。
[了解] 获取Class类的方式
-
具体的类,通过类的
class
属性获取Class c = Object.class;
-
知道类全名,通过
Class.forName()
方法获取Class c = Class.forName("com.reflection.demmo");
-
实例化的类,通过调用
.getClass()
方法获取Person person = new Person(); Class c = person.getClass();
三种获取方法的区别
1 类名.class(也称类字面常量) 方式生成Class对象不会初始化的静态块,不会初始化参数,不会调用构造函数
2 Class.forName()方式生成Class对象会初始化类静态块,但不会初始化非静态的代码块,也不调用构造函数
3 Object.getClass()方式生成Class对象会先初始化静态块,接着执行非静态块的初始化,最后调用构造函数
[了解] 可以获取Class的数据类型
类、接口、数组、注解、枚举、基本数据类型、void、Class
//代码
Class c1 = Object.class; //类
Class c2 = Runnable.class; //接口
Class c3 = String[].class; //一维数组
Class c4 = String[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class; //枚举
Class c7 = Integer.class; //基本数据类型包装类
Class c8 = void.class; //void
Class c9 = Class.class; //Class
//输出
class java.lang.Object
interface java.lang.Runnable
class [Ljava.lang.String;
class [[Ljava.lang.String;
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
Field类
代表类的成员变量
.getFields()
获取public
修饰属性
.getDeclaredFields
可以获取所有属性
//getFields 只能找到pubilc属性
Field[] fields = c1.getFields();
//getDeclaredFields 可以找到所有属性
fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//输出格式:全类名.属性
java.lang.String 注解和反射.自定义注解.name
Method 类
代表类的方法,该类型主要通过Class 中一下三个方法获取
.getMethods()
获得本类和继承类的所有public方法
.getDeclaredMethods()
获取本类的所有方法
.getMethod("方法名", 方法形参类型.class)
获得指定的方法,
//获得本类和继承类的所有public方法
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println("getMethods(): " + method);
}
//获取本类的所有方法
methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println("getDeclaredMethods(): " + method);
}
//获得指定的方法
Method setName = c1.getMethod("setName", String.class);
Method getName = c1.getMethod("getName");
System.out.println(setName);
System.out.println(getName);
//输出格式 全类名.方法名
Invke方法的使用
Class c2 = Class.forName("com.reflaction.User");
User user = (User) c2.newInstance();
Method setName = c2.getMethod("setName", String.class);
setName.invoke(user,"形参");
Constructor 类
代表类的构造方法
.getConstructors
获取本类和父类的所有构造方法
.getDeclaredConstructors
获取本类所有构造方法
.getConstructor(String.class,int.Class,int.class)
获取指定参数类型构造器
//获取本类和父类的所有构造方法
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获取本类所有构造方法
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获取指定的构造器
Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
System.out.println(constructor);
Array 类
提供了动态创建数组,以及访问数组的元素的静态方法。
动态创建一维数组并赋值
//动态创建数组
Object array = Array.newInstance(String.class, 10);
//对array数组的第五个元素赋值
Array.set(array, 5, "helloworld");
//获取数组元素
String str = (String) Array.get(array, 5);
动态创建多维数组
//反射三维数组
int[] dims = new int[] { 5, 10, 15 };
Object array = Array.newInstance(Integer.TYPE, dims);//array 是个三维数组
//获取数组元素:二维数组
Object arrayObj =Array.get(array, 3);
//数组类型
Class<?> acls = arrayObj.getClass();
System.out.println(acls);
//数组元素类型,getComponentType()返回表示数组组件类型的 Class,如果此类不表示数组类,则此方法返回null。
Class<?> componentType = arrayObj.getClass().getComponentType();
System.out.println(componentType);
//获取数组元素:一维数组
arrayObj=Array.get(arrayObj, 5);
Array.set(arrayObj, 10, 30);
//获取打印
int [][][] arrayCast=(int [][][])array;
System.out.println(arrayCast[3][5][10]);//30
反射类构造器获取实例化对象
//调用无参构造实例化对象
Class c1 = Class.forName("com.reflaction.User");
User user = (User) c1.newInstance();
//获得有参构造方法
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
//通过构造器获得实例化对象
User ago = (User) constructor.newInstance("ago", 18, 1);
System.out.println(ago);
反射获取调用普通方法
方法一
- 反射获取目标类的class对象(
Class.forName()
) ==> - 获取有参构造器(
class.getDeclaredConstructor()
) ==> - 获取目标类实例化对象(
constructor1.newInstance(param1, param2, param3 ,...)
) ==> - 调用方法(
实例化对象.Method()
)
Class c2 = Class.forName("com.reflaction.User");
Constructor constructor1 = c2.getDeclaredConstructor(String.class, int.class, int.class);
User zh1z3ven = (User) constructor1.newInstance("zh1z3ven", 20, 2);
System.out.println(zh1z3ven.getAge());
System.out.println(zh1z3ven.getName());
zh1z3ven.setId(20);
System.out.println(zh1z3ven.getId());
方法二
- 反射获取目标类class对象(
Class.forName()
) ==> - 获取目标类实例化对象(
constructor1.newInstance(param1, param2, param3 ,...)
) - 获取指定方法(
class.getMethod("方法名", 参数)
) ==> - 激活执行方法(
.invoke(目标对象, 参数)
)
Class c2 = Class.forName("com.reflaction.User");
User user2 = (User) c2.newInstance();
Method setName = c2.getMethod("setName", String.class);
//invoke 代替调用user2对象的setName方法,并向方法内传参
setName.invoke(user2, "kfei");
System.out.println(user2.getName());
反射操作属性
- 获取class对象
class.getDeclaredField("属性名")
获取属性.set()
方法设置属性- 若为
private
修饰,出现无权限操作异常,可用.setAccessible(true)
关闭安全检测,获取操作权限
Class c3 = Class.forName("com.reflaction.User");
User user4 = (User) c3.newInstance();
Field name = c3.getDeclaredField("name");
name.setAccessible(true);
name.set(user4 ,"zgo");
System.out.println(user4.getName());
[了解] 反射操作泛型
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 TestFanXingDemo {
public void test01(Map<String, User> map, List<User> list){
System.out.println("test01");
}
public Map<String, User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = TestFanXingDemo.class.getMethod("test01", Map.class, List.class);
method.setAccessible(true); //关闭安全检测,暴力反射
Type[] genericParameterTypes = method.getGenericParameterTypes(); //获得泛型的参数类型
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#genericParameterType: " + genericParameterType); //遍历泛型类型
if (genericParameterType instanceof ParameterizedType){ //判断泛型参数类型是否是参数化类型
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); //获得真实参数信息
//循环遍历参数
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
}
[了解] 反射操作注解
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class TestDemo12 {
//反射操作注解
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.reflaction.Student2");
//通过反射获得全部注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value值
TableStudent tableStudent = (TableStudent) c1.getAnnotation(TableStudent.class);
String value = tableStudent.value();//获取注解的value
System.out.println(value);
//获取指定类的注解value
Field f = c1.getDeclaredField("name");
FieldStudent annotation = f.getAnnotation(FieldStudent.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@TableStudent("db_student")
class Student2{
@FieldStudent(columnName = "db_id", type = "int", length = 10)
private int id;
@FieldStudent(columnName = "db_age", type = "int", length = 10)
private int age;
@FieldStudent(columnName = "db_name", type = "varchar", length = 3)
private String name;
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setId(int id) {
this.id = id;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE) //作用范围为类
@Retention(RetentionPolicy.RUNTIME) //作用为运行时可获取
@interface TableStudent{
String value();
}
//属性的注解
@Target(ElementType.FIELD) //作用范围为类
@Retention(RetentionPolicy.RUNTIME) //作用为运行时可获取
@interface FieldStudent{
String columnName();
String type();
int length();
}
参考
(3条消息) B站【狂神说Java笔记】-注解和反射_闲言-CSDN博客
Java之注解与反射 - CoLoo - 博客园 (cnblogs.com)