反射和注解

反射和注解

【摘要】反射和注解~

前言

反射

JDK5.0中推出的一个技术点,它的目的就是通过字节码来窥探类的结构。
通过反射,我们可以分析一个类的字节码,并且也可以通过这种方式来调用和修改方法、属性。

1
2
3
4
5
6
7
8
9
10
11
API:
java.lang
\- Class
\- Package
java.lang.reflect 包
\- Array 针对数类型的反射工具类
\- Modifier 修饰符
\- AccessibleObject
\- Constructor 构造
\- Method 方法
\- Field 属性

在学习反射API之前,首先,我们得重新学习 java.lang.Class。这个类,从名字上知道,它是“类”的意思,它是表示 类型的类。这个类是反射的入口[基础]。

所有的类型一旦被JVM加载成功后,都是Class的实例,并且一个类型只有唯一的Class实例。

比如:
Teacher类型在JVM中的类型是:Class
Account类型在JVM中的类型是:Class

不管你创建了多少个Teacher的对象,这些对象在JVM中都共享相同的Class实例

如:

1
2
3
4
Teacher t1 = new Teacher();
Teacher t2 = new Teacher();
//
System.out.println(t1.getClass() == t2.getClass()); //true

获取某个类型在JVM中的Class实例,有如下三种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//1. 通过类名.class 来获取
Class<Teacher> c = Teacher.class;

//2. 通过对象来获取
Teacher t1 = new Teacher();
Class<Teacher> c = t1.getClass();

//3. 通过Class中的一个静态方法 forName
如:
Class<Teacher> c = Class.forName("Teacher全限定名 ");

//例如:
public class A {
void ma() { ... }
void ma(int a, int b) { ... }
void mb(double a, double b) { ... }
}
Class<A> c = A.class;
Method m1 = c.getDeclaredMethod("ma",Integer.class, Integer.TYPE);
Method m2 = c.getDeclaredMethod("ma");

下面再来看一段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//1.普通方式创建一个对象
Account a = new Account();

//2.通过反射来创建对象
Class<Account> c = Class.forName("com.xx.xxx.Account");
Account a = c.newInstance();

public class XXXFactory {
public static XXX getInstance() {
//通过反射 来创建
String cName = ""; //也可以从文件中读取[io流]
Class<XXX> c = Class.forName(cName);
return c.newInstance();
}
}
//name.txt [大量的配置文件] 可配置[configurable]
//com.xx.xx.XXXImpl2

练习:
写一个StringUtil类,存放在 util 包中,这里面有如下方法:

1
2
3
4
5
6
7
8
public class StringUtil {
//通用的toString方法,此方法打印出指定对象中的所有
//属性,格式为:类名[属性名=属性值,属性名=属性值,...]
public static String toString(Object obj) {
//使用反射去实现
//...
}
}

注解

注解[Annotation]:它也是一种数据类型,与类、接口、枚举一起,是java中4大类型之一。

类 class
接口 interface
枚举 enum
注解 @interface

注:
所有的自定义注解都自动继承于 java.lang.annotation.Annotation 接口,而注解在编译完成后,也是字节码,所以,它在JVM中也是Class的实例。
如:Class<? extends Annotation>

注解的目的是用来描述数据,更确切地讲,是用代码的方式来描述数据。

如:

1
2
3
4
//限定这个注解将来可以使用在哪些元素上
public @interface HaHa {
String name() default "ZhangYao";
}

注:开发注解时,元素的类型只能是:基本类型、字符串、注解、枚举、它们的数组类型。
注:

注解开发出来本身是不会产生功能的,它必需要被其它的元素”使用”,哪些元素可以使用注解呢?

类、属性、方法、局部变量、包、…

当然,你开发注解时,是需要事先指定此注解将来要用在哪些元素上的。
这个,你需要使用 元注解 来限定。

元注解,就是用来注解的注解。[修饰注解的]

API中提供了以下几个元注解:

@Target 只有一个元素,名为 value
@Retention 只有一个元素,名为 value
@Documented 标记注解

使用注解的语法:

根据你要用的注解的API,查看此注解有哪些元素?

没有元素的注解叫 标记注解
只有1个元素的注解,一般来说,都会把元素名取为 value
有多个元素的注解,就是普通注解

根据元素的类型,使用不同的格式,如:

String 直接使用 “” 括起来
基本类型 直接使用 字面量
枚举类型 直接使用 枚举常量值
注解类型 使用 @注解名
数组类型 使用 {} 括起来,多个元素之间使用, 号隔开

注:我们开发好注解,这个注解本身并不产生作用。
要让注解产生作用,要编写注解的解析/处理程序,这个程序就叫 APT,Annotation Parse/Process Tools。

如何开发APT?

基于反射。

1
2
3
4
5
6
7
8
9
10
API:
java.lang.reflect.AnnotatedElement 接口
方法:
Annotation[] getDeclaredAnnotations();
Annotation[] getAnnotations(); //包含从父类继承的
boolean isAnnotationPresent(Class<? extends Annotation> c);
<T extends Annotation> T getAnnotation(Class<T> c);

java.lang.annotation.Annotation 接口
Class<? extends Annotaion> annotationType();

注:
默认情况下,父类中所加的注解并不能被子类所继承。除非这个注解使用了@Inherited 元注解去限定。

如:

1
2
3
4
5
6
7
8
@HaHa
public class A {

}

public class B extends A {

}

可以看出,B类没有加 @Haha注解,但是,如果在 Haha注解中,使用了:@Inherited修饰的话,则B类中将也可以获取 @HaHa注解。

结束语

还没有结束哦~

评论