文章目录
注解和反射
一、注解 Annotation
1.1、元注解
//Target表示我们的注解可以用在那些地方 @Target(value = {ElementType.TYPE,ElementType.METHOD}) //Retention 表示我们的注解在什么地方还有效 @Retention(value = RetentionPolicy.RUNTIME) //Documented 表示是否将我们的注解生成在JavaDoc中 @Documented //Inherited 子类可以继承父类的注解 @Inherited //@interface 定义注解 @interface MyAnnotation{ }
1.2、自定义注解
public class TestAnnotation {
@MyAnnotation(name = "李四", value = 5)
public void test() {
}
}
//自定义注解
//Target表示我们的注解可以用在那些地方
@Target(value = {ElementType.TYPE,ElementType.METHOD})
//Retention 表示我们的注解在什么地方还有效
@Retention(value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在JavaDoc中
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
//注解的参数 : 参数类型 + 参数名();
String name();
//可以给参数设置默认值
int id() default 0;
String[] schools() default {"北京大学","清华大学"};
//只有一个参数时,一般将参数名设为value
int value();
}
二、反射 Reflection
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法
对于每个类而言,JRE都为其保留一个不变的Class类型的对象(唯一的),一个Class对象包含了特定的
**注:**只要元素类型与维度一样,就是同一个Class
Class 类:
- Class本身也是一个类
- Class对象只能由系统建立对象 - --(我们只能获取)
- 一个加载的类在JVM中只会由一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个 .class 文件
- 每个类的实例都会记得自己是由哪个Class实例所生成
- 通过Class可以完整地得到一个类中的所有被加载的结构
- Class类是Reflection的根源,针对任何你想动态加载、运行的类、唯有先获得相应的Class对象
1.1: 只要元素类型与维度一样,就是同一个class
public static void main(String[] args) {
int[] ints1 = new int[10];
int[] ints2 = new int[20];
System.out.println(ints1.getClass().hashCode()); // 1836019240
System.out.println(ints2.getClass().hashCode()); // 1836019240
ArrayList list1 = new ArrayList<>();
ArrayList list2 = new ArrayList<>();
System.out.println(list1.getClass().hashCode()); // 325040804
System.out.println(list2.getClass().hashCode()); // 325040804
int[][] ints = new int[10][10];
int[] ints3 = new int[10];
System.out.println(ints.getClass().hashCode()); // 1173230247
System.out.println(ints3.getClass().hashCode()); // 1836019240 不同
A a = new A();
A a1 = new A(1);
System.out.println(a.getClass().hashCode()); // 856419764
System.out.println(a1.getClass().hashCode()); // 856419764
}
}
class A{
private int anInt;
public A() {}
public A(int anInt) {
this.anInt = anInt;
}}
1.2: 得到Class类的几种方式
public class ReflectionTest2 {
public static void main(String[] args) throws ClassNotFoundException {
//方式一 : 通过对象获得
Person stu = new Student();
Class c1 = stu.getClass();
System.out.println(c1.hashCode());
//方式二 : 通过forname获得
Class c2 = Class.forName("注解_反射.reflection.Student");
System.out.println(c2.hashCode());
//方式三 : 通过类名 .class 获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方式四 : 基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4); //int
}
}
class Person{
}
class Student extends Person{
}
1.3: 所有类型的class
Class c1 = Object.class; //类
Class c2 = Comparable.class; //接口
Class c3 = String[].class; //一维数组
Class c4 = int[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class; //枚举
Class c7 = Integer.class; //基本数据类型
Class c8 = void.class; //void
Class c9 = Class.class; //class
1.4: 类加载–内存分析
jvm:
堆:
1.存放new的对象和数组
2.可以被所有的线程共享,不会存放别的对象引用
方法区会在以后逐步移除,采用方法区会在以后逐步移除,采用native memory来实现方法区的规划,好像是因为方法区的回收比较困难,也因此导致过很多严重的bug来实现方法区的规划,好像是因为方法区的回收比较困难,也因此导致过很多严重的bug,常量池 jdk7后存于堆中,节约内存
栈:
1.存放基本变量类型(会包含这个基本类型的具体数值)
2.引用对象的变量(会存放这个引用在堆里面的具体地址)
方法区:
1.可以被所有的线程共享
2.包含了所有的class和static变量
1.5: 获取类的运行时结构
public class ReflectionTest4 {
public static void main(String[] args) throws Exception {
Class c1 = User.class;
//获取类的名字
System.out.println(c1.getName()); //获得包名+类名
System.out.println(c1.getSimpleName()); //获得类名
System.out.println("====================");
//获得类的属性
Field[] fields = c1.getFields(); //只能获得public修饰的属性
System.out.println(Arrays.toString(fields));
fields = c1.getDeclaredFields(); //获得全部属性
System.out.println(Arrays.toString(fields));
//获得指定属性
Field name = c1.getDeclaredField("name");
System.out.println(name);
System.out.println("====================");
//获取类的方法
Method[] methods = c1.getMethods(); //获取本类及父类所有public方法
System.out.println(Arrays.toString(methods));
methods = c1.getDeclaredMethods(); //获取本类所有方法
System.out.println(Arrays.toString(methods));
//获取指定方法 --有参数和无参数
Method setAge = c1.getDeclaredMethod("setAge", int.class);
System.out.println(setAge);
Method getAge = c1.getDeclaredMethod("getAge",null); //null 可传可不传
System.out.println(getAge);
System.out.println("====================");
//获取类的构造器
Constructor[] constructors = c1.getConstructors(); //只能获取public的构造器
System.out.println(Arrays.toString(constructors));
constructors = c1.getDeclaredConstructors(); //获取本类的所有构造器
System.out.println(Arrays.toString(constructors));
//获取指定的构造器
Constructor constructor = c1.getDeclaredConstructor(int.class, String.class);
System.out.println(constructor);
}
}
class User{
public int size;
private int age;
private String name;
public User() {
}
public User(int age, String name) {
this.age = age;
this.name = name;
}
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;
}
}
1.6:动态创建对象执行方法
public static void main(String[] args) throws Exception {
Class c1 = User.class;
//调用newInstance 构造对象.本质是调用了类的无参构造
User user = (User) c1.newInstance();
System.out.println(user);
//当类中没有无参构造时
Constructor constructor = c1.getDeclaredConstructor(int.class, String.class);
user = (User) constructor.newInstance(1,"张三");
System.out.println(user);
//调用类中方法
user.setAge(10);
System.out.println(user);
//使用反射掉用类中方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke : 激活的意思
setName.invoke(user, "李四");
System.out.println(user);
//通过反射操作属性
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性, 我们需要 打开访问权限 暴力反射
name.setAccessible(true);
name.set(user,"王五");
System.out.println(user.getName());
Method eat = c1.getDeclaredMethod("eat");
eat.setAccessible(true);
eat.invoke(user);
}
1.7:反射获取注解信息
public static void main(String[] args) throws Exception {
Class c1 = TableUser.class;
//获取注解.获得了类上的注解
Annotation[] annotations = c1.getAnnotations();
System.out.println(Arrays.toString(annotations));
//获得类中字段上的注解
Field id = c1.getDeclaredField("id");
Annotation[] annotations1 = id.getAnnotations();
System.out.println(Arrays.toString(annotations1));
//获取指定注解中的值
FieldAnnotation fieldAnnotation = id.getAnnotation(FieldAnnotation.class);
System.out.println(fieldAnnotation.columnName());
System.out.println(fieldAnnotation.type());
//获取指定注解
Annotation annotation = c1.getAnnotation(TableAnnotation.class);
System.out.println(annotation);
}
}
@TableAnnotation("db_user")
@Data
class TableUser{
@FieldAnnotation(columnName = "id",type = "int")
private int id;
@FieldAnnotation(columnName = "name",type = "varchar")
private String name;
}
//Target表示我们的注解可以用在那些地方
@Target(value = ElementType.TYPE)
//Retention 表示我们的注解在什么地方还有效
@Retention(value = RetentionPolicy.RUNTIME)
@interface TableAnnotation{
String value();
}
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
@interface FieldAnnotation{
String columnName();
String type();
}