Java注解和反射
注解入门
-
注解是从jdk5.0开始引入
-
注解的作用:
可以对程序作出解释
可以被其他程序读取
-
注解的格式:@注解名
-
注解可以在package,class,method等上面,相当于给他们添加了额外的辅助信息
内置注解
-
@Override,用于修饰方法,表示该方法重写
-
@Deprecated,用于修改方法,属性,类,表示不建议使用这样的元素,已过时
-
@SuppressWarnings,用来抑制编译时的警告信息,需要添加一个参数
@SuppressWarnings("all") @SuppressWarnings("unchecked")等等
元注解
//定义一个注解 //Target表示注解可以用在那些地方 方法,类和接口 @Target(value = {ElementType.METHOD,ElementType.TYPE}) //Retention表示注解在什么地方有效 //routime>class<sources @Retention(value = RetentionPolicy.RUNTIME) //表示我们的注解生成在javadoc中 @Documented //子类可以继承父类的注解 @Inherited @interface MyAnnoation{ }
自定义注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class Test01 { //显式赋值name,不赋值默认为"",如果没用默认值则必须要给name赋值 @MyAnnotation(name="dd",school = {"zha","xer"}) public void test(){} //可以不用写参数名,默认为value @MyAnnoation2("空间") public void test2(){} } @Target(value = {ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation{ //注解的参数:参数类型+参数名() String name() default ""; int age() default 0; String[] school(); } @Target(value = {ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnoation2{ String value(); }
反射(Reflection)
反射是java被视为动态语言的关键
反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能给直接和操作对象的内部属性及方法
正常方式:引入需要的包---new实例化----取得实例化对象
反射方式:实例化对象---getClass()方法---得到完整的包类名称
package com.henry.reflect; public class TestReflect { public static void main(String[] args) throws ClassNotFoundException { //通过反射获取类的class对象 Class c1 = Class.forName("com.henry.reflect.User"); Class c2 = Class.forName("com.henry.reflect.User"); //一个类在内存中只有一个class对象,c1和c2的hashcode相同 //一个类被加载后,类的整个结构都会被封装在class对象中 System.out.println(c1.hashCode()); System.out.println(c2.hashCode()); } } //实体类 class User{ private String name; private int id; private int age; public User() { } public User(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 + '}'; } }
获取Class类的实例
-
Class c1 = Person.class
-
Class c2 = person.getClass()
-
Class c3 = Class.forName("demo.Person")
//测试class类的创建方式 public class TestGetClass { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println(person.name); //方式1,通过对象获得class Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式2,forname Class c2 = Class.forName("com.henry.reflect.Student"); System.out.println(c2.hashCode()); //方式3 类名.class Class c3 = Student.class; System.out.println(c3.hashCode()); //获得父类类型 System.out.println(c1.getSuperclass()); } } 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对象
-
class,类
-
interface 接口
-
数组
-
enum 枚举
-
annotation 注解
-
基本数据类型
-
void
Class c1 = Object.class; //类
Class c2 = Runnable.class; //接口
Class c3 = int[].class; //数组
Class c4 = Override.class; //注解
Class c5 = ElementType.class; //枚举
Class c6 = Integer.class; //基本数据类型
Class c7 = void.class;
只要元素类型一样,就是同一个Class
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; } static int m = 100; public A(){ System.out.println("A的无参构造初始化"); } }
类初始化
public class Test06 { static { System.out.println("主类被加载"); } public static void main(String[] args) throws ClassNotFoundException { //主动引用 //Son son = new Son();//主类被加载,父类被加载,子类被加载 //反射也会产生主动引用 //Class.forName("com.henry.reflect.Son"); //不会产生类的引用的方法 //System.out.println(Son.f);//调用父类的静态方法或者变量,不会初始化子类 //主类被加载,父类被加载,1 //Son[] array = new Son[5]; //主类被加载 System.out.println(Son.S); //主类被加载,2 } } class Father{ static int f = 1; static { System.out.println("父类被加载"); } } class Son extends Father{ static { System.out.println("子类被加载"); } static int m = 100; static final int S = 2; }
类加载器的作用
类加载的作用:将class字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
public class Test07 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类的加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //获得系统类加载器的父类加载器---扩展类加载器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); //获得扩展类加载器的父类加载器---根加载器(c/c++编写)无法获取 System.out.println(parent.getParent()); //测试当前类是哪个加载器加载的 System.out.println(Test07.class.getClassLoader());//系统类加载器 System.out.println(Class.forName("java.lang.Object").getClassLoader());//根加载器 //获得系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path")); } }
Class c1 = Class.forName("User"); //获得类的名字 System.out.println(c1.getName()); //获得包名+类名 System.out.println(c1.getSimpleName());//获得类名 //获得类的属性 Field[] fields = c1.getFields();//只能找到public属性的 fields = c1.getDeclaredFields(); //找到全部属性 for (Field field : fields) { System.out.println(field); } //获得指定属性的值 Field name = c1.getDeclaredField("name");//因为是私有的,不能getField System.out.println(name); //获得类的方法 Method[] methods = c1.getMethods();//获得本类和父类的public方法 c1.getDeclaredMethods();//获得本类的所有方法 //获得指定方法 Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName", String.class); System.out.println(getName); System.out.println(setName); //获得构造器 Constructor[] constructors = c1.getConstructors();//获得public构造器 for (Constructor constructor : constructors) { System.out.println(constructor); } c1.getDeclaredConstructors();//获得所有的构造器 //获得指定的构造器 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println(declaredConstructor);
public class Test09 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //获得class对象 Class c1 = Class.forName("com.henry.reflection.User"); //构造一个对象 User user = (User) c1.newInstance();//本质上调用了类的无参构造器 System.out.println(user); //通过构造器创建对象 Constructor constructor = c1.getDeclaredConstructor(String.class, int.class); User user2 = (User) constructor.newInstance("张虎", 12); System.out.println(user2); //通过反射调用普通方法,如果方法为私有的需要关闭安全检测 setName.setAccessible(true); User user3 = (User) c1.newInstance(); Method setName = c1.getDeclaredMethod("setName", String.class); //invoke:激活的意思 //(对象,传递的参数) setName.invoke(user3, "户端"); System.out.println(user3.getName()); //通过反射操作属性 User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); //不能直接操作私有属性,需要关闭程序的安全检测 name.setAccessible(true); name.set(user4,"看看"); System.out.println(user4.getName()); } }
性能对比分析
public class Test10 { //普通方式调用 public static void u1(){ User user1 = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { user1.getName(); } long endTime = System.currentTimeMillis(); System.out.println("用的时间:"+(endTime-startTime)+"ms"); } //反射方式调用 public static void u2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("用的时间:"+(endTime-startTime)+"ms"); } //反射方式调用,关闭检测,能够提高效率 public static void u3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("用的时间:"+(endTime-startTime)+"ms"); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { u1(); u2(); u3(); } }
通过反射获取泛型信息
//通过反射获取泛型 public class Test11 { public void t1(Map<String,User> map, List<User> list){ System.out.println("t1"); } public Map<String,User> t2(){ System.out.println("t2"); return null; } public static void main(String[] args) throws NoSuchMethodException { //参数 Method method = Test11.class.getDeclaredMethod("t1", Map.class, List.class); Type[] genericExceptionTypes = method.getGenericParameterTypes(); for (Type genericExceptionType : genericExceptionTypes) { System.out.println(genericExceptionType); if(genericExceptionType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericExceptionType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } System.out.println("---------------------------"); //返回值 Method method2 = Test11.class.getDeclaredMethod("t2", null); Type genericReturnType = method2.getGenericReturnType(); System.out.println(genericReturnType); if(genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } }
获取注解信息
ORM:Object relationship mapping 对象关系映射
public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.henry.reflection.Student2"); //通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的value值 TableYD tableYD = (TableYD)c1.getAnnotation(TableYD.class); System.out.println(tableYD.value()); //获得类指定的注解 Field name = c1.getDeclaredField("name"); FieldYD annotation = name.getAnnotation(FieldYD.class); System.out.println(annotation); System.out.println(annotation.columnName()); System.out.println(annotation.length()); System.out.println(annotation.type()); } } @TableYD("db_student") class Student2{ @FieldYD(columnName = "db_id",type = "int",length = 10) private int id; @FieldYD(columnName = "db_age",type = "int",length = 10) private int age; @FieldYD(columnName = "db_name",type = "varchar",length = 10) private String name; public Student2() { } public Student2(int id, int age, String name) { this.id = id; this.age = age; 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; } 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注解的使用范围,retention描述注解的声明周期(SOURCE<CLASS<RUNTIME) @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableYD{ String value(); } //属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldYD{ String columnName(); String type(); int length(); }