Java注解与反射知识梳理
迪丽瓦拉
2024-02-17 04:25:25
0

Java注解与反射

注解

内置注解

  • @Overrice
  • @Deprecated
  • @SupperessWarnings
package annotation;import java.util.ArrayList;
import java.util.List;// 什么是注解
public class Test01 extends Object{// @Override重写的注解@Overridepublic String toString() {return super.toString();}// Deprecated 不推荐程序员使用,但是可以使用. 或者存在更好的方式@Deprecatedpublic static void test(){System.out.println("Deprecated");}@SuppressWarnings("all")public void test02(){List list = new ArrayList();}public static void main(String[] args) {test();}
}

元注解

  • 元注解的作用就是负责注解其他注解,4种
  • 在java.lang.annotation中可找到(@Target, @Retetion, @Documente, @Inherited)
    • @Target:用于描述注解的使用范围
    • @Retetion:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME)
    • @Documente: 说明该注解将被包含在javadoc中
    • @Inherited:说明子类可以继承父类的该注解

自定义注解

  • 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
  • 分析
    • @interface用来声明一个注解,格式:public @interface注解名{定义内容}
    • 其中每一个方法实际上是声明了一个参数配置
    • 方法的名称就是参数的名称
    • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
    • 可以通过default来声明参数的默认值
    • 如果只有一个参数成员,一般参数名为value
    • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
package annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 自定义注解
public class test03 {// 注解可以显示赋值,如果没有默认值,我们就必须给注解赋值@MyAnnotation2(name="alex",school = {"snut","sust"})public void test(){}@MyAnnotation3("alex")public void test2(){}
}@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{// 注解的参数:参数类型 + 参数名();String name();int age() default 0;int id() default -1; // 如果默认值是-1,代表不存在String[] school();
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{String value();
}

反射机制 java.reflection

静态语言 vs 动态语言

  • 动态语言
    • 是一类在运行时可以改变结构的语言
    • 主要动态语言: Object-C,c#,JavaScript,PHP,Python等
  • 静态语言
    • 运行时结构不可改变的语言就是静态语言。如Java,C,C++
    • Java不是动态语言,由于反射机制,所以Java是“准动态语言”

Java Reflection

  • Reflection是Java被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
        Class c = Class.forName("java.lang.String")
    
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像是一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
    正常方式:引入需要的包名 -> 通过new实例化 -> 取得实例化对象
    反射方式:实例化对象 -> getClass()方法 -> 得到完整的“包类”名称

功能

  • 运行时判断任意一个对象所属的类
  • 运行时构造任一个类的对象
  • 运行时判断任意一个类所具有的成员变量和方法
  • 运行时获取泛型信息
  • 运行时调用任一个对象的成员变量和方法
  • 运行时处理注解
  • 生成动态代理

优点
可以实现动态创建对象和编译,灵活
缺点
对象能有影响。是一种解释操作,jvm满足人,慢于直接执行的相同操作。

package reflection;// 什么叫反射
public class test01 {// 通过反射机制获取类的Class对象public static void main(String[] args) throws ClassNotFoundException {Class c1 = Class.forName("reflection.User");System.out.println(c1);Class c2 = Class.forName("reflection.User");Class c3 = Class.forName("reflection.User");// 一个类在内存中只有一个Class对象// 一个类被加载后,类的整个结构都会被封装在Class对象中System.out.println(c1.hashCode());System.out.println(c2.hashCode());System.out.println(c3.hashCode());}
}//实体类
class User{private String name;private int id;private int age;public User(){}public User(String name, int id, int age){this.name = name;this.id = id;this.age = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

获取Class类的实例

  1. 若已知具体的类,通过类的class属性获取,该方法是最为安全可靠,程序性能最高;
        Class clazz = Person.class;
    
  2. 已知某个类的实例,调用该实例的getClass()方法获取Class对象
        Class clazz = person.getClass();
    
  3. 已知一个类的全类名,且该类在路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNOtFoundException
        Class clazz = Class.forName("demo01.Student");
    
  4. 内置基本数据类型可以直接用类名.Type
  5. 还可以利用Class Loader
package reflection;public class Test03 {public static void main(String[] args) throws ClassNotFoundException {Person p1= new Student();System.out.println("这个人是:"+p1.name);// 方式1: 通过对象获得Class c1 = p1.getClass();System.out.println(c1.hashCode());// 方式2:通过forname获得Class c2 = Class.forName("reflection.Student");System.out.println(c2.hashCode());// 方式3:通过 类名.class获得Class c3 = Student.class;System.out.println(c3.hashCode());// 方式4: 基本内置类型的包装类都有一个Type属性Class c4 = Integer.TYPE;System.out.println(c4);// 获取父类类型Class c5 = c1.getSuperclass();System.out.println(c5);System.out.println(c5.hashCode());}
}class Person{String name;public Person(){}public Person(String name){this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';}
}class Student extends Person{public Student(){this.name = "学生";}
}class Teacher extends Person{public Teacher(){this.name = "教师";}
}

按住option键可以复制多列,并给多列赋值

哪些类可以有Class对象

package reflection;import java.lang.annotation.ElementType;// 所有类型的Class
public class Test03 {public static void main(String[] args) {Class c1 = Object.class;  // 类Class c2 = Comparable.class;  // 接口Class c3 = String[].class;  // 一维数组Class c4 = int[][].class;  // 二维数组Class c5 = Override.class;  // 注解Class c6 = ElementType.class;  // 枚举Class c7 = Integer.class;  // 基本数据类型Class c8 = void.class;  // voidClass c9 = Class.class;  // ClassSystem.out.println(c1);System.out.println(c2);System.out.println(c3);System.out.println(c4);System.out.println(c5);System.out.println(c6);System.out.println(c7);System.out.println(c8);System.out.println(c9);}
}

类的加载过程:Load(生成一个代表这个类的java.lang.Class对象) -> Link -> Initialize(执行类构造器)

package reflection;public class Test04 {public static void main(String[] args) {A a = new A();System.out.println(a.m);}/*1. 加载到内存,会产生一个类对应Class对象2. 链接,链接结束后 m = 03. 初始化(){System.out.println("A类静态代码块初始化");m = 300;m = 100;}m = 100*/
}class A{static {System.out.println("A类静态代码初始化");m = 300;}static int m = 100;public A(){System.out.println("A类的无参构造初始化");}
}

主动引用和被动引用

主动引用

  1. new
  2. 反射

被动引用

  1. 子类直接调用父类
  2. 数组
  3. 加载常量
package reflection;// 测试类什么时候会初始化
public class Test05 {static {System.out.println("main类被加载");}public static void main(String[] args) throws ClassNotFoundException {// 1. 主动引用
//         Son son = new Son();// 2.反射也会产生主动引用
//        Class.forName("reflection.Son");// 3. 不会产生类的引用的方法// 3.1 子类直接调用父类
//        System.out.println(Son.b);// 3.2 数组
//        Son[] array = new Son[5];// 3.3 加载常量System.out.println(Son.M);}
}class Father{static int b = 2;static{System.out.println("父类被加载");}
}class Son extends Father{static {System.out.println("子类被加载");m = 300;}static int m = 100;static final int M = 1;
}

通过反射获得类的方法、属性

package reflection;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;// 获得类的信息
public class Test07 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {Class c1 = Class.forName("reflection.User");//        User user = new User();
//        c1 = user.getClass();// 获得类的名字System.out.println(c1.getName());  // 获得包名+类名System.out.println(c1.getSimpleName());  // 获得类名// 获得类的属性System.out.println("=========================================");Field[] fields = c1.getFields();  // 只能找到public属性fields = c1.getDeclaredFields();for(Field field: fields){System.out.println(field);}// 获得指定的属性Field name = c1.getDeclaredField("name");System.out.println(name);// 获得类的方法System.out.println("==========================================");Method[] methods = c1.getMethods();  // 获得本类及其父类的全部public方法for(Method method : methods){System.out.println("正常的"+method);}methods = c1.getDeclaredMethods();  // 获取本类的所有方法,包括私有for(Method method: methods){System.out.println("getDeclaredMethods:"+method);}// 获得指定方法Method getName = c1.getMethod("getName", null);Method setName = c1.getMethod("setName", String.class);System.out.println(getName);System.out.println(setName);// 获得指定的构造器System.out.println("===========================================");Constructor[] constructors = c1.getConstructors();for (Constructor constructor : constructors){System.out.println(constructor);}constructors = c1.getDeclaredConstructors();for (Constructor constructor : constructors){System.out.println("#"+constructor);}}
}

通过反射动态创建对象

package reflection;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;// 动态创建对象,通过反射
public class Test08 {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {// 获得Class对象Class c1 = Class.forName("reflection.User");// 1. 构造一个对象
//        User user = (User) c1.newInstance();  // 本质是调用了类的无参构造器
//        System.out.println(user);// 2. 通过构造器创建对象
//        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
//        User user2 =  (User)constructor.newInstance("alex", 1, 18);
//        System.out.println(user2);// 通过反射调用普通方法User user3 = (User)c1.newInstance();// 通过反射获取一个方法Method setName = c1.getDeclaredMethod("setName", String.class);setName.invoke(user3, "alex");System.out.println(user3.getName());// 通过反射操作属性System.out.println("==============================================");User user4 = (User)c1.newInstance();Field name = c1.getDeclaredField("name");name.setAccessible(true);  // 关掉安全检检测,操作私有属性name.set(user4, "alex2");System.out.println(user4.getName());}
}

性能

package reflection;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;// 性能比较
public class Test09 {public static void test01(){User user = new User();long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {user.getName();}long endTime = System.currentTimeMillis();System.out.println("普通方法执行耗时:"+ (endTime-startTime)+"ms");}public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName", null);long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user, null);}long endTime = System.currentTimeMillis();System.out.println("反射方式执行耗时:"+ (endTime-startTime)+"ms");}public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName", null);getName.setAccessible(true);long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user, null);}long endTime = System.currentTimeMillis();System.out.println("反射关掉安全校验方式执行耗时:"+ (endTime-startTime)+"ms");}public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {test01();test02();test03();}
}

通过反射获取泛型信息

package reflection;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 Test10 {public void test01(Map map, List list){System.out.println("test01");}public Map test02(){System.out.println("test02");return null;}public static void main(String[] args) throws NoSuchMethodException {Method method = Test10.class.getMethod("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);}}}System.out.println("=====================================================");method= Test10.class.getMethod("test02", null);Type genericReturnType = method.getGenericReturnType();if (genericReturnType instanceof ParameterizedType){Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();for(Type actualTypeArgument: actualTypeArguments){System.out.println(actualTypeArgument);}}}
}

通过反射获取注解

package reflection;import java.lang.annotation.*;
import java.lang.reflect.Field;// 反射操作注解
public class Test11 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {Class c1 = Class.forName("reflection.Student2");// 通过反射获得注解Annotation[] annotations= c1.getAnnotations();for(Annotation annotation : annotations){System.out.println(annotation);}// 获取注解的value的值TableAlex tableAlex = (TableAlex)c1.getAnnotation(TableAlex.class);String value = tableAlex.value();System.out.println(value);// 获得类指定的注解Field f = c1.getDeclaredField("id");FieldAlex annotation = f.getAnnotation(FieldAlex.class);System.out.println(annotation.columnName());System.out.println(annotation.type());System.out.println(annotation.length());}}@TableAlex("db_student")
class Student2{@FieldAlex(columnName = "db_id", type = "int", length = 10)private int id;@FieldAlex(columnName = "db_age", type = "int", length = 10)private int age;@FieldAlex(columnName = "db_name", type = "varchar", length = 3)private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Student2{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';}
}// 类名注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableAlex{String value();
}// 属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAlex{String columnName();String type();int length();
}

相关内容