1.1 反射
- 反射API 入门: The Reflection API
2. 反射的优点
• 可扩展性 :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
• 类浏览器和可视化开发环境 :一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
• 调试器和测试工具 : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。
3. 反射的缺点:
• 性能开销 :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
• 安全限制 :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
• 内部暴露 :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
1.2 泛型
- Java 泛型 <? super T> 中 super 怎么 理解?与 extends 有何不同?
- 上界<? extends T>不能往里存,只能往外取,适合频繁往外面读取内容的场景。
- 下界<? super T>不影响往里存,但往外取只能放在Object对象里,适合经常往里面插入数据的场景。
- 泛型不能用于显式地引用运行时类型的操作之中,如:上下转型、instanceof操作、 和new 表达式
- 重载问题: 由于擦除的原因,重载方法将产生相同的类型签名
- 泛型提供了编译期的类型安全,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。
1.3注解
- 注解(Annotation),也叫元数据; 它是JDK1.5及以后版本引入的一个特性
- 元注解
- @Documented – 注解是否将包含在JavaDoc中
- @Retention – 什么时候使用该注解
- @Target – 注解用于什么地方
- @Inherited – 是否允许子类继承该注解
@Retention – 定义该注解的生命周期
- RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
- RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
- RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括
- ElementType.CONSTRUCTOR: 用于描述构造器
- ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
- ElementType.LOCAL_VARIABLE: 用于描述局部变量
- ElementType.METHOD: 用于描述方法
- ElementType.PACKAGE: 用于描述包
- ElementType.PARAMETER: 用于描述参数
- ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明
- Java8 中新增的注解特性: 重复注解 @Repeatable
声明一个可重复的注解
//@Repeatable 元注解指定用来存储可重复注解的容器; Schedules是一个注解
@Repeatable(Schedules.class)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
声明存储可重复注解的容器注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
Schedule[] value();
}
使用注解 ```java //Java8之前使用重复注解 @Schedules({@Schedule(dayOfMonth = “second”), @Schedule(dayOfMonth = “third”)}) public void doPeriodicCleanup() {…}
//Java8 //在编译后,方法doPeriodicCleanup上的注解如下(java8前的声明一样) //@java8.repeatAnnotation.Schedules({@java8.repeatAnnotation.Schedule(dayOfMonth = “last”), @java8.repeatAnnotation.Schedule(dayOfWeek = “Fri”, hour = 25)}) @Schedule(dayOfMonth=”last”) @Schedule(dayOfWeek=”Fri”, hour=”23”) public void doPeriodicCleanup() { … }
- 获取方法上的注解
```java
Method method = RepeatableAnnotationTest.class.getDeclaredMethod("doPeriodicCleanup");
//java 1.5 T getAnnotation(Class<T> annotationClass)
Schedules schedules1 = method.getAnnotation(Schedules.class);
//java 1.8 T[] getAnnotationsByType(Class<T> annotationClass)
Schedule[] schedules2 = method.getAnnotationsByType(Schedule.class);