1、註解(Annotation)
1.1 什麼是註解(Annotation)
註解不是程式本身,可以在程式編譯、類別載入和執行時被讀取,並執行相應的處理。註解的格式為"@註解名(參數值)",可以附加在套件、類別、方法和欄位上,透過反射機制實現註解的存取。
1.2 內建註解
@Override:限定子類別重寫方法
該註解表示覆寫的是其父類別的方法,當子當類別重寫父類別方法時,確保子類別確實重寫了父類別的方法,避免出現低階錯誤
/**
* 该注解标识覆盖的是其父类的方法,当子类重写父类方法时,确保子类确实重写了父类的方法,避免出现低级错误
* @return
*/
@Override
public String toString() {
return super.toString();
}
@Deprecated:標記已過時
##該註解表示某個屬性、方法或類別等已過時(程式設計師不鼓勵使用的程式元素,通常是因為它是危險的,或因為有更好的替代方法),當其他程式使用已過時的屬性、方法或類別時,編譯器會給予警告(刪除線)。
/**
* 该注解表示此方法已过时,存在危险,不推荐使用,其有代替方法,如果继续使用会通过删除线进行标识
*/
@Deprecated
public static void test() {
System.out.println("标记已过时");
}
@SuppressWarnings(參數):抑制編譯器警告
此註解作用的類別、方法和屬性會取消顯示編譯器警告,其參數主要是進行警告說明以及取消(unchecked)等。
@SuppressWarnings("取消此类的所有警告")
public class BuiltAnnotation {
@SuppressWarnings("取消此属性的警告")
private String username;
@SuppressWarnings("取消此方法的警告")
public static void main(String[] args) {
// ...
}
}
1.3 元註解(meta-annotation)
元註解的作用就是負責註解其他註解,Java定義了4個標準的元註解類型,他們被用來提供對其他註解的作用範圍及類型進行說明,透過元註解可以自訂其他註解。
@Target:描述註解的使用範圍
例如@Target(ElementType.METHOD)表示作用在方法上,@Target(ElementType.TYPE)表示作用在類別或介面上等
/**
* @Target注解:描述注解的使用范围
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* 类或接口:ElementType.TYPE;
* 字段:ElementType.FIELD;
* 方法:ElementType.METHOD;
* 构造方法:ElementType.CONSTRUCTOR;
* 方法参数:ElementType.PARAMETER;
* ...
*/
ElementType[] value();
}
@Retention:表示需要在什麼層級保存該註解訊息,用於描述註解的生命週期
通常自訂的註解都使用@Retention(RetentionPolicy.RUNTIME),也就是運行時期作用。
/**
* @Retention:表示需要在什么级别保存该注解信息,用于描述注解的生命周期
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* RetentionPolicy.SOURCE:仅编译期,注解将被编译器丢弃。
* RetentionPolicy.CLASS:仅class文件,注释将由编译器记录在类文件中,但VM不需要在运行时保留,如果不指定则默认为class。
* RetentionPolicy.RUNTIME:运行期,注释将由编译器记录在类文件中,并由VM在运行时保留,因此可以反射读取。通常自定义的注解都是RUNTIME。
* 范围:RUNTIME>CLASS>SOURCE
*/
RetentionPolicy value();
}
@Document:說明該註將被包含在javadoc中
@Iherited:定義子類別是否可繼承父類別定義的註解。
@Inherited僅針對@Target(ElementType.TYPE) 類型的註解有用,並且只能是class 的繼承,對interface 的繼承無效:
1.4 自訂註解
定義註解
/**
* 1. 使用@interface定义注解;
* 3. 通过元注解配置该注解,配置注解的使用范围和生命周期等
* @author Loner
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Report{
/**
* 2. 添加参数、默认值,如果没有默认值,就必须给参数赋值,一般把最常用的参数定义为value(),推荐所有参数都尽量设置默认值
* 形式为:参数类型 参数名();
*/
int type() default 0;
String value() default "LonerMJ";
}
使用註解
@Report(type = 1, value = "test")
public class CustomerAnnotation {
@Report(type = 1, value = "test")
public void testCustomerAnnotation() {
System.out.println("测试自定义注解");
}
}
2、反射(Reflection)
2.1 反射和反射機制
反射
Reflection(反射)是指程式在運行期可以拿到一個物件的所有資訊。
反射機制
反射機制是指程式在執行時,透過Reflection API取得任何類別的內容訊息,並能直接操作任何物件的內部屬性及方法。
2.2 Class類的取得方式和常用方法
java.lang.Class類,實現反射的核心類,類別載入完成之後,在堆記憶體的方法區中就會產生一個Class物件(一個類別只有一個Class物件),這個物件包含了類別的完整結構訊息,透過這個物件看到類別的結構。
Class類別的取得方式
public class InstantiationClass {
public static void main(String[] args) throws ClassNotFoundException {
Teacher teacher = new Teacher("张三", "123456");
// 方式一:调用Class类的静态方法forName(String className)
Class<?> c1 = Class.forName("com.loner.mj.reflection.Teacher");
// 方式二:已知某个类的实例,调用该实例的getClass()方法,getClass是Object类中的方法。
Class<? extends Teacher> c2 = teacher.getClass();
// 方式三:已知具体类,通过类的class属性获取,该方法最安全可靠,程序性能最高
Class<Teacher> c3 = Teacher.class;
// 方式四:通过基本内置类型的包装类的TYPE属性获得CLass实例
Class<Integer> c4 = Integer.TYPE;
// 方式五:通过当前子类的Class对象获得父类的Class对象
Class<?> c5 = c1.getSuperclass();
}
}
Class類別的常用方法
方法名稱 | 方法功能 |
static Class forName(String name) | 傳回指定類別名稱的Class物件 |
Obiect newInstance() | 呼叫無參構函數,傳回Class物件的一個實例 |
String getName() | 傳回此Class物件所表示的實體(類,接口,陣列類別或void)的名稱 |
Class getSuperclass() | 傳回目前Class物件的父類別的Class對象 |
Class[] getinterfaces() | 傳回目前Class物件的介面 |
ClassLoader getClassLoader() | 傳回該類別的類別載入器 |
Method getDeclareMethod(String name, Class6b3d0130bba23ae47fe2b8e8cddf0195 ... parameterTypes) | 取得方法名稱和參數清單相符的方法 |
Method[] getDeclareMethods() | #取得所有非繼承的方法 |
##Method[] getMethods()
取得所有非私有方法 |
|
Field getDeclareField(String name)
取得指定屬性 |
|
Field [] getDeclareFields()
取得所有屬性 |
|
#Field[] getFields()
取得所有非私有屬性 |
|
Constructor getConstructor(Class6b3d0130bba23ae47fe2b8e8cddf0195... parameterTypes
取得參數清單匹配的建構方法 |
|
Constructor getConstructors()
取得類別的所有建構方法 |
|
A getAnnotation(Class6b3d0130bba23ae47fe2b8e8cddf0195 annotationClass)
傳回指定註解 |
|
#Annotation[] getDeclaredAnnotations()
傳回所有註解 |
|
#public class ReflectionMethods {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
Class<Worker> workerClass = Worker.class;
/**
* 类
*/
System.out.println(workerClass.getName());
System.out.println(workerClass.getSimpleName());
System.out.println(workerClass.getSuperclass());
System.out.println(workerClass.getPackage());
Class<?>[] interfaces = workerClass.getInterfaces();
for (Class<?> i : interfaces) {
System.out.println(i);
}
/**
* 属性
*/
// 获取所有的属性
Field[] declaredFields = workerClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
// 获取指定属性
System.out.println(workerClass.getDeclaredField("username"));
// 获取所有公共属性
Field[] fields = workerClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
/**
* 构造方法
*/
// 获取所有构造方法
Constructor<?>[] declaredConstructors = workerClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
// 获取指定的构造方法
System.out.println(workerClass.getDeclaredConstructor(String.class, String.class));
/**
* 方法
*/
// 获取所有的方法
Method[] declaredMethods = workerClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
// 获取指定方法
System.out.println(workerClass.getDeclaredMethod("getUsername", null));
// 获取所有功能方法
Method[] methods = workerClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
哪些类型具有Class对象
public class InstantiationClass {
public static void main(String[] args) throws ClassNotFoundException {
// 类(外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。)
Class<Object> objectClass = Object.class;
// 接口
Class<Comparable> comparableClass = Comparable.class;
// 数组
Class<String[]> stringClass = String[].class;
Class<int[][]> intClass = int[][].class;
// 枚举
Class<ElementType> elementTypeClass = ElementType.class;
// 注解
Class<Override> overrideClass = Override.class;
// 基本数据类型
Class<Integer> integerClass = Integer.class;
// void
Class<Void> voidClass = void.class;
// Class
Class<Class> classClass = Class.class;
}
}
2.3 反射的使用
反射操作对象
public class UseClass {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class<User> userClass = User.class;
/**
* 通过构造器实例化对象:不使用构造器,默认通过无参构造进行对象创建
*/
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
User user = declaredConstructor.newInstance("张三", "123456");
System.out.println(user);
/**
* 调用方法并执行相关操作
*/
Method setUsername = userClass.getDeclaredMethod("setUsername", String.class);
// invoke(Object, 参数):激活,即执行相关操作为该对象
setUsername.invoke(user, "李四");
Method setPassword = userClass.getDeclaredMethod("setPassword", String.class);
setPassword.invoke(user, "123456");
System.out.println(user);
/**
* 操作属性:通过反射直接操作私有属性会报错,需要通过setAccessible(ture)关闭访问安全检查,此方法属性、方法和构造都具有,会影响效率
*/
Field username = userClass.getDeclaredField("username");
username.setAccessible(true);
username.set(user, "用户名");
System.out.println(user);
}
}
反射操作泛型
Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题。但是,一旦编译完成,所有和泛型有关的类型全部擦除。
为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable:是各种类型变量的公共父接口
WildcardType:代表一种通配符类型表达式
public class ClassOperateGenerics {
public Map<String, String> list() {
System.out.println("返回值是泛型");
return new HashMap<>();
}
public void test(Map<String, User> map, List<Integer> list) {
System.out.println("参数是泛型");
}
public static void main(String[] args) throws NoSuchMethodException {
/**
* 获取方法参数的泛型
*/
Method method = ClassOperateGenerics.class.getMethod("test", Map.class, List.class);
// 获取所有方法参数的泛型
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
// java.util.Map<java.lang.String, com.loner.mj.reflection.User>
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
// 获取所有泛型的真实参数
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
// String, User, Integer
System.out.println(actualTypeArgument);
}
}
}
/**
* 获取方法返回值的泛型
*/
Method list = ClassOperateGenerics.class.getMethod("list", null);
// 获取方法返回值的泛型
Type genericReturnType = list.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
// 获取所有泛型的真实参数
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
反射操作注解
public class ClassOperateAnnotation {
public static void main(String[] args) throws NoSuchFieldException {
Class<People> peopleClass = People.class;
// 获取类的所有注解
Annotation[] declaredAnnotations = peopleClass.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println(declaredAnnotation);
}
// 获取类的注解的值
Table declaredAnnotation = peopleClass.getDeclaredAnnotation(Table.class);
System.out.println(declaredAnnotation.value());
// 获取属性的注解
Field name = peopleClass.getDeclaredField("name");
Fields annotation = name.getAnnotation(Fields.class);
System.out.println(annotation.name());
}
}
以上是Java中的註解與反射怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!