Java 注解和反射 - 总结概述
注解
什么是注解
- Annotation是从JDK5.0开始引入的新技术
- Annotation的作用:
- 不是程序本身,可以对程序作出解释(这一点和注释(comment)没什么区别)
- 可以被其他程序(比如:编译器等)读取
- Annotation的格式:
- 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:@SuppressWarnings(value="unchecked")
- Annotation在哪里使用?
- 可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问
内置注解
- @Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
- @Deprecated:定义在java.lang.Deprecated中,此注释可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择
- @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了
- @SuppressWarinings("all")
- @SuppressWarinings("unchecked")
- @SuppressWarinings(value={"unchecked","deprecation"})
- 等等.......
1 //什么是注解2 public class Test01 extends Object {
3
4 //@Override 重写的注解
5 @Override
6 public String toString() {
7 return super.toString();
8 }
9
10 //Deprecated 不推荐程序员使用,但是可以使用,或者存在更好的方式
11 @Deprecated
12 public static void test(){
13 System.out.println("Deprecated");
14 }
15
16 //镇压警告
17 @SuppressWarnings("all")
18 public void test02(){
19 List list = new ArrayList();
20 }
21 public static void main(String[] args) {
22 test();
23 }
24 }
元注解
- 元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明
- 这些类型和它们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inherited)
@Target:用来描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Retention:表示需要在什么级别保存该注释信息,用来描述注解的生命周期(SOURCE<CLASS<RUNTIME)
- @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
1 public class Test02 {2
3 @MyAnnotation
4 public void test(){
5 }
6 }
7
8 //定义一个注解
9 //Target 表示我们的注解可以用在哪些地方:ElementType.METHOD(用在方法上),ElementType.TYPE(可以用在类上)
10 @Target(value = {ElementType.METHOD,ElementType.TYPE})
11
12 //Retention 表示我们的注解在什么地方有效;RUNTIME:运行时,CLASS:编译,SOURCE:源码
13 //runtime>class>source
14 @Retention(value = RetentionPolicy.RUNTIME)
15
16 //Documented 表示是否将我们的注解生成在JavaDoc文档中
17 @Documented
18
19 //Inherited 子类可以继承父类的注解
20 @Inherited
21 @interface MyAnnotation{}
自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
- 分析:
- @interface用来声明一个注解,格式:public @interface 注解名{定义内容}
- 其中的每一个方法实际上是声明了一个配置参数
- 方法的名称就是参数的名称
- 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value
- 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
1 //自定义注解2 public class Test03 {
3
4 @MyAnnotation02(age = 18,name = "张三")
5 public void test(){}
6
7 @MyAnnotation03("李四")
8 public void test02(){}
9 }
10
11 @Target({ElementType.TYPE,ElementType.METHOD})
12 @Retention(RetentionPolicy.RUNTIME)
13 @interface MyAnnotation02{
14 //注解的参数格式:参数类型 + 参数名();
15 String name() default ""; //default默认该参数为空,使用该注解,此参数不需要必传
16 int age();
17 int id() default -1;//如果默认值为-1,代表不存在
18 String[] schools() default {"北京大学"};
19 }
20
21 @Target({ElementType.TYPE,ElementType.METHOD})
22 @Retention(RetentionPolicy.RUNTIME)
23 @interface MyAnnotation03{
24 String value(); //注解只有一个参数的时候,建议参数名为value,这样使用该注解时,就不需要在输入参数名,直接输入值即可
25 }
反射
静态VS动态语言
动态语言
- 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点讲就是在运行时代码可以根据某些条件改变自身结构
- 主要动态语言:Object-C、C#、JavaScript、PHP、Python等
静态语言
- 与动态语言相对应的,运行时结构不可变的语言就是静态语言。如:Java、C、C++
- Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活
Java Reflection反射
- Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
- Class c = Class.forName("java.lang.String")
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,通过这个镜子看到类的结构,所以,我们形象的称之为:反射
- Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
- .....
- Java反射的优点:可以实现动态创建对象和编译,体现出很大的灵活性
- Java反射的缺点:对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作
- 反射相关的主要API
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
- .......
1 //什么叫反射2 public class Test01 {
3 public static void main(String[] args) throws ClassNotFoundException {
4 //通过反射获取类的class对象
5 Class c1 = Class.forName("reflection.User");
6 System.out.println(c1);
7
8 Class c2 = Class.forName("reflection.User");
9 Class c3 = Class.forName("reflection.User");
10 Class c4 = Class.forName("reflection.User");
11
12 //一个类在内存中只有一个class对象
13 //一个类被加载后,类的整个结构都会被封装在class对象中
14 System.out.println(c2.hashCode());
15 System.out.println(c3.hashCode());
16 System.out.println(c4.hashCode());
17 }
18 }
19
20 //实体类:pojo,entity
21 class User{
22 private String name;
23 private int id;
24 private int age;
25
26 public User() {
27 }
28
29 public User(String name, int id, int age) {
30 this.name = name;
31 this.id = id;
32 this.age = age;
33 }
34
35 @Override
36 public String toString() {
37 return "User{" +
38 "name='" + name + '\'' +
39 ", id=" + id +
40 ", age=" + age +
41 '}';
42 }
43
44 public String getName() {
45 return name;
46 }
47
48 public void setName(String name) {
49 this.name = name;
50 }
51
52 public int getId() {
53 return id;
54 }
55
56 public void setId(int id) {
57 this.id = id;
58 }
59
60 public int getAge() {
61 return age;
62 }
63
64 public void setAge(int age) {
65 this.age = age;
66 }
67 }
得到Class类的几种方式
1 //测试class类的创建方式有哪些2 public class Test02 {
3 public static void main(String[] args) throws ClassNotFoundException {
4 Person person = new Student();
5 System.out.println("这个人是:"+person.name);
6
7 //方式一:通过对象获得
8 Class c1 = person.getClass();
9 System.out.println(c1.hashCode());
10
11 //方式二:forname获得
12 Class c2 = Class.forName("reflection.Student");
13 System.out.println(c2.hashCode());
14
15 //方式三:通过类名.class获得
16 Class c3 = Student.class;
17 System.out.println(c3.hashCode());
18
19 //方式四:基本内置类型的包装类都有一个Type属性
20 Class c4 = Integer.TYPE;
21 System.out.println(c4);
22
23 //获得父类类型
24 Class c5 = c1.getSuperclass();
25 System.out.println(c5);
26 }
27 }
28
29 class Person{
30 public String name;
31
32 public Person() {
33 }
34
35 public Person(String name) {
36 this.name = name;
37 }
38
39 @Override
40 public String toString() {
41 return "Person{" +
42 "name='" + name + '\'' +
43 '}';
44 }
45 }
46
47 class Student extends Person{
48 public Student(){
49 this.name="学生";
50 }
51 }
52
53 class Teacher extends Person{
54 public Teacher(){
55 this.name="老师";
56 }
57 }
所有类型的Class对象
1 //所有类型的class2 public class Test03 {
3 public static void main(String[] args) {
4 Class c1 = Object.class; //类
5 Class c2 = Comparable.class; //接口
6 Class c3 = String[].class; //一维数组
7 Class c4 = int[][].class;//二维数组
8 Class c5 = Override.class;//注解
9 Class c6 = ElementType.class;//枚举
10 Class c7 = Integer.class;//基本数据类型
11 Class c8 = void.class;//void
12 Class c9 = Class.class;//Class
13
14 System.out.println(c1);
15 System.out.println(c2);
16 System.out.println(c3);
17 System.out.println(c4);
18 System.out.println(c5);
19 System.out.println(c6);
20 System.out.println(c7);
21 System.out.println(c8);
22 System.out.println(c9);
23
24 //只要元素类型与维度一样,就是同一个Class
25 int[] a = new int[10];
26 int[] b = new int[100];
27 System.out.println(a.getClass().hashCode());
28 System.out.println(b.getClass().hashCode());
29 }
30 }
获取类的运行时结构
1 //反射的作用:获得类的信息2 public class Test08 {
3 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
4 Class c1 = Class.forName("reflection.User");
5
6 //1.获得类的名字
7 System.out.println(c1.getName()); //类名+包名
8 System.out.println(c1.getSimpleName());//类名
9
10 //2.获得类的属性
11 //2.1只能找到public属性
12 Field[] fields = c1.getFields();
13 for(Field f : fields){
14 System.out.println(f);
15 }
16 //2.2可以找到所有属性
17 Field[] fields1 = c1.getDeclaredFields();
18 for(Field f : fields1){
19 System.out.println(f);
20 }
21 //2.3只能找到public的指定属性
22 Field top = c1.getField("top");
23 System.out.println(top);
24 //2.4找到类的指定属性
25 Field name = c1.getDeclaredField("name");
26 System.out.println(name);
27
28 //3.获得类的方法
29 //3.1 获得本类及其父类的全部public方法
30 Method[] methods = c1.getMethods();
31 for (Method method : methods) {
32 System.out.println(method);
33 }
34 //3.2 获得本类的所有方法
35 Method[] declaredMethods = c1.getDeclaredMethods();
36 for (Method declaredMethod : declaredMethods) {
37 System.out.println(declaredMethod);
38 }
39 //3.3 获得指定的方法
40 //获得指定方法一定要加参数,因为牵扯到方法的重载,方法名一样,参数不一样;不传参数,不知道你要获得哪个方法;参数丢类型即可
41 Method getName = c1.getMethod("getName", null);
42 Method setName = c1.getMethod("setName", String.class);
43 System.out.println(getName);
44 System.out.println(setName);
45
46 //4.获得指定的构造器
47 //4.1 获得本类public的构造方法
48 Constructor[] constructors = c1.getConstructors();
49 for (Constructor constructor : constructors) {
50 System.out.println(constructor);
51 }
52 //4.2 获得本类所有的构造方法
53 Constructor[] declaredConstructors = c1.getDeclaredConstructors();
54 for (Constructor declaredConstructor : declaredConstructors) {
55 System.out.println(declaredConstructor);
56 }
57 //4.3 获得指定的构造器
58 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
59 System.out.println(declaredConstructor);
60 }
61 }
62
63
64 //实体类:pojo,entity
65 class User{
66 private String name;
67 private int id;
68 private int age;
69
70 public int top=180;
71
72 public User() {
73 }
74
75 public User(String name, int id, int age) {
76 this.name = name;
77 this.id = id;
78 this.age = age;
79 }
80
81 @Override
82 public String toString() {
83 return "User{" +
84 "name='" + name + '\'' +
85 ", id=" + id +
86 ", age=" + age +
87 '}';
88 }
89
90 public String getName() {
91 return name;
92 }
93
94 public void setName(String name) {
95 this.name = name;
96 }
97
98 public int getId() {
99 return id;
100 }
101
102 public void setId(int id) {
103 this.id = id;
104 }
105
106 public int getAge() {
107 return age;
108 }
109
110 public void setAge(int age) {
111 this.age = age;
112 }
113 }
动态创建对象执行方法
1 //动态的创建对象,通过反射2 public class Test09 {
3 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
4 //获得class对象
5 Class c1 = Class.forName("reflection.User");
6
7 //构造一个对象
8 //User user = (User) c1.newInstance(); //本质上是调用了类的无参构造器。如果类没有无参构造器则会报错
9 //System.out.println(user);
10
11 //如果类没有无参构造器,怎么办?
12 //通过构造器创建对象
13 //Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
14 //User user1 = (User) constructor.newInstance("张三", 001, 20);
15 //System.out.println(user1);
16
17 //通过反射调用普通方法
18 User user2 = (User) c1.newInstance();
19 //通过反射获取一个方法
20 Method setName = c1.getDeclaredMethod("setName", String.class);
21
22 //invoke:激活的意思
23 //(对象,“方法的值”)
24 setName.invoke(user2,"Gelaotou");
25 System.out.println(user2.getName()); //Gelaotou
26
27 //通过反射操作属性
28 User user3 = (User) c1.newInstance();
29 Field name = c1.getDeclaredField("name");//由于name是private私有属性,所以会报错
30
31 //不能直接操作私有属性,需要关闭程序的安全检测,私有的属性和方法使用setAccessible(true)关闭检测
32 name.setAccessible(true);//关闭程序的安全检测
33
34 name.set(user3,"张三");
35 System.out.println(user3.getName());
36 }
37 }
1 //性能对比分析2 public class Test10 {
3
4 //普通方式调用
5 public static void test01(){
6 User user = new User();
7 long startTime=System.currentTimeMillis();
8 for (int i = 0; i < 100000000; i++) {
9 user.getName();
10 }
11
12 long endTime=System.currentTimeMillis();
13 System.out.println("普通方式执行,花费的时间为:"+(endTime-startTime)+"ms");
14 }
15
16 //反射方式调用
17 public static void test02() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
18 User user = new User();
19 Class c1 = user.getClass();
20
21 Method getName = c1.getDeclaredMethod("getName",null);
22
23 long startTime=System.currentTimeMillis();
24
25 for (int i = 0; i < 100000000; i++) {
26 getName.invoke(user,null);
27 }
28
29 long endTime=System.currentTimeMillis();
30 System.out.println("反射方式调用执行,花费的时间为:"+(endTime-startTime)+"ms");
31 }
32
33 //反射方式调用 关闭检测
34 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
35 User user = new User();
36 Class c2 = user.getClass();
37
38
39 Method getName = c2.getDeclaredMethod("getName", null);
40 getName.setAccessible(true);
41
42 long startTime=System.currentTimeMillis();
43
44 for (int i = 0; i < 100000000; i++) {
45 getName.invoke(user,null);
46 }
47
48 long endTime=System.currentTimeMillis();
49 System.out.println("反射方式调用 关闭检测执行,花费的时间为:"+(endTime-startTime)+"ms");
50
51 }
52
53 public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
54 test01(); //2ms
55 test02(); //216ms
56 test03(); //111ms
57
58 //总结:反射调用过多,关闭检测,可以提高性能
59 }
60 }
类加载内存分析
1 public class Test05 {2 public static void main(String[] args) {
3 A a = new A();
4 System.out.println(a.m);
5 /*
6 1.加载到内存,会产生一个类对应class对象
7 2.链接,链接结束后,m=0
8 3.初始化
9 <clinit>(){
10 System.out.println("A类静态代码块初始化");
11 m=300;
12 m=100;
13 }
14 m=100
15 */
16 }
17 }
18
19 class A{
20
21 static {
22 System.out.println("A类静态代码块初始化");
23 m=300;
24 }
25 static int m =100;
26
27 public A() {
28 System.out.println("A类的无参构造初始化");
29 }
30 }
1 //运行结果2 A类静态代码块初始化
3 A类的无参构造初始化
4 100
分析类的初始化
1 //测试类什么时候会初始化2 public class Test06 {
3 static {
4 System.out.println("Test06类静态代码块被加载");
5 }
6
7 public static void main(String[] args) throws ClassNotFoundException {
8 //1.主动引用
9 //Son son = new Son();
10 /*
11 //输出结果:
12 Test06类静态代码块被加载
13 父类静态代码块被加载
14 子类静态代码块被加载
15 */
16
17 //2.反射也会产生主动引用
18 //Class.forName("reflection.Son");
19 /*
20 //输出结果:
21 Test06类静态代码块被加载
22 父类静态代码块被加载
23 子类静态代码块被加载
24 */
25
26 //3.类的被动引用,通过子类调用父类的静态变量,不会导致子类的初始化
27 //System.out.println(Son.b);
28 /*
29 //输出结果,不会导致子类的初始化:
30 Test06类静态代码块被加载
31 父类静态代码块被加载
32 2
33 */
34
35 //4.类的被动引用,通过数组,不会导致类的任何初始化
36 //Son[] array=new Son[5];
37 /*
38 //输出结果:
39 Test06类静态代码块被加载
40 */
41
42 //5.类的被动引用,访问常量,不会导致类的任何初始化
43 System.out.println(Son.n);
44 /*
45 //输出结果:
46 Test06类静态代码块被加载
47 1
48 */
49 }
50 }
51
52 class Father{
53 static int b = 2;
54 static {
55 System.out.println("父类静态代码块被加载");
56 }
57 }
58
59 class Son extends Father{
60 static {
61 System.out.println("子类静态代码块被加载");
62 m=300;
63 }
64
65 static int m=100;
66 static final int n=1;
67 }
类加载器
1 public class Test07 {2 public static void main(String[] args) throws ClassNotFoundException {
3 //获取系统类的加载器
4 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
5 System.out.println(systemClassLoader);
6
7 //获取系统类加载器的父类加载器--->即扩展类加载器
8 ClassLoader parent = systemClassLoader.getParent();
9 System.out.println(parent);
10
11 //获取扩展类加载器的父类加载器--->即根加载器(C、C++)
12 ClassLoader parent1 = parent.getParent();
13 System.out.println(parent1);
14
15 //测试当前类是哪个加载器加载的
16 ClassLoader aClass = Class.forName("reflection.Test07").getClassLoader();
17 System.out.println(aClass);
18 //测试JDK内置的类是谁加载的
19 ClassLoader aClass1 = Class.forName("java.lang.Object").getClassLoader();
20 System.out.println(aClass1);
21
22 //如何获得系统类加载器可以加载的路径
23 System.out.println(System.getProperty("java.class.path"));
24 }
25 }
以上是 Java 注解和反射 - 总结概述 的全部内容, 来源链接: utcz.com/z/391359.html