注解(Annotation)
- 不是程序本身,可以对程序做出解释,可被其他程序读取
- 注解是以“@注释名”在代码中存在的,还可以添加一些参数值
- 可以附加在package(包),class(类),method(方法),field(属性)等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问
内置注解
- @Override 表示此方法是重写的方法
- @Deprecated 表示此方法可以使用,但是不推荐程序员使用。或存在更好的方式
- @SupperssWarnings(“all”) 镇压警告,可以忽略一切警告信息
元注解
@Target(value = {ElementType.METHOD,ElementType.TYPE})//表示注解可以用在什么地方
@Retention(RetentionPolicy.RUNTIME)//使用范围 RUNTIME>CLASS>SOURCES
@Documented//表示是否将我们的注解生成在javadoc中
@Inherited//子类可以继承父类的注解
@interface myAnnotation {
//注解的参数:参数类型+参数名() +参数默认值(非必须);
String name() default "";
int age() default 0;
int id() default -1;
}
- 元注解用来注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明
- @Target:用于描述注解的使用范围
- @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期
- @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
自定义注解
@Target(value = {ElementType.METHOD,ElementType.TYPE})//表示注解可以用在什么地方
@Retention(RetentionPolicy.RUNTIME)//使用范围 RUNTIME>CLASS>SOURCES
@Documented//表示是否将我们的注解生成在javadoc中
@Inherited//子类可以继承父类的注解
@interface myAnnotation {
//注解的参数:参数类型+参数名() +参数默认值(非必须);
String name() default "";
int age() default 0;
int id() default -1;
}
- @interface用来声明一个注解,格式:public @ interface注解名{定义内容}
- 其中的每个方法实际上是声明了一个配置参数.
- 方法的名称就是参数的名称.
- 返回值类型就是参数的类型(返回值只能是基本类型,Class, String,enum).
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员, -般参数名为value
- 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值.
反射(Java Reflection)
-
反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
-
加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个类就像是一面镜子,透过这个镜子看到类的结构,所以,形象的称之为“反射”
-
反射相关主要类
- java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法
- java.lang.reflect.Field: 代表类的成员变量,Field对象表示某个类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
-
类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则会优先初始化其父类
-
类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就已经存入类的常量池中了)
-
类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
-
类缓存:标准的JavaSE类加载器可以按照要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
-
双亲委派机制
- 当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。
- 当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
- 如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
- 如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。
- 如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。
- 如果均加载失败,就会抛出ClassNotFoundException异常。
//通过对象获取类
Student student=new Student();
Class c1= student.getClass();
//通过包名加类名获取类
Class c2=Class.forName("suan.Study.Student");
//通过类名获取类
Class<Student> c3 = Student.class;
//获取其父类
Class c4 = c1.getSuperclass();
static ClassforName(String name ) -->返回指定类名name的Class对象
Object newInstance() -->调用缺省构造函数,返回Class对象的一个实例
getName() -->返回此Class对象所表示的实体(类,接口,数组类或void)的名称。
Class getSuperClass() -->返回当前Class对象的父类的Class对象
Class[] getinterfaces() -->获取当前Class对象的接口
ClassLoader getClassLoader() -->返回该类的类加载器
Constructor[] getConstructors() -->返回一个包含某些Constructor对象的数组
Method getMothed(String name,Class… T) -->返回一一个Method对象,此对象的形参类型为paramType
Field[] getDeclaredFields() -->返回Field对象的一个数组
反射获取类的信息
Class c1 = Class.forName("suan.Study.Student");
System.out.println(c1.getName());//获取 包名加类名
System.out.println(c1.getSimpleName());//获取类名
System.out.println("---------------");
Field[] fields = c1.getFields();//获取public属性
for (Field field:fields){
System.out.println(field);
}
System.out.println("---------------");
fields=c1.getDeclaredFields();//获取所有属性
for (Field field:fields){
System.out.println(field);
}
System.out.println("---------------");//获得指定属性的值
Field age = c1.getDeclaredField("age");
System.out.println(age);
System.out.println("---------------");//获得类的方法
Method[] methods = c1.getMethods();//获取本类及其父类的全部public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("---------------");
methods = c1.getDeclaredMethods();//获取本类的所有方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("---------------");//获取指定方法
Method getAge = c1.getMethod("getAge",null);//null可以不写,但建议写上
Method setAge = c1.getMethod("setAge", int.class);
System.out.println(getAge);
System.out.println(setAge);
System.out.println("---------------");//获取构造器
Constructor[] constructors = c1.getConstructors();//public
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors = c1.getDeclaredConstructors();//全部
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor constructor1 = c1.getConstructor(String.class, String.class,int.class);//获取指定构造器
System.out.println(constructor1);
constructor1 = c1.getConstructor(null);//获取指定构造器
System.out.println(constructor1);
通过反射创建对象并设置基本信息
Class c1 = Class.forName("suan.Study.Student");
Student Student1 = (Student)c1.newInstance();//通过无参构造器创建对象
System.out.println(Student1);
//通过有参构造器 传入参数 创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, String.class, int.class);
Student Student2 = (Student)constructor.newInstance("张三", "男", 23);
System.out.println(Student2);
//通过反射调用普通方法
Student Student3 = (Student) c1.newInstance();
Method setAge = c1.getDeclaredMethod("setAge", int.class);
setAge.invoke(Student3,32);
System.out.println(Student3.getAge());
//通过反射操作属性
Student Student4 = (Student) c1.newInstance();
Field sex = c1.getDeclaredField("sex");
//不能直接访问私有属性,先通过setAccessible()方法关闭安全检测后,在进行操作
sex.setAccessible(true);//关闭之后会提高效率
sex.set(Student4,"女");
System.out.println(Student4.getSex());
获取类的注解信息
public static void t2() throws ClassNotFoundException, NoSuchMethodException {
Class c1 = Class.forName("suan.Study.AnnotationStudy");//获取类
Annotation[] annotations = c1.getDeclaredAnnotations();//获取类的所有注解
for (Annotation anInterface : annotations) {
System.out.println(anInterface);
}
//获取类的注解
myAnnotation myAnnotation = (myAnnotation) c1.getAnnotation(myAnnotation.class);
System.out.println(myAnnotation.name());//获取注解的值
//获取方法的注解
Method test = c1.getDeclaredMethod("test");
suan.Study.myAnnotation annotation = test.getAnnotation(myAnnotation.class);
System.out.println(annotation.name());
System.out.println(annotation.age());
System.out.println(annotation.id());
}