注解和反射
1、注解
什么是注解?
annotation在哪里使用?
我们可以通过附加在package,class,method,field上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问
1.1、内置注解
@Override:定义在 java.lang.Override 中,此注解只适用于修辞方法,表示一个方法声明打算重写超类的另一个方法声明。
@Deprecated:定义在java.lang.Deprecated中,此注解可以用于修辞方法,属性、类,表示不鼓励程序员使用这样的元素,通常是因为他们危险或者有更好的选择
@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
与前两个注释不同,你需要添加一个参数才能正常使用,这些参数都是已经定义好的
- SuppressWarnings(“all”)
- SuppressWarnings(“unchecked”)
- SuppressWarnings(value={"unchecked,“deprecation”})
1.2、元注解
- 元注解的作用就是负责注解其他注解,java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明
- 这些类型和他们所支持的类在java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inherited)
- @Target:用于描述注解的使用范围(也就是被描述的注解可以用在什么地方)
- @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期
- (SOURCE<CLASS<RUNTIME)
- @Documented:说明该注释将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的注解
1.3、自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
- 分析:
- @interface用来声明一个注释,格式:public @ interface 注解名{定义内容}
- 参数格式:类型 参数名();
- 其中的每一个方法实际上是声明了一个配置参数
- 方法的名称就是参数的名称
- 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value
- 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
2、反射
2.1、动态语言和静态语言
-
动态语言:
- 是一类在运行时可以改变其结构的语言:例如新的对象,函数,甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗来说就是在运行时代码可以根据某些条件改变自身结构。
- 主要动态语言:Object-C,C#,JavaScript,PHP,Python等
-
静态语言:
- 运行时结构不可变的就是静态语言,eg :Java,C,C++
- Java不是动态语言,但是它可以称为准动态语言。也就是Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活
2.2、Java Reflection
- Reflection (反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于 Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只要一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过镜子看到类的结构,所以,我们形象的称之为反射
正常方式: 引入需要的包类名称----->通过new实例化------->取得实例化对象
反射方式:实例化对象 ------->getClass()方法----->取得完整的包类名称
2.3、反射机制提供的功能
2.4、反射的优缺点
2.5、反射相关的API
2.6、Class类
//一个类在内存中只有一个Class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中在这里插入代码片
//通过反射获得类的class对象
Class c1 = Class.forName("com.wu.pojo.User");
2.7、Java内存分析
2.8、类的加载过程
2.9、类的加载与ClassLoader的理解
package com.wu.test;
//测试类加载
public class Test2 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
}
/*
* 1、加载到内存,回产生一个Class对象
* 2、链接,结束后m=0
* 3、初始化<clinit>(){
* System.out.println("A静态代码块初始话");
m=300;
* m = 100;
* }
* m=100;
* */
}
class A{
static {
System.out.println("A静态代码块初始话");
m=300;
}
static int m = 100;
public A(){
System.out.println("A无参构造初始化");
}
}
2.10、分析类初始化
package com.wu.test;
//测试类什么时候初始化
public class Test3 {
static {
System.out.println("Main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//1 主动引用会发生类的初始化
//Son son = new Son();
// 反射 也会产生类的初始化
//Class aClass = Class.forName("com.wu.test.Son");
//2 被动引用
//System.out.println(Son.b); // 子类调用父类的静态变量时,子类不会被加载
//Son[] arr = new Son[3]; // 数组不会触发类的初始化,之后加载Main
System.out.println(Son.M); // 引用常量在链接时已经初始化了,所以不会出发类的初始化
}
}
class Father{
static int b=2;
static {
System.out.println("父类已加载");
}
}
class Son extends Father{
static {
System.out.println("子类已加载");
m=300;
}
static int m =100;
static final int M = 1;
}
2.11、类加载器的作用
2.12、创建运行时类的对象
package com.wu.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class<?> c1 = Class.forName("com.wu.pojo.User");
//Class的方法
//获得类名
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); //没有打印出来
}
Field[] declaredFields = c1.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField); //找到全部的属性
}
System.out.println("========================");
System.out.println(c1.getDeclaredField("id"));
System.out.println("================");
//获得类方法
for (Method method : c1.getMethods()) {
System.out.println("正常的:"+method); //获得本类和父类的所有public方法
}
System.out.println("============================");
for (Method declaredMethod : c1.getDeclaredMethods()) {
System.out.println("其他的:"+declaredMethod); //获得本类的所有方法(包括私有方法)
}
//获得指定方法
System.out.println(c1.getMethod("getName",null));
System.out.println(c1.getMethod("setName", String.class));
System.out.println("=======================");
//获得类构造器
for (Constructor<?> constructor : c1.getConstructors()) {
System.out.println(constructor);
}
//获得指定构造器
System.out.println(c1.getConstructor(String.class, int.class, int.class));
System.out.println(c1.getConstructor(null));
}
}
2.13、动态创建对象执行方法
package com.wu.test;
import com.wu.pojo.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test6 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> c1 = Class.forName("com.wu.pojo.User");
//User user = (User) c1.newInstance(); //本质上调用了无参构造器
//通过构造器创建对象
Constructor<?> constructor = c1.getConstructor(String.class, int.class, int.class);
User user = (User) constructor.newInstance("吴佳俊", 1, 21);
System.out.println(user);
System.out.println("========================");
//通过反射调用方法
User user1 = (User) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user1,"wujiajun"); //激活方法(对象,方法的参数)
System.out.println(user1.getName());
System.out.println("===========================");
//通过反射操作属性
//不能直接操作私有属性 我们需要关闭安全检测: 方法/属性.setAccessible(true)
User user2 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name"); // 权限不够
name.setAccessible(true); // 关闭方法或者属性的权限访问
name.set(user2,"吴佳俊2");
System.out.println(user2.getName());
}
}
2.14、反射和普通的性能分析
package com.wu.test;
import com.wu.pojo.User;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析反射和普通性能
public class Test7 {
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
test1();
test2();
test3();
}
//普通方式调用
public static void test1(){
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行10亿次耗时:"+(endTime-startTime)+"ms");
}
//反射方式调用
public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class<User> userClass = User.class;
Method getName = userClass.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次"+(endTime-startTime)+"ms");
}
//反射方式调用(关闭安全权限检查)
public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class<User> userClass = User.class;
Method getName = userClass.getDeclaredMethod("getName", null);
getName.setAccessible(true);//关闭检查
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式调用(关闭安全权限检查)执行10亿次"+(endTime-startTime)+"ms");
}
}
2.15、获得泛型信息【难】
2.16、反射获取注解信息
- getAnnotations
- getAnnotation
package com.wu.test;
import java.lang.annotation.*;
//反射操作注解
public class Test9 {
public static void main(String[] args) throws NoSuchFieldException {
Class<Student2> c1 = Student2.class;
//通过反射获取注解
for (Annotation annotation : c1.getAnnotations()) {
System.out.println(annotation);
}
//获得注解value的值
tableKuang annotation = c1.getAnnotation(tableKuang.class);
System.out.println(annotation.value());
//获得类指定的注解
java.lang.reflect.Field field = c1.getDeclaredField("id");
Field fieldAnnotation = field.getAnnotation(Field.class);
System.out.println(fieldAnnotation.columnName());
System.out.println(fieldAnnotation.type());
System.out.println(fieldAnnotation.length());
}
}
@tableKuang("db_student")
class Student2{
@Field(columnName = "db_id",type = "int",length = 10)
private int id;
@Field(columnName = "db_age",type = "int",length = 10)
private int age;
@Field(columnName = "db_name",type = "String",length = 10)
private String name;
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public Student2() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface tableKuang{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field{
String columnName();
String type();
int length();
}