文章目录
注解和反射
1.注解-annotation
1.1 元注解
元注解的作用就是负责注解其他注解(@Target、@Retention、@Documented、@Inherited)
@Target:描述注解的使用范围(方法、类、参数上等)——多个使用范围,必须加上{ }
@Retention: 定义了注解保持有效的 使命周期阶段(runtime(默认写这个) >class>sources)
@Documented: 表示是否将我们的注解生成在JavaDoc中
@Inherited: 子类可以继承父类的注解
//@Retention 定义了注解保持有效的 使命周期阶段
@Retention(RetentionPolicy.RUNTIME)
//@Target 表示注解能使用的目标
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER})
//@Documented:表示是否将我们的注解生成在JavaDoc中
@Documented
//@Inherited:子类可以继承父类的注解
@Inherited
public @interface MyAnnotation {
//成员
String userName() default "张三";
int age();
boolean flag() default true;
//枚举
Color color() default Color.RED;
//注解
OtherAnnotation othanno();
}
注意:
-
注解:主要作用就在程序中传值(在运行阶段完成:结合反射使用)
-
在注解中参数可以用default来定义默认值
-
调用自定义自定义注解,注解有一个成员参数可以直接写参数值,注解有多个成员参数,必须用参数名value= ;
-
注解中有默认值,可以不用给其赋值·
-
注解中的成员参数是数组且数组只有一个元素时,{}可以省略,否则{}不能省略
@MyAnnotation(userName = "李四",age = 16,color = Color.RED,othanno = @OtherAnnotation(1)) public class annotationDemo { public static void main(String[] args) { System.out.println(" "); } }
1.2 通过基本反射读取注解
annotationDemo类:设置注解
@MyAnnotation(userName = "王啊五",age = 4,flag = true,color = Color.RED,othanno = @OtherAnnotation(1))
public class annotationDemo {
@MyAnnotation(userName = "李四",age = 5,othanno = @OtherAnnotation(4))
private static void print(@MyAnnotation(age = 1,othanno = @OtherAnnotation(1))String userName,@MyAnnotation(age = 7,userName = "刘六")Integer id){
System.out.println("你好");
}
}
TestGetValue类:分别读取类上、方法上、参数上的注解
public class TestGetValue {
public static void main(String[] args) throws NoSuchMethodException {
Class<TestAnnotation> annotationClass = TestAnnotation.class;
//获取方法参数中的注解
Method print = annotationClass.getDeclaredMethod("print", String.class, Integer.class);
Parameter[] parameters = print.getParameters();
for (Parameter parameter : parameters) {
boolean annotationPresent = parameter.isAnnotationPresent(MyAnnotation.class);
if (annotationPresent) {
MyAnnotation annotation = parameter.getAnnotation(MyAnnotation.class);
int age = annotation.age();
String userName = annotation.userName();
System.out.println(age+" "+userName);
}
}
System.out.println("============================");
//获取方法上的注解
Method print1 = annotationClass.getDeclaredMethod("print", String.class,Integer.class);
boolean isAnnotation2 = print1.isAnnotationPresent(MyAnnotation.class);
if (isAnnotation2) {
MyAnnotation annotation = print1.getAnnotation(MyAnnotation.class);
int age = annotation.age();
String userName = annotation.userName();
System.out.println(age + " " + userName);
}
System.out.println("============================");
//获取类上的注解
boolean isAnnotation = annotationClass.isAnnotationPresent(MyAnnotation.class);
if (isAnnotation) {
MyAnnotation annotation = annotationClass.getAnnotation(MyAnnotation.class);
int age = annotation.age();
String userName = annotation.userName();
System.out.println(userId + " " + userName);
}
}
}
2.反射-Java Reflection
2.1 java反射机制功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
- 。。。。。。
2.2 反射优缺点
优点: 可以实现动态创建对象和编译,体现很大的灵活性
缺点: 对性能有影响;反射操作总是慢于直接执行相同的操作(就是所谓的解释操作,告诉JVM,希望它满足反射操作的要求)
2.3 创建类的三种方式
//方式一:通过 forName 获取class类
Class userClass = Class.forName("entity.User");
//方式二:通过 对象 获得
User user = new User();
Class userClass2 = user.getClass();
//方式三:通过 类名.class 方式获取(靠谱安全)
Class userClass3 = User.class;
2.4 获取类名、属性、方法、构造器
Class userClass = Class.forName("entity.User");
//获取类的名字
System.out.println("============类的名字==============");
String name = userClass.getName(); //包名+类名
System.out.println("包名+类名:"+name);
String simpleName = userClass.getSimpleName(); //类名
System.out.println("只有类名:"+simpleName);
System.out.println();
//获取类的属性
System.out.println("===========类的属性============");
Field[] fields = userClass.getFields(); //只能找到public属性
for (Field field : fields) {
System.out.println("public属性:"+field);
}
Field[] declaredFields = userClass.getDeclaredFields(); //找到所有属性
for (Field declaredField : declaredFields) {
System.out.println("所有权限的属性:"+declaredField);
}
System.out.println();
//获取指定属性的值
System.out.println("============指定属性==================");
Field userName = userClass.getField("userName"); //获取指定public属性的值
System.out.println("指定public属性:"+userName);
Field userName1 = userClass.getDeclaredField("userName");//可以获取所有属性的值
System.out.println("指定所有权限的属性" + userName1);
System.out.println();
//获取类的方法
System.out.println("=============类的方法================");
Method[] methods = userClass.getMethods(); //获取本类及父类全部的public方法
for (Method method : methods) {
System.out.println("本类及父类全部的public方法:"+method);
}
Method[] declaredMethods = userClass.getDeclaredMethods(); //获取本类中所有的方法
for (Method declaredMethod : declaredMethods) {
System.out.println("本类中所有的方法:"+declaredMethod);
}
System.out.println();
//获取指定类的方法
System.out.println("===============指定类的方法===============");
Method setUserId = userClass.getMethod("setUserId", Integer.class);//获取指定public方法
Method getUserId = userClass.getMethod("getUserId");
System.out.println("指定public方法setUserId:"+setUserId);
System.out.println("指定public方法getUserId:"+getUserId);
Method sleep = userClass.getDeclaredMethod("sleep", User.class);//获取指定所有权限的方法
Method getUserId1 = userClass.getDeclaredMethod("getUserId");
System.out.println("指定所有权限的方法sleep:"+sleep);
System.out.println("指定所有权限的方法getUserId1:"+getUserId1);
System.out.println();
//获取构造器
System.out.println("=============类的构造器=================");
Constructor[] constructors = userClass.getConstructors();//获取public构造器
for (Constructor constructor : constructors) {
System.out.println("public构造器:"+constructor);
}
Constructor[] declaredConstructors = userClass.getDeclaredConstructors();//获取所有权限的构造器
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println("所有权限的构造器:"+declaredConstructor);
}
System.out.println();
//获取指定的构造器(单例模式中的构造器可以不是public)
System.out.println("============指定类的构造器================");
Constructor constructor = userClass.getConstructor(); //获取指定public构造器
Constructor integerConstructor = userClass.getConstructor(Integer.class);
System.out.println("指定的public无参构造器:"+constructor);
System.out.println("指定public构造器:"+integerConstructor);
Constructor declaredConstructor = userClass.getDeclaredConstructor(Integer.class, String.class);
Constructor stringDeclaredConstructor = userClass.getDeclaredConstructor(String.class);//获取指定(所有权限)构造器
System.out.println("指定(所有权限)构造器:"+declaredConstructor);
System.out.println("指定(所有权限)构造器:"+stringDeclaredConstructor);
2.5 动态创建对象执行方法
2.5.1 创建对象的方法
//1.通过反射创建一个对象
User user = (User) userClass.newInstance();//本质调用无参构造器
//2.通过构造器创建对象
Constructor declaredConstructor = userClass.getDeclaredConstructor(Integer.class, String.class);
User user2 = (User) declaredConstructor.newInstance(15, "xiaolu");
2.5.2 通过反射调用某个方法、属性等
调用***私有方法、私有属性***时,要暴力反射 给参数/属性赋值;
暴力反射:方法名/属性.setAccessible(true);
例:以public权限方法 和 非public权限方法为例
实体User类: setUserName public方法 和 sleep private方法
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
private void sleep(User user){
System.out.println(user.getUserId()+"在睡觉");
}
-
调用public权限方法
//通过反射获取一个方法 Method setUserName = userClass.getDeclaredMethod("setUserName", String.class); //invoke(对象,参数赋值) setUserName.invoke(user,"xiaoli"); System.out.println("获取值:"+user.getUserName());
-
调用非public权限的方法
//通过反射获取一个私有方法 Method sleep = userClass.getDeclaredMethod("sleep", User.class); user.setUserId(1); user.setUserName("xiaolu"); //不能直接操作非public权限,我们需要关闭程序的安全监测,即属性或方法的setAccessible(true) sleep.setAccessible(true);//暴力反射 sleep.invoke(user, user); //System.out.println(invoke);
2.6 反射操作泛型
- ParameterizedType:表示一种参数化类型 比如Collection
- GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
- TypeVariable:是各种类型变量的公共父接口
- WildcardType:代表一种通配符类型表达式
Reflection3 类 : 里面test01 和 test02两方法
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;
}
2.6.1 获取泛型的参数类型
Class<Reflection3> reflection3Class = Reflection3.class;
Method method = reflection3Class.getDeclaredMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.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); //遍历输出
}
}
}
2.6.2 获取泛型返回值的的类型
Class<Reflection3> reflection3Class = Reflection3.class;
Method method1 = reflection3Class.getDeclaredMethod("test02");
Type genericReturnType = method1.getGenericReturnType();//获取泛型返回值类型
System.out.println(genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument); //遍历返回值的参数类型
}
}