一、注解
1、注解(Annotation)是什么?
- Annotation是从JDK5.0开始引入的新技术。
- Annotation的作用: 不是程序本身,可以对程序作出解释。可以被其他程序(比如编译器等)读取。
- Annotation的格式: 注解是"@注释名"在代码中存在的,还可以添加一些参数值。
2、内置的注解
- @Override:用作修辞方法,表示一个方法声明打算重写超类中的另一个声明
- @Deprecated:不推荐使用,但是可以使用,或存在更好的方式。
- @SuppressWarnings: 用来抑制编译时的警告信息,必须要添加参数。
//SuppressWarnings 用来抑制编译时的警告信息,必须要添加参数
@SuppressWarnings("all")
public class test1 extends parent{
public static void main(String[] args) {
}
//Override 重写的注解
@Override
public void test1() {
super.test1();
}
//Deprecated 不推荐使用,但是可以使用,或存在更好的方式。
@Deprecated
public static void test2(){
System.out.println("这是Deprecated");}
}
3、元注解
元注解的作用就是负责注解其他注解, Java定义了4个标准的meta -annotation类型,他们被用来
提供对其他annotation类型作说明 。
- @Target :用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
- @Retention :表示需要在什么级别保存该注释信息,用于描述注解的生命周期 (SOURCE < CLASS < RUNTIME)
- @Document:说明该注解将被包含在javadoc中
- @Inherited: 说明子类可以继承父类中的该注解
public class Test2 {
@MyAnnotation
public void test(){
}
}
//定义一个自己的注解
//Target 表示这个注解可以用在哪个地方
//Retention 表示我们注解在什么地方有效
//Inherited 子类可以继承父类的注解
@Target(value = {ElementType.METHOD,ElementType.ANNOTATION_TYPE})
//runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@interface MyAnnotation{
}
4、自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
- @ interface用来声明一个注解,格式: public @ interface注解名{定义内容}。
- 其中的每一个方法实际上是声明了一个配置参数。
- 方法的名称就是参数的名称。
- 返回值类型就是参数的类型(返回值只能是基本类型,Class , String , enum )。
- 可以通过default来声明参数的默认值。
- 如果只有一一个参数成员, - -般参数名为value。
- 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值。
public class Test3 {
//注解可以显示赋值,如果没有默认值,我们就必须给注解赋值。
@MyAnnotation2(age=23)
public void test1(){
}
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//注解的参数:参数类型+参数名();
String name() default "";
int age();
}
二、反射
1.什么是反射?
反射指的是我们可以在运行期间加载、探知、使用编译期间完全未知的类。是一个动态的机制,允许我们通过字符串来指挥程序实例化,操作属性、调用方法。使得代码提高了灵活性,但是同时也带来了更多的资源开销。
加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个 类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过 这个镜子看到类的结构,所以,我们形象的称之为:反射。
2、如何获取反射的类?
先创建个User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String id;
public String name;
private Integer age;
}
通过三种方法获取到
//获取反射
public class Test1 {
//通过Class.forName()获取(最常用)
public static void main(String[] args) {
try {
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//通过getClass()获取
User user = new User();
Class aClass1 = user.getClass();
//通过.class来获取
Class<User> userClass = User.class;
}
}
2、如何使用反射?
- 获取类名、变量、字段、还有方法
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
//获取全类名
String name = aClass.getName();
System.out.println(name);
//获取简单类名
String simpleName = aClass.getSimpleName();
System.out.println(simpleName);
//获取类的字段、某些变量
//获取该类的所有public字段,包括父类的
Field[] fields = aClass.getFields();
for ( Field field: fields ){
System.out.println(field.getName());
}
//根据字段名获取该类的public字段
Field name1 = aClass.getField("name");
//根据字段名获取该类的字段
aClass.getDeclaredField("age");
}
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
//获取该类的所有public方法,包括父类的
Method[] methods = aClass.getMethods();
//根据方法名获取该类的public方法
Method method = aClass.getMethod("getName");
//如果该类为重写方法,可以在第二个参数加上重写方法的参数类型,不写为无参数的方法
Method paramMethod = aClass.getMethod("getName",String.class);
//获取该类的所有方法,不包括父类(仅自定义)
Method[] declaredMethods = aClass.getDeclaredMethods();
//根据方法名获取该类的方法
Method declaredMethod = aClass.getDeclaredMethod("getName");
}
- 获取类的构造器
//获取类的构造器
public class Test4 {
public static void main(String[] args) throws Exception {
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
//获取该类的所有构造器,包括父类
Constructor[] constructors = aClass.getConstructors();
//根据构造器的参数类型来获取指定构造器,不写为无参构造器
Constructor constructor = aClass.getConstructor();
Constructor constructor1 = aClass.getConstructor(String.class,int.class);
//获取该类的所有构造器,不包括父类
Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
//根据构造器的参数类型来获取指定的自定义构造器,不写为无参构造器
Constructor declaredConstructor = aClass.getDeclaredConstructor();
Constructor declaredConstructor1 = aClass.getDeclaredConstructor(String.class, int.class);
}
}
- 实例化一个类
//类的实例化
public class Test5 {
public static void main(String[] args) throws Exception {
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
//通过class类直接实例化,使用的是User类的无参构造器
User user = (User) aClass.newInstance();
//获取构造器来进行实例化,这里获取有参构造器
Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class,String.class,Integer.class);
//根据构造器进行实例化
User user1 = (User) declaredConstructor.newInstance("12", "admin",44);
System.out.println(user1);
}
}
- 运行结果
- 使用发射来调用方法
public class Test6 {
public static void main(String[] args) throws Exception{
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
User user = (User) aClass.newInstance();
Method setName = aClass.getMethod("setName", String.class);
//第一个是调用底层方法的对象,也就是通过哪个对象来调用方法
//第二个为可变参数,是用于方法调用的参数
setName.invoke(user,"admin1");
System.out.println(user);
}
}
- 运行结果
- 使用反射修改字段的值(使用id.setAccessible(true)跳过安全检查)
public class Test7 {
public static void main(String[] args) throws Exception{
Class aClass = Class.forName("com.example.dci.Reflect.pojo.User");
User o = (User) aClass.newInstance();
Field id = aClass.getDeclaredField("id");
//使用id.setAccessible(true)跳过安全检查
id.setAccessible(true);
//第一个参数为修改的字段的对象
//第二个为被修改字段的新值
id.set(o,"123");
System.out.println(o);
}
}
- 运行结果
3、注解与反射的使用
- 注解是之前创建的一个自定义注解
//定义一个自己的注解
//Target 表示这个注解可以用在哪个地方
//Retention 表示我们注解在什么地方有效
//Inherited 子类可以继承父类的注解
@Target(value = {ElementType.METHOD,ElementType.ANNOTATION_TYPE})
//runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation{
String name() default "";
}
- 要拿注解的值,先利用反射获取到注解修饰的那个类,然后通过调用***getDeclaredAnnotation(注解名字.class)***才能获取到注解的值。
//注解与反射
public class Test8 {
public static void main(String[] args) throws Exception {
Class aClass = Class.forName("com.example.dci.annotation.test1");
Method test1 = aClass.getDeclaredMethod("test2");
MyAnnotation declaredAnnotation = test1.getDeclaredAnnotation(MyAnnotation.class);
String value = declaredAnnotation.name();
System.out.println(value);
}
}