什么是注解
作用:对程序做出解释,可以被其他程序读取
格式:@开头
在那里使用:包 类 方法 属性
内置注解
@Override 重写
@Deprecated 不鼓励使用,有更好的方法
@SuppressWarnings 抑制编译时的警告信息(有参数)
元注解
负责注解其他注解
@Target: (描述注解使用范围)
@Retention: 表示需要在什么级别保存该注释信息,描述注解的声明周期( SOURCE < CLASS <RUNTIME)
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
定义一个注解
@interface MyAnnotation{}
注解的参数:参数类型 + 参数名();
设置参数默认值:参数类型 + 参数名() + default +默认值;
注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
参数名多半会用value() 因为赋值时可以省略value =
反射
Java被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象)。可以通过这个对象看到类的结构,就像一面镜子。
对比:
正常:引入包类名称---> New 实例化 ---> 取得实例化对象
反射:实例化对象 ---> getClass方法 ---> 得到完整的包类名称
反射机制提供的功能
-
运行时判断任意一个对象所属的类
-
运行时构造任意一个类的对象
-
运行时判断任意一个类所具有的成员变量和方法
-
运行时获取泛型信息
-
运行时调用任意一个对象的成员变量和方法
-
运行时处理注解
-
生产多态代理
优缺点
优点:可以实现动态创建对象和编译,体现很大的灵活性
缺点:对性能有影响
反射相关的主要API
java.lang.Class //代表一个类 java.lang.reflect.Method //代表类的方法 java.lang.reflect.Field //代表类的成员变量 java.lang.reflect.Constructor //代表类的构造器
Class类
-
Class 本身也是一个类
-
Class 对象只能由系统建立对象
-
一个加载的类JVM中只会有一个Class实例
-
一个Class对象对应的是一个加载到JVM中的一个class文件
-
每个类的实例都会记得自己是由那个Class实例所生成
-
通过Class可以完整地得到一个类中的所有被加载的结构
-
Class类是Reflection的根源,针对任何你想动态加载运行的类,为有先获得相应的Class对象
获得Class 类的几种方法
public class Test03 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("这个人是:"+person.name); //方式一:通过对象获得 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式二:forname获取 Class c2= Class.forName("com.guo.reflection.Student"); System.out.println(c2.hashCode()); //方式三:通过类名获得 Class c3 = Student.class; System.out.println(c3.hashCode()); //方式四:基本内置类型的包装类都有一个Type属性 Class c4 = Integer.TYPE; System.out.println(c4.hashCode()); //获得父类类型 Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person{ public String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name="学生"; } } class Teacher extends Person{ public Teacher(){ this.name="老师"; } }
所有类型的Class对象
public class Test04 { public static void main(String[] args) { 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 System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); //只要元素类型和维度相同,就是同一个Class int[] a = new int[10]; int[] b = new int[100]; System.out.println(a.getClass().hashCode()); //a=b System.out.println(b.getClass().hashCode()); } }
类型加载
加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
链接:将java类的二进制代码合并到JVM的运行状态之中的过程。
-
验证:确保加载的类信息符合JVM规范,没有安全方面的问题
-
准备:正式为类变量(static)分配内存并设置类变量默认初始化阶段,这些内存都将在方法区中进行分配
-
解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
初始化:
-
执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的
-
当初始化一个类的时候,如果发现其父类还没有初始化,则需要先触发其父类的初始化
-
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。
public class Test05 { 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; } /* m=300 m=100 */ static int m =100; public A(){ System.out.println("A类的无参构造代码块"); } }
类初始化分析
什么时候类会初始化?
public class Test06 { static { System.out.println("Main类被加载"); } public static void main(String[] args) throws ClassNotFoundException { //①类的主动引用(一定发送类的初始化) //当虚拟机启动时,先初始化Main方法所在的类 //new一个类的对象 //调用类的静态成员和静态方法(final除外) //对类进行反射调用 //初始化一个类,父类没有初始化会先初始化其父类 //1.主动引用 Son son = new Son(); //2.反射 Class.forName("com.guo.reflection.Son"); //②类的被动引用(不会产生类的初始化) //子类引用父类的静态变量,不会导致子类初始化 System.out.println(Son.b); //通过数组定义类引用 Son[] array = new Son[5]; //引用常量 } } 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; }
类加载器
public class Test07 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类加载器 : 最常用加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2 //获取系统类加载器的父类加载器-->扩展类加载器 :负责jre/lib/ext目录下的jar包 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); //sun.misc.Launcher$ExtClassLoader@1b6d3586 //获取扩展类加载器的父类加载器-->根加载器 :负责java核心库 JVM自带加载器 ClassLoader parent1 = parent.getParent(); System.out.println(parent1); //null --> c/c++写的 //测试JDK内置类是谁加载的 ClassLoader classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader); //null 根加载器 //双亲委派机制:写好的东西有记录,不让你乱写 系统->扩展->根->扩展->系统 查询如果写了,你写的就没用了 } }
获得运行时类的完整结构
public class Test08 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.guo.reflection.User"); //获得类的名字 System.out.println(c1.getName()); //com.guo.reflection.User (获得包名+类名) System.out.println(c1.getSimpleName()); //User 类名 //获得类的属性 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); //private java.lang.String com.guo.reflection.User.name //private int com.guo.reflection.User.id //private int com.guo.reflection.User.age } //获得类的指定属性 Field name = c1.getDeclaredField("name"); System.out.println(name); //private java.lang.String com.guo.reflection.User.name //获得类的方法 Method[] methods = c1.getMethods(); //获得本类及其父类全部public方法 for (Method method : methods) { System.out.println("正常的:"+method); } Method[] declaredMethods = c1.getDeclaredMethods(); //获得本类的所有方法 for (Method declaredMethod : declaredMethods) { System.out.println("getDeclaredMethods:"+declaredMethod); } //获得类的指定方法 Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName", String.class); System.out.println(getName); //public java.lang.String com.guo.reflection.User.getName() System.out.println(setName); //public void com.guo.reflection.User.setName(java.lang.String) //获得类的构造器 Constructor[] constructors = c1.getConstructors(); //获得public的构造器 for (Constructor constructor : constructors) { System.out.println(constructor); } Constructor[] declaredConstructors = c1.getDeclaredConstructors(); //获得所有的构造器 for (Constructor declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } //获得类的指定的构造器 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println(declaredConstructor); //public com.guo.reflection.User(java.lang.String,int,int) } }
动态创建对象
public class Test09 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //获得Class对象 Class c1 = Class.forName("com.guo.reflection.User"); //构造一个对象 newInstance() User user = (User) c1.newInstance(); //本质上是调用无参构造 System.out.println(user); //User{name='null', id=0, age=0} //通过构造器创建对象 Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); User user2 = (User) constructor.newInstance("小郭", 21, 20); System.out.println(user2); //User{name='小郭', id=21, age=20} //通过反射调用普通方法 User user3 = (User) c1.newInstance(); Method setName = c1.getDeclaredMethod("setName", String.class); setName.invoke(user3,"xiaohu"); System.out.println(user3.getName()); //xiaohu //通过反射调用属性 User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); //不能直接操作私有属性 //解决办法 name.setAccessible(true); name.setAccessible(true); name.set(user4,"xiaolaohu"); System.out.println(user4.getName()); //java.lang.IllegalAccessException 没有权限 ->解决后 xiaolaohu } }
获取注解信息
public class Test10 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //反射操作注解 Class c1 = Class.forName("com.guo.reflection.Student2"); //通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的Value值 Tableguo tableguo = (Tableguo) c1.getAnnotation(Tableguo.class); String value = tableguo.value(); System.out.println(value); //获得指定类的注解 Field f = c1.getDeclaredField("name"); Fieldguo annotation = f.getAnnotation(Fieldguo.class); System.out.println(annotation); //其中的值 System.out.println(annotation.columnName()); System.out.println(annotation.length()); System.out.println(annotation.type()); } } @Tableguo("db_student") class student2{ @Fieldguo(columnName = "db_name",type = "varchar",length = 15) private String name; @Fieldguo(columnName = "db_id",type = "int",length = 15) private int id; @Fieldguo(columnName = "db_age",type = "int",length = 15) private int age; public student2() { } public student2(String name, int id, int age) { this.name = name; this.id = id; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } 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; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; } } //类名的注解(表名) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Tableguo{ String value(); } //属性的注解(字段) @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Fieldguo{ String columnName(); //列名 String type(); //类型 int length(); //长度 }