注解与反射
注解
元注解
@ Target:用于描述注解的使用范围
@Rutention:表示需要在什么级别保存该注释信息,用于描述注解的声明周期
(SOURCE<CLASS<RUNTIME)
自定义注解
@interface用来声明一个注解:public @interface 注解名 {定义内容}
public class Annotation {
@MyAnnotation("")
public String test(){
return "注解";
}
@MyAnnotation2(age = 18,value ={"HKU"})
public String test2(){
return "注解";
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
// @Retention(RetentionPolicy.CLASS)
// @Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation{
String value();
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2{
int age();
String name() default "Chet";
//传对象
String[] value();
}
}
反射
创建对象方式
- 正常方式
- 反射方式
获取Class类的实例
- 已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class<User> clazz = User.class;
- 已知某个类的实例,调用该实例的getClass()方法获取Class对象,调用该实例的getSuperclass()方法获取该Class对象的父对象Class
Class clazz = user.getClass();
Class superclass = clazz.getSuperclass();
- 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class userClass = Class.forName("com.refelction.User");
获取实例化对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取类名
Class userClass = Class.forName("com.refelction.User");
System.out.println(userClass);
//获取实例化对象
User user = (User) userClass.getDeclaredConstructor().newInstance();
user.setAge(1);
user.setId(2);
user.setName("Chet");
System.out.println(user);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class User{
private String name;
private Integer age;
private Integer id;
}
所有类型的Class对象
public class test2 {
public static void main(String[] args) {
Class<Object> objectClass = Object.class;//类
System.out.println(objectClass);
Class<Comparable> comparableClass = Comparable.class;//接口
System.out.println(comparableClass);
Class<String[]> stringArr = String[].class;//一维数组
System.out.println(stringArr);
Class<int[][]> intArrArr = int[][].class;//二维数组
System.out.println(intArrArr);
Class<Override> overrideClass = Override.class;//注解
System.out.println(overrideClass);
Class<ElementType> elementTypeClass = ElementType.class;//枚举
System.out.println(elementTypeClass);
Class<Integer> integerClass = Integer.class;//基本数据类型
System.out.println(integerClass);
Class<Void> voidClass = void.class;//void
System.out.println(voidClass);
Class<Class> classClass = Class.class;//Class
System.out.println(classClass);
}
}
- 输出
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
Process finished with exit code 0
类加载内存分析
加载
- 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构 ,然后生成一个代表这个类的java.lang.Class对象
链接
- 将Java类的二进制代码合并到JVM的运行状态之中的过程
初始化
ClassLoader
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取系统类加载器的父类加载器--扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//获取扩展类加载器的父类加载器--根加载器
ClassLoader grand = parent.getParent();
System.out.println(grand);
//测试加载当前类的类加载器
ClassLoader classLoader1 = Class.forName("com.refelction.Test").getClassLoader();
System.out.println("com.refelction.Test的 classLoader"+classLoader1);
ClassLoader classLoader2 = Class.forName("java.lang.Object").getClassLoader();
System.out.println("java.lang.Object的 classLoader="+classLoader2);
}
- 输出
jdk.internal.loader.ClassLoaders$AppClassLoader@78308db1
jdk.internal.loader.ClassLoaders$PlatformClassLoader@2e817b38
null
com.refelction.Test的 classLoader=jdk.internal.loader.ClassLoaders$AppClassLoader@78308db1
java.lang.Object的 classLoader=null
获取类的运行时结构
- User类
@Data
@NoArgsConstructor
@AllArgsConstructor
class User{
public String name;
private Integer age;
private Integer id;
}
- 获取结构
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class userClass = Class.forName("com.refelction.User");
//包名+类名
String name = userClass.getName();
System.out.println(name);
System.out.println("=======================");
//类名
String simpleName = userClass.getSimpleName();
System.out.println(simpleName);
System.out.println("=======================");
Field[] fields1 = userClass.getFields();//只能找到public属性
for (Field field : fields1) {
System.out.println(field);
}
System.out.println("=======================");
Field[] fields2 = userClass.getDeclaredFields();//可以找到全部属性
for (Field field : fields2) {
System.out.println(field);
}
System.out.println("=======================");
Field fieldName = userClass.getField("name");
System.out.println("fieldName" + fieldName);
//获取不到private属性,报错
// Field fieldAge = userClass.getField("age");
Field fieldAge = userClass.getDeclaredField("age");
System.out.println("fieldAge=" + fieldAge);
System.out.println("=======================");
Method[] methods = userClass.getMethods();//获得本类和父类的public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("=======================");
Method[] declaredMethods = userClass.getDeclaredMethods();//获得本类的所有方法
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("=======================");
//获得指定名称方法
Method getName = userClass.getDeclaredMethod("getName");
System.out.println(getName);
Method getAge = userClass.getMethod("getAge");
System.out.println(getAge);
System.out.println("=======================");
//获得所有的构造器
Constructor[] constructors = userClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("=======================");
//获取有参构造器
Constructor constructor1 = userClass.getConstructor(String.class, Integer.class, Integer.class);
System.out.println(constructor1);
Constructor declaredConstructor1 = userClass.getDeclaredConstructor(String.class, Integer.class, Integer.class);
System.out.println(declaredConstructor1);
//获取无参构造器
Constructor constructor2 = userClass.getConstructor();
System.out.println(constructor2);
Constructor declaredConstructor2 = userClass.getDeclaredConstructor();
System.out.println(declaredConstructor2);
}
动态创建对象执行方法
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<User> userClass = User.class;
User user = userClass.getDeclaredConstructor().newInstance();//调用了无参构造器
user.setName("Chet");
user.setId(1);
user.setAge(18);
System.out.println(user);
//得到有参构造方法
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, Integer.class, Integer.class);
User user1 = declaredConstructor.newInstance("Atkins",2,34);
System.out.println(user1);
//通过反射得到方法
//1.获取实例化对象
User user2 = userClass.getDeclaredConstructor().newInstance();
//2.得到实例化对象的setAge方法
Method setAge = userClass.getDeclaredMethod("setAge", Integer.class);
//3.方法.invoke(实例化对象,参数)
setAge.invoke(user2, 25);
System.out.println(user2);
//通过反射得到方法
Field id = userClass.getDeclaredField("id");
//id为private属性,需要设置为可以访问,默认访问开关为false
id.setAccessible(true);
id.set(user2,3);
Field name = userClass.getDeclaredField("name");
// name为public属性,不需要开启name.setAccessible(true);
name.set(user2,"MJ");
System.out.println(user2);
}
性能检测
public class Test6 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test1();
test2();
test3();
}
//普通方式调用
public static void test1() {
User user = new User();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println(time);
}
//反射方式调用
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
long start = System.currentTimeMillis();
Class userClass = user.getClass();
Method getName = userClass.getDeclaredMethod("getName");
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println(time);
}
//反射方式调用,关闭检测
public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
long start = System.currentTimeMillis();
Class userClass = user.getClass();
Method getName = userClass.getDeclaredMethod("getName");
getName.setAccessible(true);
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long end = System.currentTimeMillis();
long time = end - start;
System.out.println(time);
}
}
反射操作泛型
- ParameterizedType:表示一种参数化类型,比如Collection<String>
- GenericArrayType:表示一种元素类型时参数化类型或者类型变量的数组类型
- TypeVariable:是各种变量的公共父接口
- WildcardType:代表一种通配符类型表达式
获取注解的值
@Annotation.MyAnnotation2(age = 28,value ={"HK","UK"})
public class Annotation {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
//通过一个类的属性获取一个类的注解的值
//1.获取一个类的class
Class<Teacher> teacherClass = Teacher.class;
//2.获取该类的属性
Field name = teacherClass.getDeclaredField("name");
//3.通过该属性获取其指定注解
MyAnnotation2 annotation = name.getAnnotation(MyAnnotation2.class);
//4.获取指定注解的值
String[] annotationValue = annotation.value();
for (String s : annotationValue) {
System.out.println(s);
}
System.out.println(annotation.age());
//通过一个类获取类的值
//1.获取一个类的class
Class<Annotation> annotationClass = Annotation.class;
//2.获取该类的注解
MyAnnotation2 annotation2 = annotationClass.getAnnotation(MyAnnotation2.class);
//3.获取指定注解的值
String[] value = annotation2.value();
for (String s : value) {
System.out.println(s);
}
int age = annotation2.age();
System.out.println(age);
}
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation2{
int age();
String name() default "Chet";
//传对象
String[] value();
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Teacher{
@MyAnnotation2(age = 18,value ={"HKU"})
String name;
Integer age;
}
}