接口
- 一个类可以实现多个接口
- 不同于类,一个接口可以extends多个接口
- 当实现的多个接口中有同名方法时(名+参数),编译不报错,但可能会导致一些问题,需考虑改变设计
- 当实现的接口中有同名方法且其中一个方法为default方法时,此时类必须实现该方法,否则编译报错
- 成员变量必须被初始化(仅static修饰的变量可以不用定义初值,仅final修饰的变量如果无初值则需在默认构造器中赋值)
//源码
public interface TestInterface1 {
int i = 1;
String a = "test";
void test();
default void test2() {
System.out.println(a);
}
}
//反编译后
//没用public修饰则默认包访问权限
//接口类的访问标识 flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
public interface utils.TestInterface1 {
//接口中所有常量都被默认修饰为public static final
//接口中所有方法都被默认修饰为public abstract
public static final int i;
public static final java.lang.String a;
public abstract void test();
/**
*default方法未被修饰为abstract
*jdk1.8之后接口中出现default修饰方法的原因如下
*当向某个接口添加方法时,所有实现该接口的类都需实现该方法,不符合开闭原则
*使用default修饰后,类不再必须实现改方法(如果没有显示覆盖则使用接口中定义的默认实现方式)
*/
public void test2();
}
注解
概念
Java提供的一种原程序中的元素关联任何信息和任何元数据的途径和方法,jdk1.5之后添加
本质
注解的本质还是接口,继承至Annotation接口
关键字
@interface
Annotation
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
//返回此注解的注释类型。
Class<? extends Annotation> annotationType();
}
举例说明
//源码
public @interface TestAnnotation1 {
int age = 10;
String name();
}
//反编译
//类访问标识:flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION,与接口的标识相比多了一个Annotation来标识注解
public interface utils.TestAnnotation1 extends java.lang.annotation.Annotation {
//字段和方法的默认修饰符与接口一致
public static final int age;
public abstract java.lang.String name();
}
与枚举类型类似编译器自动为注解类继承了Annotation接口
在对注解有了基本认识再来看看常见的注解分类
JDK中预定义注解
@Override
检查被标识的方法是否继承自父类或接口
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Deprecated
标识的目标被弃用,已有新的代替
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
标示了该注解的范围对应jvm中的属性会添加如下属性
@SuppressWarnings
阻止编译器发出警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
元注解
用于描述注解的注解
@Target
定义注解的作用范围
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
ElementType为一个枚举类型,用来描述注解作用范围
public enum ElementType {
/** 类、接口、注解、枚举 */
TYPE,
/** 字段 */
FIELD,
/** 方法 */
METHOD,
/** 方法参数 */
PARAMETER,
/** 构造函数 */
CONSTRUCTOR,
/** 本地变量 */
LOCAL_VARIABLE,
/** 与TYPE区别为该类型只能作用注解类型 */
ANNOTATION_TYPE,
/** 包 */
PACKAGE,
/**
* 类型参数声明,可用于泛型声明处
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 包括类型声明和类型参数声明
*
* @since 1.8
*/
TYPE_USE
}
@Retention
描述注解被保留的阶段
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
RetentionPolicy 为一个枚举变量,描述注解保留阶段
public enum RetentionPolicy {
/**
* 注解仅存在于源码中,被编译器遗弃
*/
SOURCE,
/**
* 默认保留方式,在编译后的class文件中存在,但在运行时无法获得
*/
CLASS,
/**
* 注解在运行时可以通过反射获得
*/
RUNTIME
}
@Document
描述注解是否被抽取到api文档中 使用javadoc生成后能够看到
@Inherited
描述注解是否被子类继承
自定义注解
public @interface TestAnnotation1 {
String name();
int age() default 18;
String[] interest();
}
//使用 @TestAnnotation1(name="king",age=10(可选),interest={"Basketball","Book"})
- 注解方法中的返回类型只能为基本类型、String、enum、annotation及这4种的数组类型
- 当注解存在value方法时,注解传入参数不用指定对应值
- 如果使用default,则在使用注解时可以不用赋值
- 如果传入参数为数组则需使用{}包裹,只有一个元素可取消
- 注解中的方法不能带参数
对应注解在class字节码中的显示
@TestAnnotation1(name = "king",age=10,interest = {"A","B"})
@Deprecated
public void test(){
//测试方法
}
对应该方法注解的字节码
表明此方法上存在两个注解分别在常量池#17和#25
注解的解析
解析注解常见方法
package java.lang.reflect;
public interface AnnotatedElement {
//实现类:class,method,field,constructor,parameter
// 获取某个具体类型的注解
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
// 判断某个对象上是否被某个注解标识
default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return getAnnotation(annotationClass) != null;
}
// 返回此元素上存在的注解。
Annotation[] getAnnotations();
// 返回直接存在于此元素上的注解。
Annotation[] getDeclaredAnnotations();
//返回与此元素相关联的注解
default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
//返回该元素上指定类型的元素注解,否则返回null。 此方法忽略继承的注解。
default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
//如果此类注解直接存在或间接存在,则返回该元素的注解(指定类型)。
default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
}