注解和反射(持续更新)

    科技2022-08-17  116

    什么是注解

    Annotation是从JDK5.0开始引入的新技术Annotation的作用 不是程序本身,可以对程序作出解释(这一点和注释(comment)没有什么区别) 2.== 可以被其他程序(比如:编译器等)读取.== Annotation的格式 注解是以 @注释名 在代码中存在,还可以添加一些参数值,例如:@SuppressWarinings(value="unchecked’)Annotation在哪里使用? 可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息.我们可以通过反射机制编程实现对这些元数据的访问.

    内置注解

    @Override :定义在java.lang.Override中,此注解只适用于修辞方法,表示一个方法声明打算重写超类中的 另一个方法声明.@Deprecated: 定义在java.lang.Deprecated中,此注解可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通过因为它很危险或者有更好的选择.@SuppressWarnings:定义在java.lang. SuppressWarnings中,用来抑制编译时的警告信息. 与前两个注释有所不同,你需要添加一个参数才能正确使用.这些参数都是已经定义好的,我们选择使用就好了. @SuppressWarnings(“all”) 镇压警告. @SuppressWarnings(“unchecked”) @SuppressWarinings(value={“unchecked”,“deprecation”}) 等等…

    元注解

    元注解就是负责注解其他的注解, java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明.这些类型和它们所支持的类在java.lang.annotation包中可以找到,(@Target,@Retention,@Documented,@Inherited)@Target:用于描述注解的使用范围(即:被描述的注解 可以用在什么地方)@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期 (SOURCE<CLASS<RUNTIME)@Document:说明该注解将被包含在javadoc中.@Inherited:说明子类可以继承父类中的该注解. 示例

    自定义注解

    使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口 分析: @interface用来声明一个注解,格式:public@interface注解名{定义内容}其中的每一个方法实际上是声明了一个配置参数方法的名称就是参数的名称返回值类型就参数的类型(返回值只能是基本类型 ,Class,String,enum).可以通过default来声明参数的默认值如果只有一个参数成员,一般参数名为value注解元素必须要有值,我们定义注解元素时,经常使用空字符串,或者0位默认值.

    静态VS动态语言

    动态语言 是一类在运行时可以改变其结果的语言:例如新的函数,对象,甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化,通俗的说就是代码运行时,代码可以根据某些条件改变自身结构. 主要动态语言: Object-c, C#,JavaScript,php,python等 静态语言 与动态语言相对应,运行时结果不可变的语言就是静态语言,如java,c,c++ java不是动态语言,但java称之为准"动态语言".即java有一定的动态性,我们可以利用反射机制获得动态语言的特性.java的动态机制让编程更加灵活!

    反射 Java Reflection

    Reflection是java被称为动态语言的关键,反射机制永许在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性以及方法. Class c = Class.forName(“java.lang.String”) 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结果信息.我们可以通过这个对象看到类的结果.这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射. 正常方式:引入需要的"包类"名称⇒ 通过new 实例化 ⇒ 取得实例化对象 反射方式: 实例化对象 =>getClass()方法 => 取得完整的"包类"名称

    反射的优点和缺点

    优点 : 可以实现动态创建对象和编译,体现出很大的灵活性. 缺点:对性能有影响.使用反射基本上是一种解释操作,我们需要去告诉JVM,我们希望做什么并且它满足我们的要求.这类操作总是慢于直接执行相同的操作.

    反射相关的主要API

    java.lang.Class: 代表一个类. java.lang.reflect.Method:代表类的方法 java.lang.reflect.Field:代表类的方法 java.lang.reflect.Constructor:代表类的方法

    Class 类

    在Object类中定义了以下的方法,此方法将被所有子类继承 public final Class getClass() 以上的方法返回值的类型是一个Class类,此类是java反射的源头,实际上从程序的运行结果很好得理解,看出可以通过反射求出一个类的名称.

    代码演示

    package com.kuang; public class test1 { 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()); // 方式二 通过名称获得 Class c2 = Class.forName("com.kuang.Student"); System.out.println(c2.hashCode()); // 方式三 通过类名活动 Class c3 = Student.class; System.out.println(c3.hashCode()); // 通过子类获得父类 Class c4 = c3.getSuperclass(); System.out.println(c4.hashCode()); // 基本类型都有内置属性 Type Class c5 = Integer.TYPE; 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类的实例

    a) 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高 Class clazz = Person.class; b)已知某个类的实例,调用该实例的getClass()方法获取Class对象 Class clazz = person.getClass(); c)已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出 ClassNotFoundException Class clazz = Class.forName(“demo01.Student”); d) 基本数据类型可以直接用类名.Type e) 还可以利用ClassLoader下面会详解.

    哪些类型可以有Class对象?

    class: 外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类. interface: 接口 []: 数组 enum: 枚举 annotation : 注解@Interface primitive type : 基本数据类型 void

    package com.kuang; import java.lang.annotation.ElementType; public class test2 { public static void main(String[] args) { Class c1 = Object.class; // 类 Class c2 = Comparable.class; //接口 Class c3 = String[].class; // String一维数组 Class c4 = int[][].class; // int 二维数组 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 java.lang.Object interface java.lang.Comparable class [Ljava.lang.String; class [[I interface java.lang.Override class java.lang.annotation.ElementType class java.lang.Integer void class java.lang.Class

    java内存分析

    了解:类的加载过程

    什么时候会发生类初始化?

    类加载器的作用

    类加载器的作用

    java核心库 是rt.jar,里面有我们常用的类.

    package com.kuang; public class test3 { public static void main(String[] args) throws ClassNotFoundException { // 获得系统类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 // 获得父类 扩展类加载器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@4554617c // 获得扩展类的父类加载器-->根加载器(c/c++) ClassLoader parent1 = parent.getParent(); System.out.println(parent1); // null 得不到父类加载器了(即引导类加载器也叫根加载器), 因为根加载器无法直接获取,它是C++编写的. //测试当前类是哪个加载器加载 Class c1 = Class.forName("com.kuang.test3"); ClassLoader classLoader = c1.getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 // //测试JDK内置的类哪个加载器加载 ClassLoader c2 = Class.forName("java.lang.Object").getClassLoader(); System.out.println(c2); //null // 如何可以获得系统类加载器可以加载的路径 String property = System.getProperty("java.class.path"); System.out.println(property); /*打印结果如下: D:\install\Java\jdk1.8.0_101\jre\lib\charsets.jar; D:\install\Java\jdk1.8.0_101\jre\lib\deploy.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\access-bridge-64.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\cldrdata.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\dnsns.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\jaccess.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\jfxrt.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\localedata.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\nashorn.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\sunec.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\sunjce_provider.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\sunmscapi.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\sunpkcs11.jar; D:\install\Java\jdk1.8.0_101\jre\lib\ext\zipfs.jar; D:\install\Java\jdk1.8.0_101\jre\lib\javaws.jar; D:\install\Java\jdk1.8.0_101\jre\lib\jce.jar; D:\install\Java\jdk1.8.0_101\jre\lib\jfr.jar; D:\install\Java\jdk1.8.0_101\jre\lib\jfxswt.jar; D:\install\Java\jdk1.8.0_101\jre\lib\jsse.jar; D:\install\Java\jdk1.8.0_101\jre\lib\management-agent.jar; D:\install\Java\jdk1.8.0_101\jre\lib\plugin.jar; D:\install\Java\jdk1.8.0_101\jre\lib\resources.jar; D:\install\Java\jdk1.8.0_101\jre\lib\rt.jar; D:\JavaSE\reflect\out\production\reflect; D:\install\IntelliJ IDEA 2017.2.6\lib\idea_rt.jar */ } }

    获取运行时类的完整结构

    通过反射获取运行时类的完整结构 Field , Method, Constructor,Superclass,Interface,Annotation 实现的全部接口 所继承的父类 全部的构造器 全部的方法 全部的Field 注解 … 代码 体现下面

    package com.kuang; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class test8 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.kuang.pojo.User"); System.out.println(c1.getName());//获得包名+ 类名 com.kuang.pojo.User System.out.println(c1.getSimpleName());//获得类名 User //获得类的属性. Field[] fields = c1.getFields();//只能得到public公共的属性. //找到全部属性 Field[] fields1 = c1.getDeclaredFields(); for(Field f:fields1){ System.out.println(f); /* private java.lang.String com.kuang.pojo.User.name private int com.kuang.pojo.User.id private int com.kuang.pojo.User.age * */ } System.out.println("=========================="); //获得指定属性的值 Field field = c1.getDeclaredField("name");//private java.lang.String com.kuang.pojo.User.name System.out.println(field); //获得类的方法 System.out.println("==============="); //获得方法 获得本类及其父类public 公共的方法. Method[] methods = c1.getMethods(); for (Method m1: methods){ System.out.println(m1); /* 不但获得本类的公共方法,还活动了Object的方法了. public java.lang.String com.kuang.pojo.User.toString() public java.lang.String com.kuang.pojo.User.getName() public int com.kuang.pojo.User.getId() public void com.kuang.pojo.User.setName(java.lang.String) public int com.kuang.pojo.User.getAge() public void com.kuang.pojo.User.setAge(int) public void com.kuang.pojo.User.setId(int) public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() * */ } System.out.println("----------------------"); // 获得本类所有的方法. Method[] declaredMethods = c1.getDeclaredMethods(); for (Method m2:declaredMethods){ System.out.println(m2); /* public java.lang.String com.kuang.pojo.User.toString() public java.lang.String com.kuang.pojo.User.getName() public int com.kuang.pojo.User.getId() public void com.kuang.pojo.User.setName(java.lang.String) private void com.kuang.pojo.User.test() public int com.kuang.pojo.User.getAge() public void com.kuang.pojo.User.setAge(int) public void com.kuang.pojo.User.setId(int) * */ } System.out.println("=========="); // 获得指定的方法 // 因为方法有重载 所以需要参数 Method m3 = c1.getMethod("getName",null); Method m4 = c1.getMethod("setName",String.class); System.out.println(m3); System.out.println(m4); /* * public java.lang.String com.kuang.pojo.User.getName() public void com.kuang.pojo.User.setName(java.lang.String) * */ System.out.println("---------------===================="); Method m5 = c1.getDeclaredMethod("getName",null); Method m6 = c1.getDeclaredMethod("setName",String.class); System.out.println(m5); System.out.println(m6); // public java.lang.String com.kuang.pojo.User.getName() // public void com.kuang.pojo.User.setName(java.lang.String) System.out.println("===============------------------======="); //获得构造器 Constructor[] constructors = c1.getConstructors(); for (Constructor constructor:constructors){ System.out.println(constructor); //public com.kuang.pojo.User() //public com.kuang.pojo.User(java.lang.String,int,int) } System.out.println("=========================="); Constructor[] declaredConstructors = c1.getDeclaredConstructors(); for (Constructor constructor:declaredConstructors){ System.out.println(constructor); //public com.kuang.pojo.User() //public com.kuang.pojo.User(java.lang.String,int,int) } System.out.println("=========================="); // 获得指定的构造器 Constructor constructor = c1.getConstructor(String.class, int.class, int.class); System.out.println(constructor);//public com.kuang.pojo.User(java.lang.String,int,int) // 后面没有参数 就是获得无参的构造器. Constructor constructor1 = c1.getConstructor(); System.out.println(constructor1); // public com.kuang.pojo.User() } }

    有了Class对象,能做什么?

    package com.kuang; import com.kuang.pojo.User; import com.sun.glass.ui.Accessible; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test9 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { Class c1 = Class.forName("com.kuang.pojo.User"); // 通过Class 对象的newInstance方法创建user对象 User user = (User) c1.newInstance(); // 本质是调用的无参构造器. System.out.println(user); //User{name='null', id=0, age=0} //如果没有无参构造,那么也可以通过有参构造器来创建对象 反射拿到构造方法.然后创建对象 Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); User user2 = (User) declaredConstructor.newInstance("小米", 001, 20); //反射拿到构造去后创建对象. System.out.println(user2); //User{name='小米', id=1, age=20} // 通过反射调用普通方法 User user3 = (User) c1.newInstance(); // 反射得到一个setName 方法. 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"); // 必须先设置这个可使用为true 才能 通过反射 给属性设值. name.setAccessible(true); name.set(user4,"狂神"); // 必须有上面的setAccessible 为true 取消安全检测. 不然为报错 权限不够(私有的不能). System.out.println(user4.getName()); //狂神 } }

    setAccessible 的介绍

    做一个性能对比测试

    package com.kuang; import com.kuang.pojo.User; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test10 { // 普通方式 public static void test01(){ 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 test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { Class c1 = Class.forName("com.kuang.pojo.User"); User user = (User) c1.newInstance(); //获取指定的方法 方法名, 参数类型 Method getName = c1.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 test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { Class c1 = Class.forName("com.kuang.pojo.User"); User user = (User) c1.newInstance(); Method getName = c1.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"); } public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { test01(); test02(); test03(); } } 测试结果: 普通方式执行10亿次是需要 :6ms 反射执行10亿次是需要 :2563ms 反射加关闭检测执行10亿次是需要 :1531ms

    反射操作泛型

    代码演示如下

    package com.kuang; import com.kuang.pojo.User; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.List; import java.util.Map; // 反射获得泛型 public class Test11 { public void test01(Map<String,User> map,List<String> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { //测试方法1 想拿到泛型 要先拿到方法. Method test01 = Test11.class.getDeclaredMethod("test01", Map.class, List.class); Type[] genericParameterTypes = test01.getGenericParameterTypes(); // 获得泛型类型的数组 for (Type genericParameterType : genericParameterTypes) { System.out.println(genericParameterType); //java.util.Map<java.lang.String, com.kuang.pojo.User> // java.util.List<java.lang.String> if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();// 获得真实的参数类型 for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); //class java.lang.String // class com.kuang.pojo.User //class java.lang.String } } } System.out.println("=================="); //测试方法2 想拿到泛型 要先拿到方法. Method test02 = Test11.class.getDeclaredMethod("test02", null); Type genericReturnType = test02.getGenericReturnType(); // 获得返回值类型. System.out.println(genericReturnType);//返回值类型只有一个. java.util.Map<java.lang.String, com.kuang.pojo.User> if(genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); //class java.lang.String //class com.kuang.pojo.User } } } }

    练习ORM

    代码演示

    package com.kuang; import java.lang.annotation.*; import java.lang.reflect.Field; // 练习反射操作注解 public class Test12 { public static void main(String[] args) throws NoSuchFieldException { Class c1 = Student2.class; // 通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); //@com.kuang.TableAnnotation(value=db_student) } //获得指定类上的注解的value的值. TableAnnotation tableAnnotation = (TableAnnotation) c1.getAnnotation(TableAnnotation.class); System.out.println(tableAnnotation.value());//db_student // 获得类中指定字段(属性)的注解 Field id = c1.getDeclaredField("id"); FieldAnnotation annotation = id.getAnnotation(FieldAnnotation.class); System.out.println(annotation.columnName());//db_id System.out.println(annotation.type());//int System.out.println(annotation.length());//10 } } @TableAnnotation("db_student") // 比如这个数据库的名字叫db_student 来注解. class Student2{ @FieldAnnotation(columnName = "db_name",type="varchar",length = "3") // 注明,它是db_的id, 类型int ,长度10位 private String name; @FieldAnnotation(columnName = "db_id",type="int",length = "10") // 注明,它是db_的id, 类型int ,长度10位 private int id; @FieldAnnotation(columnName = "db_age",type="int",length = "10") // 注明,它是db_的id, 类型int ,长度10位 private int 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 "Student{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; } } // 自定义的注解 //类名的注解 @Target(ElementType.TYPE) // 作用在类上 @Retention(RetentionPolicy.RUNTIME) // 运行级别 @interface TableAnnotation{ String value(); } // 属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldAnnotation{ String columnName(); String type(); String length(); }
    Processed: 0.016, SQL: 9