第一章:注解
一:注解引入
Annotation是从jdk5.0引入的技术,注解和反射是很多框架的实现的方式
二:注解作用
不是程序本身:可以对程序作出解释,这一点和注释没有任何区别。
可以被其他程序,例如编译器进行读取,作为一定的标志。
检查和约束,例如:不是正确的重写的方法,上边的@Override就会报错。
三:注解定义格式
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @interface Fieldkuang{ String column(); String type(); int length(); }
四:注解分类
1:元注解
元注解是解释其他注解的注解,Java当中只有四个元注解 TRDI
@Target:这个注解描述非元注解的使用的位置。这个注解用于描述被修饰注解的使用时放置的位置,非元注解值得就是内置注解和自定义注解,注解所在的包位于,java.lang.annotation包下
@Retention:这个注解描述的是被修饰的注解的生命周期,作用时间分别为source < class< runtime三种情况
@Document:注解表示被修饰的注解被包含在JavaDoc当中
@Inherited:说明子类可以继承父类中被此注解修饰的注解。
2:内置注解
内置注解就是java自带的注解。
@SuppressWarnings(“all”)抑制编译器警告
@Deprecated 表示:某个程序元素(类、方法等)已过时
@SafeVarargs (JDK1.7更新) 表示:专门为抑制“堆污染”警告提供的。
@FunctionalInterface注明这是函数式接口
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
五:自定义注解
自定义注解时,自动继承了java.lang.annotation接口。
@interface用于声明注解,可以public,可以非public,注解中看似像方法的东西其实是一个个参数,方法名就是参数名的名称,获取时采用 注解对象.参数名()进行获取,返回值类型的位置就是参数的类型(基本类型,Class,String,Enum,数组),可以通过default赋值,默认值一般为0或者“”,注解有默认值我们可以不用赋值,注解没有默认值使用的时候必须手动赋值,如果只有一个参数,我们经常叫做value,如果叫做value,赋值的时候可以value = 进行省略,注解可以通过反射机制进行元数据的访问,所以反射+注解的形式会被大量应用在框架中。
//定义一个注解: //@Target(value = ElementType.METHOD) //target表示我们的注解可以使用在什么位置 @Target(value = {ElementType.METHOD,ElementType.TYPE}) //retention表示我们的注解什么时候有效,retention默认是runtime @Retention(value = RetentionPolicy.RUNTIME) //表示是否将我们的注解保存奥Javadoc当中 @Documented //表示是否子类是否可以集成父类中的该注解。 @Inherited @interface MyAnnotation{ String [] value() default {""}; }
第二章:反射
一:创建对象的四种方式
用new语句创建对象,这是最常用的创建对象的方式
运用反射手段,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法
调用对象的clone()方法
运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法
二:反射机制
1:动态语言
动态语言是运行时可以改变其结构的语言,运行时代码可以根绝某些条件改变自身结构。
2:静态语言
静态语言是指运行时不能改变其代码的自身结构的语言。
反射允许程序在执行期间使用反射的api读取类中的内部信息,并能直接从操作任意对象的内部属性和内部方法。
三:反射可以提供的功能
在运行时判断任意一个对象所属的类,构造任意一个类的对象
运行时获取和调用任意一个类的属性和方法
运行时获取区类中任意位置的泛型信息和注解信息
生成动态代理
四:反射的优缺点
实现动态创建对象和编译,体现出很大的灵活性。
对性能有影响,反射基本上是一种解释性工作,性能较低。
五:反射主要的API
- java.lang.Class:反射的核心类。
- java.lang.reflect.Field:类的变量
- java.lang.reflect.Method:类的方法
- java.lang.reflect.Constructor:类的构造器
- java.lang.reflect.ParameterizedType:类的泛型
- java.lang.annotation.Annotation:类的注解
第三章:Class类和Class对象
一:Class类
Class类是反射中的核心类,这个类是java反射的源头。
二:Class对象
- 获取java中任何一个类都只有一个Class对象,获取这种Class对象共有五中,包含三种常规方法和两种特有的方法。
三:获取Class对象
1:类名.class
2:对象.getClass()此方法继承自Object
3:Class.forName(“com.yuming.mokuaiming.Name”)
4:内置基本类型数据可以直接用类名.Type
5:还可以使用ClassLoader类加载器
package reflaction; /** 这个类用于说明,不同方式得到的Class对象是一个。 */ public class Test02 extends Object { public static void main(String[] args) throws ClassNotFoundException { //通过反射获取类的class对象 Class clazz1 = Class.forName("reflaction.User"); System.out.println(clazz1);//class reflaction.User Class clazz2 = Class.forName("reflaction.User"); Class clazz3 = Class.forName("reflaction.User"); Class clazz4 = Class.forName("reflaction.User"); System.out.println(clazz1.hashCode()); System.out.println(clazz2.hashCode()); System.out.println(clazz3.hashCode()); System.out.println(clazz4.hashCode()); // 460141958 // 460141958 // 460141958 一个类在内存中只有一个Class对象,一个类被加载后,整个类的结构都会被封装在这个Class对象当中。 // 460141958 hashcode相同说明是一个类。 } } //实体类,类中只有属性;pojo entity class User{ private int id; private int age; private String name; public User(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } void show(){} public User() { } 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 "User{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } }
/** 创建Class对象的五中方式 */ package reflaction; 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("reflaction.Student"); System.out.println(c2.hashCode()); //方式三:通过类名.class可以直接获得。 Class c3 = Student.class; System.out.println(c3.hashCode()); // 这个人是:学生 // 460141958 // 460141958 // 460141958 //方式四:基本内置类型的包装类都有一个TYPE属性, Class c4 = Integer.TYPE; System.out.println(c4); //int Class c5 = c1.getSuperclass(); System.out.println(c5); //class reflaction.Person } }
四:Class对象的细节补充
Class对象只能有系统进行建立
一个加载的类在JVM当中只能有一个Class对象,无论是采用哪种方式获得
一个Class对象对应的是加载到JVM当中的一个Class文件
每个类的实例都会记得自己是由哪个Class实例产生
通过Class对象可以完整的得到一个类中所有被加载的结构细节信息
Class类是反射的根源,动态加载、运行的类都必须获得响应的Class对象
1:JAVA动态加载类和静态加载类的区别
new创建对象的方式称作为静态加载,而使用Class.forName(“XXX”)称作为动态加载,它们俩本质的区别在于静态加载的类的源程序在编译时期加载(必须存在,必须导入类,并且new他的对象)而动态加载的类在编译时期可以缺席(源程序不必存在,写入类的路径就可以骗过编译器)
2:Class类的常用方法
##:3:都有哪些类可以有Class对象
共计七种:
- Class:Class类本身、外部类、内部类:成员(成员内部类,静态内部类,局部内部类,匿名内部类)
- interface 接口
- 数组(一维数组+二维数组)
- 枚举
- 注解
- 基本数据类型
- Void
package reflaction; import java.lang.annotation.ElementType; //所有类型的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 //只要元素的类型和维度是一样的,Class就是一样的。 int[] a = new int[10]; int[] b = new int[20]; System.out.println(a.getClass().hashCode() == b.getClass().hashCode()); //类 System.out.println(c1); //class java.lang.Object //接口 System.out.println(c2); //interface java.lang.Comparable //一维数组 System.out.println(c3); //class [Ljava.lang.String; //二维数组 System.out.println(c4); //class [[I //注解 System.out.println(c5); //interface java.lang.Override //枚举 System.out.println(c6); //class java.lang.annotation.ElementType //基本数据类型 System.out.println(c7); //class java.lang.Integer //void System.out.println(c8); //void //Class System.out.println(c9); //class java.lang.Class } }
4:反射获取类的运行时结构
创建运行时类的对象,首先需要获取运行时类的结构,这是两个不同的概念。
通过反射获取类运行时的完整的结构包括:
1、 实现的全部的接口。
2、 所继承的父类。
3、 所有的构造器
4、 所有的属性
5、 所有的方法
6、 所有的注解。
动态获取类的构造的对象。
package reflaction; /** * 获取类的信息 * */ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //获取类的信息 public class Test08 {//alt + shift + enter --方法上直接抛出异常信息。 public static void main(String[] args) throws Exception{ Class c1 = Class.forName("reflaction.User"); //获取类的名字 System.out.println(c1.getName());//reflaction.User 这个是全限定类名。 System.out.println(c1.getSimpleName());//User 这个是单纯的类名。 //获得类的属性 //只能获取public修饰的属性 System.out.println("===================================="); Field[] fields = c1.getFields(); //fields.for可以快速实现foreach。 for (Field field : fields) { System.out.println(field); } //可以获取所有类型的属性 System.out.println("===================================="); Field[] fields1 = c1.getDeclaredFields(); for (Field field : fields1) { System.out.println(fields); // [Ljava.lang.reflect.Field;@74a14482 // [Ljava.lang.reflect.Field;@74a14482 // [Ljava.lang.reflect.Field;@74a14482 } //获取指定名称的属性--只能找到public类型的属性 // Field field = c1.getField("name");因为找不到这个属性所以会抛出一个NoSuchFieldException,程序碰到异常之后就会停止。 // System.out.println(field); //获取指定名称的属性--可以找到任何类型的属性 Field field1 = c1.getDeclaredField("name"); System.out.println(field1);//private java.lang.String reflaction.User.name //获取类的方法 //1、获取所有类的方法--获取本类和父类所有的public修饰的方法 Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println(method); // public java.lang.String reflaction.User.toString() // public java.lang.String reflaction.User.getName() // public int reflaction.User.getId() // public void reflaction.User.setName(java.lang.String) // public void reflaction.User.setId(int) // public int reflaction.User.getAge() // public void reflaction.User.setAge(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() //2、获取本类的所有的public和非public的方法 System.out.println("============================================="); Method[] methods1 = c1.getDeclaredMethods(); for (Method method1 : methods1) { System.out.println(method1); // public java.lang.String reflaction.User.toString() // public java.lang.String reflaction.User.getName() // public int reflaction.User.getId() // public void reflaction.User.setName(java.lang.String) // public void reflaction.User.setId(int) // void reflaction.User.show() // public void reflaction.User.setAge(int) // public int reflaction.User.getAge() } //3、获取指定方法 Method method1 = c1.getMethod("getName",null); Method method2 = c1.getMethod("setName",String.class); // System.out.println(method1);public java.lang.String reflaction.User.getName() // System.out.println(method2);public void reflaction.User.setName(java.lang.String) //获取构造器 //1、获取本类的所有的public的构造器 System.out.println("=============================================="); Constructor[] constructors = c1.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); // public reflaction.User(int,int,java.lang.String) // public reflaction.User() } //2、获取本类的所有的public和非public的构造器 System.out.println("=============================================="); Constructor[] constructor1 = c1.getDeclaredConstructors(); for (Constructor constructor : constructor1) { System.out.println(constructor); // public reflaction.User(int,int,java.lang.String) // public reflaction.User() } //3、获取指定名称的构造器 System.out.println("==============================================="); Constructor constructor = c1.getConstructor(int.class,int.class,String.class); System.out.println(constructor); constructor = c1.getConstructor(Integer.TYPE,Integer.TYPE,"".getClass()); System.out.println(constructor); constructor = c1.getConstructor(Integer.TYPE,Integer.TYPE,Class.forName("java.lang.String")); System.out.println(constructor); constructor = c1.getDeclaredConstructor(Integer.TYPE,Integer.TYPE,"".getClass()); System.out.println(constructor); constructor = c1.getDeclaredConstructor(Integer.TYPE,Integer.TYPE,Class.forName("java.lang.String")); System.out.println(constructor); // public reflaction.User(int,int,java.lang.String) // public reflaction.User(int,int,java.lang.String) // public reflaction.User(int,int,java.lang.String) // public reflaction.User(int,int,java.lang.String) // public reflaction.User(int,int,java.lang.String) } } }
package reflaction; /** * 动态获取类运行时结构的对象 * */ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //动态的创建类的运行时结构对象 public class Test09 { public static void main(String[] args) throws Exception { //获得User的Class对象 Class c1 = Class.forName("reflaction.User"); //创建一个User对象 //本质上是调用了类的无参构造器。--如果没有无参构造器,就会报错。 // User user = (User)c1.newInstance(); // System.out.println(user); //通过构造器对象如何创建对象 // Constructor constructor = c1.getConstructor(String.class, int.class, int.class); Constructor constructor = c1.getConstructor(int.class, int.class, String.class); //参数的个数、类型、顺序必须实际构造器保持一致。 User user1 =(User)constructor.newInstance(001,10,"秦江"); System.out.println(user1); //通过反射调用普通方法 User user3 = (User)c1.newInstance(); //获取指定名称的方法 Method setName = c1.getDeclaredMethod("setName", String.class); //激活方法执行方法--invoke(谁的方法,方法的参数) 返回值是原方法的返回值,原方法没有则返回null setName.invoke(user3, "kuangshen"); System.out.println(user3); System.out.println(user3.getName());//kuangshen //通过方法调用属性 User user4 = (User)c1.newInstance(); Field field = c1.getDeclaredField("name"); /** * 不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessble方法。 * */ field.setAccessible(true);//这样就不检查属性是否是private了。默认是FALSE field.set(user4,"狂神2"); //Class reflaction.Test09 can not access a member of class reflaction.User with modifiers "private" System.out.println(user4.getName());//狂神2 } }
4:关闭私有检查的效率问题
package reflaction; import java.lang.reflect.Method; //比较性能问题 public class Test10 { public static void main(String[] args) throws Exception { //普通方式 test01(); test02(); test03(); // 普通方式执行10亿次:0ms // 反射不关闭执行10亿次:2437ms // 反射关闭私有检查执行10亿次:1109ms 关闭之后效率提升了两到三倍。 } private 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");//普通方式执行10亿次:10ms } private static void test02() throws Exception { Class c1 = Class.forName("reflaction.User"); User user = new User(); Method method = c1.getMethod("getName",null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { method.invoke(user); } long endTime = System.currentTimeMillis(); System.out.println("反射不关闭执行10亿次:"+(endTime - startTime)+"ms");//普通方式执行10亿次:2347ms } private static void test03() throws Exception { Class c1 = Class.forName("reflaction.User"); User user = new User(); Method method = c1.getMethod("getName",null); method.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { method.invoke(user); } long endTime = System.currentTimeMillis(); System.out.println("反射关闭执行10亿次:"+(endTime - startTime)+"ms");//普通方式执行10亿次:1206ms } }
5:反射构建类运行时结构对象-泛型
package reflaction; import sun.reflect.generics.tree.ReturnType; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; //通过反射获取泛型 public class Test11 { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws Exception { Method method = Test11.class.getMethod("test01",Map.class,List.class); //获取带有泛型的参数类型 Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println(genericParameterType);//例如:java.util.Map<java.lang.String, reflaction.User> if(genericParameterType instanceof ParameterizedType){ //获取带有泛型的参数类型中的真实泛型类型 Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument.getTypeName());//例如:java.lang.String,,reflaction.User } } } // java.util.Map<java.lang.String, reflaction.User> // java.lang.String // reflaction.User // java.util.List<reflaction.User> // reflaction.User System.out.println("==========================================================="); Method test02 = Test11.class.getMethod("test02",null); Type genericReturnType = test02.getGenericReturnType(); if(genericReturnType instanceof ParameterizedType){ System.out.println(genericReturnType.getTypeName()); Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument.getTypeName());//例如:java.lang.String,,reflaction.User } } } }
6:反射获取类运行时结构对象-注解
package reflaction; //练习反射操作注解。 /* * 通过反射操作注解,我们以后用到的框架当中都是这样写的, * 他们在类中会有大量的注解,通过反射读取这个注解,进行 * 响应的操作。 */ import java.lang.annotation.*; import java.lang.reflect.Field; public class Test12 { public static void main(String[] args) throws Exception { Class c1 = Class.forName("reflaction.Student2"); //通过反射获取注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); //@reflaction.Tablekuang(value=db_student) } //获取注解value的值 Tablekuang annotation = (Tablekuang)c1.getAnnotation(Tablekuang.class); String value = annotation.value(); System.out.println(value);//db_student //获得类指定的注解 Field name = c1.getDeclaredField("name"); Fieldkuang fieldkuang = name.getAnnotation(Fieldkuang.class); System.out.println(fieldkuang.column()); // db_id System.out.println(fieldkuang.type()); // varchar System.out.println(fieldkuang.length()); // 10 } } @Tablekuang("db_student") class Student2{ @Fieldkuang(column = "db_id",type = "int",length = 10) private int id; @Fieldkuang(column = "db_id",type = "int",length = 10) private int age; @Fieldkuang(column = "db_id",type = "varchar",length = 10) private String 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 + '\'' + '}'; } } @SuppressWarnings("all") @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @interface Tablekuang{ String value() ; } @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @interface Fieldkuang{ String column(); String type(); int length(); }