注解和反射
注解
什么是注解
Annotation是从jdk5.0开始引入新技术
作用:可对程序做出解释,可以被其他程序(比如:编译器等)读取。
格式:注解是以@注释名在代码中存在的
可以通过反射读注解
内置注解
-
@override 重写超类(父类)方法声明
-
@Deprecated 危险,已过时的
-
@SupperWarning 抑制编译时的警告信息
元注解
元注解的作用就是负责注解其他注解。
- @Target: 被描述的注解可以放在什么地方(例如方法上,类上)
@Target(value = {ElementType.METHOD,ElementType.TYPE})
- @Retention:描述注解的生命周期
@Retention(value = RetentionPolicy.RUNTIME)
- @Document:说明该注解被包含在javadoc中
- Inherited:说明自雷可以继承父类中的该注解
自定义注解
-
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
-
分析:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o61Zr9X2-1629878413311)(D:\File\图片\QQPhoto\QQ截图20210825153712.png)]
//自定义注解 public class Test3 { //注解可以显示赋值,如果没有默认值,我们就必须给赋值 @MyAnnotiation2(age = 18,name = "秦疆") public void test(){ } @MyAnnotation3("QINJIANG") //如果注解只有一个值,可用value命名,省略value= public void test1(){ } } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotiation2{ //注解的参数:参数类型+参数名() String name() default ""; int age(); int id() default -1;//如果默认值是-1,代表不存在 String[] schools() default {"西部开源","清华大学"}; } @interface MyAnnotation3{ String value(); }
反射
反射是java被视为动态语言的关键。
优点:实现动态创建对象和编译
缺点:对性能有影响
1、获得反射对象
Class c = Class.forName(“java.lang.String”)
一个类在内存中只有一个class对象,这个类包含了完整的类的结构信息。
反射相关的API
2、获得Class类的几种方式
Class类的常用方法
获取Class类的实例
//方式一:通过对象过得到
Class c1 = person.getClass();
System.out.println(c1.hashCode());
System.out.println(c1.getName());
//方式二:forname获得
Class c2 = Class.forName("com.jia.reflection.Student");
System.out.println(c2.hashCode());
System.out.println(c2.getName());
//方式三: 通过类名.class获得
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
System.out.println(c3.getName());
3、获取运行时类的完整结构
通过反射获取运行时类的完整结构
Field、Method、Constructor、SuperClass、Interface、Annotation
//获得类的名子
System.out.println(c1.getName());//获得包名+类名
System.out.println(c1.getSimpleName());//获得类名
//获得类的属性
Field[] fields = c1.getFields(); //getFileds()只能找到public属性
fields= c1.getDeclaredFields();//getDeclaredFields()能找到全部属性
for (Field field : fields) {
System.out.println(field);
}
Field name = c1.getDeclaredField("name");//获得指定属性
System.out.println(name);
-
获得类的方法
-
getMethods() :获得本类及其父类的全部public方法
-
getDeclaredMethods() :获得本类的所有方法
-
getMethod(name,parameterTypes) :获得指定方法 例如:
c1.getMethod("setName",String.class);
-
4、动态创建对象执行
(1)创建类的对象:调用Class对象的newInStance()方法
类必须有一个无参数的构造器
类的构造器访问权限需要足够
**注:**如果没有无参构造器,只要在操作是明确调用类的构造器,并将参数穿进去,才可以实例化。步骤如下:
- 通过Class类的getDeclaredConstructor(Class …parameterType)取得本类的指定形参类型的构造器。
- 按构造器的需要,里面放入构造器所需的各个参数
- 通过Constructor实例化对象。
//动态创建对象,通过反射
public class Test2 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
//获得Class对象
Class c1 = Class.forName("com.jia.reflection.User");
//构造一个对象
User user = (User)c1.newInstance(); //本质是调用了类的无参构造器
System.out.println(user);
//通过有参构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("秦疆",2,18);
System.out.println(user2);
}
}
(2)调用指定得到方法
通过反射,调用类中的方法,通过Method类完成
- 通过Class类的getMethod(String name, Class…parameterType)方法取得一个Method对象,并设置此方法操作时所需的参数类型。
- 之后使用 Object invoke(Object obj, Object[] args)(对象,方法值)进行调用,并向方法中传递设置的obj对象的参数信息。
Object invoke(Object obj, Object[] args)
//通过反射调用普通方法
User user3 = (User)c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getMethod("setName", String.class);
//invoke:激活的意思
//(对象,"方法的值")
setName.invoke(user3,"狂神");
System.out.println(user3.getName());
(3)通过反射操作属性
//通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,我们需要关闭程序的安全监测,属性或者方法的setAccessible(true)
name.setAccessible(true);
name.set(user4,"狂神2");
System.out.println(user4.getName());
setAccessible
视频连接:https://www.bilibili.com/video/BV1p4411P7V3?p=4