(一)什么是注解?
注解相当于一种标记,在程序中添加注解就等于为程序打上了某种标记。程序可以利用java的反射机制来了解你的类及各种元素上有无何种标记,针对不同的标记,就去做相应的事件。
(二)java内建注解
@Override当我们想要复写父类中的方法时,我们需要使用该注解去告知编译器我们想要复写这个方法。这样一来当父类中的方法移除或者发生更改时编译器将提示错误信息。
@Deprecated 当我们希望编译器知道某一方法不建议使用时,我们应该使用这个注解。Java在javadoc 中推荐使用该注解,我们应该提供为什么该方法不推荐使用以及替代的方法。
@SuppressWarnings 这个仅仅是告诉编译器忽略特定的警告信息,例如在泛型中使用原生数据类型。它的保留策略是SOURCE(译者注:在源文件中有效)并且被编译器丢弃。
(三)元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。
@Target 规定自定义的注解作用范围
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value(); // 适用目标元素的类型
}
public enum ElementType {
TYPE, // 类,接口包括注解或者枚举
FIELD, // 字段包括枚举字段
METHOD, //方法
PARAMETER, // 参数
CONSTRUCTOR, //构造方法
LOCAL_VARIABLE, //局部变量
ANNOTATION_TYPE,
PACKAGE, // 包
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
@Retention 定义自定义注解的生命周期
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
public enum RetentionPolicy {
SOURCE, // java源代码中生效
CLASS, // 在class文件中生效
RUNTIME //在运行时生效
}
@Documented 描述注解应该被作为被标注的程序成员公共API
@Inherited 描述注解标注的某个类型是被继承的,该注解将会作用于继承的子类
(四)如何自定义注解
@interface 用来声明一个注解 语法: public @interface 自定义注解名 { //参数设置 }
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
String name() default "defaultValue"; // 使用默认值
}
@MyAnnotation(name = "I am A class")
public class A {
@MyAnnotation //注解里使用了默认值可不填参数
String n;
@MyAnnotation
public void testMethod(){
System.out.println("testMethod");
}
}
(五)什么是反射?
在程序运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
反射中四个核心类:
Class:类对象
Constructor:类的构造器对象
Method:类的方法对象
Field:类的属性对象
Class对象的三种获得方式:
@Test
public void test1() throws ClassNotFoundException {
// 对象的getClass()方法;
// 类的.class(最安全/性能最好)属性;
// 运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用).
// 注意:一个类在JVM中只有一个Class实例。
Class<? extends A> c1 = new A().getClass();
Class<A> c2 = A.class;
Class<?> c3 = Class.forName("com.wanshi.A");
}
使用Class对象获取类的信息:
@Test
public void test2(){
/**
String getName(): 获得类的名称,包括包名
String getSimpleName(): 获得类的名称,不包括包名
Class getSuperClass(): 获得本类的父类的类对象
Class[] getInterfaces() : 获得本类所实现的所有接口的类
Package getPackage():获取此类的包
ClassLoader getClassLoader() :返回该类的类加载器
*/
Class<A> c = A.class;
System.out.println(c.getName());
System.out.println(c.getSimpleName());
System.out.println(c.getSuperclass());
System.out.println(c.getInterfaces());
System.out.println(c.getPackage());
System.out.println(c.getClassLoader());
}
使用类中的方法:
@Test
public void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
/**
Method[] getMethods() :返回的 Method 类型的数组,包括所有的公开方法,也包括父类中定义的公开方法。私有方法不会被获取。
Method[] getDeclaredMethods() :返回在本类中定义的所有方法,包括私有方法。不能获得父类中的任何方法。
Method getMethod(String name, Class<?>... parameterTypes)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
*/
Class<A> c = A.class;
Method testMethod = c.getMethod("testMethod");
/**
Object invoke(Object obj, Object... args):利用反射,调用对象的方法
void setAccessible(boolean flag):指定布尔值设置是否执行java语言访问检查。
即调用一个类中的私有方法,只需要在调用 Method 对象的 invoke 方法之前,先调用 setAccessible(true)即可。
public Class<?> getReturnType():此 Method 对象所表示的方法的返回值类型
public Class<?>[] getParameterTypes():此 Method 对象所表示的方法的形参类型
Class<?>[] getExceptionTypes():此 Method 对象表示的方法抛出的异常类型的Class对象的数组
String getName():此 Method 对象表示的方法名称
*/
testMethod.invoke(new A());
System.out.println(testMethod.getReturnType());
System.out.println(testMethod.getName());
}
使用Class对象创建类的对象:
@Test
public void test4() throws IllegalAccessException, InstantiationException {
/**
newInstance():通过类的无参构造方法, 创建此 Class 对象所表示的类的一个新实例
好处在运行时加载,探知和使用编译期间完全未知的类.
在框架中大量使用,所以我们通常要求我们的类要有无参的构造方法
*/
Class<A> c = A.class;
A a = c.newInstance();
a.n="Hello";
System.out.println(a);
}
Class对象操作类字段:
@Test
public void test5() throws NoSuchFieldException, IllegalAccessException {
/**
Feild getField(String name):获得本类的公开属性以及从父类继承到的公开属性,是无法获得非公开属性
Feild getDeclaredField(String name):获得本类属性,包括本类的非公开属性
Feild[] getDeclaredFields()
Feild[] getFields()
*/
Class<A> c = A.class;
Field n = c.getField("n");
/**
Filed的方法
Object get(Object obj)
set(Object obj, Object value)
setAccessible(boolean flag):通过反射突破属性私有的限制,在读取和修改之前调用该方法,参数设置为true
*/
A a = new A();
a.n = "Hello 顽石";
System.out.println((String) n.get(a));
}
Class对象操作类构造方法:
@Test
public void test6() throws IllegalAccessException, InvocationTargetException, InstantiationException {
/**
Class方法:
Constructor<?>[] getConstructors() 获取所有的构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor方法
T newInstance(Object ... initargs)
*/
Class<A> c = A.class;
A a = (A)c.getConstructors()[0].newInstance();
}
末尾: 反射里的方法还有很多,没有一一列出来,还有一个更重要的反射获取注解的信息,后面文章再写,常用于java框架里面,只要搞懂反射具体是干嘛的,主要的方法能看懂 ,其他的方法可以自行查看文档,非常简单.