Java反射学习笔记
反射机制:指的是可以在运行时加载,使用编译期间完全未知的类,
程序在于行状态中,可以动态的加载一个只有名称的类,对于任意一个已加载的类,都能够通过反射知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性
如何理解Class对象:在Java中万事万物皆对象,我们都知道类是对象的模板,通过类我们可以创建该类的实例。
那么我们有没有想过类又是谁的实例对象呢?答案是类Class的对象,我们可以这样理解,There have a class named Class,类也是对象。
创建Class的三种方式:例如
1 Class c = Class.forName("com.xvl.test.student");
2 对象.getClass();
3 类名.class;
eg: Student student = new Student(); //假如这个类在com.xvl.test包里面
1 Class c = Class.forName("com.xvl.test.student"); //c就是Student类的类类型,也是Class类的实例对象
2 Class c1 = Student.class;
3 Class c2 = student.getClass();
注意:c == c1 == c2
加载完类之后,在堆内存中就产生了一个Class对象(注意:一个类只有一个Class对象)这个对象就包含了完整类的信息结构,就像是一面镜子所以称之为反射。
反射Demo1:
1 package cn.xvl.reflection; 2 3 public class person { 4 public int id; 5 private String name; 6 private int number; 7 8 public person(int id, String name, int number) { 9 super(); 10 this.id = id; 11 this.name = name; 12 this.number = number; 13 } 14 15 public person() { 16 } 17 18 public int getId() { 19 return id; 20 } 21 public String getName() { 22 return name; 23 } 24 public int getNumber() { 25 return number; 26 } 27 public void setId(int id) { 28 this.id = id; 29 } 30 public void setName(String name) { 31 this.name = name; 32 } 33 public void setNumber(int number) { 34 this.number = number; 35 } 36 37 }
运用反射操作Person类
1 package cn.xvl.reflection; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.InvocationTargetException; 6 import java.lang.reflect.Method; 7 8 /** 9 * 通过反射api动态操作:构造器 属性 方法 10 * @author 1 11 * 12 */ 13 public class demo03 { 14 public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { 15 //通过反射创建新对象 16 Class<person> c = (Class<person>) Class.forName("cn.xvl.reflection.person"); 17 person p1 =c.newInstance(); //此处调用了person的无参数构造方法 javabean必须有无参构造 18 p1.setId(20); 19 System.out.println(p1.getId()); 20 //获取有参构造 21 Constructor<person> con = c.getDeclaredConstructor(int.class,String.class,int.class); 22 //使用有参构造创建对象 23 person p2 =con.newInstance(18,"张三",1); 24 System.out.println(p2.getId()+"-->"+p2.getName()+"-->"+p2.getNumber()); 25 26 27 //通过反射调用普通方法 28 person p3 =(person)c.newInstance(); 29 Method m = c.getDeclaredMethod("setName", String.class); //有几个参数就传几个因为是可变参数... 30 m.invoke(p1, "张三"); //就相当于p1.setName; 原有方法返回值类型是void则返回null 31 System.out.println(p1.getName()); 32 33 34 //通过反射操作属性 不能直接操作私有属性 但是可以设置安全检查操作私有属性 35 Field f = c.getDeclaredField("id"); 36 f.setAccessible(true);//设置安全检查 意思是这个私有属性不需要做安全检查,可以直接访问 37 f.set(p1, 17); //通过反射直接写属性 38 System.out.println(f.get(p1));//通过反射直接读取属性 39 System.out.println(p1.getId()+"-->"+p1.getName()); 40 } 41 }
反射demo2 获取一个类的信息(方法 属性)
1 package cn.xvl.reflection1; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 6 public class ClassUtil { 7 8 //获取类的全部信息 包括类的成员函数成员变量 9 public static void getClassMessage(Object object) { 10 //获取类的类类型 11 Class class1 = object.getClass(); 12 //获取类的名称 13 System.out.println("类名:"+class1.getName()); 14 //获取类的方法 15 /* 16 * 一个成员方法就是一个method对象 17 * getMethods() 获取的是所有的public函数 包括父类继承而来的方法 18 * getDeclaredMethods() 获取的是所有该类自己声明的方法 包括private方法 不包含父类继承而来的方法 19 */ 20 Method[] method = class1.getMethods(); 21 for (int i = 0; i < method.length; i++) { 22 //得到方法返回值的*类类型*、 23 Class rt = method[i].getReturnType(); 24 System.out.print(rt.getName()+" "); 25 //得到方法的名称 26 System.out.print(method[i].getName()+"("); 27 //获取参数类型 ---->得到的是参数列表的类类型 如果参数是int string 那么得到的是int.class string.class并将其放在参数数组中 28 Class[] param = method[i].getParameterTypes(); 29 for (Class class2 : param) { 30 System.out.print(class2.getName()+","); 31 } 32 System.out.println(")"); 33 } 34 35 /* 36 * 成员变量也是对象 37 * java.lang.reflect.Field封装了关于成员变量的操作 38 * getFields()获取的是所有的public的成员变量 **注意是public变量 不能获取私有的变量 39 * getDeclaredFields()获取的是所有该类自己声明的成员变量包括private变量 40 */ 41 42 Field[] fields = class1.getFields(); 43 for (Field field : fields) { 44 //得到成员变量类型的类类型 45 Class ty = field.getType(); 46 //得到成员变量类型的名字 47 String tyName= ty.getName(); 48 //得到成员变量的名字 49 String fieldName = field.getName(); 50 System.out.println("typename"+"-->"+fieldName); 51 } 52 } 53 }
1 package cn.xvl.reflection1; 2 3 public class test { 4 public static void main(String[] args) { 5 String string = "张三"; 6 ClassUtil.getClassMessage(string); 7 } 8 }
测试结果:
类名:java.lang.String
boolean equals(java.lang.Object,)
java.lang.String toString()
int hashCode()
int compareTo(java.lang.String,)
int compareTo(java.lang.Object,)
int indexOf(java.lang.String,int,)
int indexOf(java.lang.String,)
int indexOf(int,int,)
int indexOf(int,)
java.lang.String valueOf(int,)
java.lang.String valueOf(long,)
java.lang.String valueOf(float,)
java.lang.String valueOf(boolean,)
java.lang.String valueOf([C,)
java.lang.String valueOf([C,int,int,)
java.lang.String valueOf(java.lang.Object,)
java.lang.String valueOf(char,)
java.lang.String valueOf(double,)
char charAt(int,)
int codePointAt(int,)
int codePointBefore(int,)
int codePointCount(int,int,)
int compareToIgnoreCase(java.lang.String,)
java.lang.String concat(java.lang.String,)
boolean contains(java.lang.CharSequence,)
boolean contentEquals(java.lang.CharSequence,)
boolean contentEquals(java.lang.StringBuffer,)
java.lang.String copyValueOf([C,)
java.lang.String copyValueOf([C,int,int,)
boolean endsWith(java.lang.String,)
boolean equalsIgnoreCase(java.lang.String,)
java.lang.String format(java.util.Locale,java.lang.String,[Ljava.lang.Object;,)
java.lang.String format(java.lang.String,[Ljava.lang.Object;,)
void getBytes(int,int,[B,int,)
[B getBytes(java.nio.charset.Charset,)
[B getBytes(java.lang.String,)
[B getBytes()
void getChars(int,int,[C,int,)
java.lang.String intern()
boolean isEmpty()
java.lang.String join(java.lang.CharSequence,[Ljava.lang.CharSequence;,)
java.lang.String join(java.lang.CharSequence,java.lang.Iterable,)
int lastIndexOf(int,)
int lastIndexOf(java.lang.String,)
int lastIndexOf(java.lang.String,int,)
int lastIndexOf(int,int,)
int length()
boolean matches(java.lang.String,)
int offsetByCodePoints(int,int,)
boolean regionMatches(int,java.lang.String,int,int,)
boolean regionMatches(boolean,int,java.lang.String,int,int,)
java.lang.String replace(char,char,)
java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence,)
java.lang.String replaceAll(java.lang.String,java.lang.String,)
java.lang.String replaceFirst(java.lang.String,java.lang.String,)
[Ljava.lang.String; split(java.lang.String,)
[Ljava.lang.String; split(java.lang.String,int,)
boolean startsWith(java.lang.String,int,)
boolean startsWith(java.lang.String,)
java.lang.CharSequence subSequence(int,int,)
java.lang.String substring(int,)
java.lang.String substring(int,int,)
[C toCharArray()
java.lang.String toLowerCase(java.util.Locale,)
java.lang.String toLowerCase()
java.lang.String toUpperCase()
java.lang.String toUpperCase(java.util.Locale,)
java.lang.String trim()
void wait()
void wait(long,int,)
void wait(long,)
java.lang.Class getClass()
void notify()
void notifyAll()
java.util.stream.IntStream chars()
java.util.stream.IntStream codePoints()
typename-->CASE_INSENSITIVE_ORDER
注意:
setAccessible():启用和禁用访问安全检查的开关,置为true表示反射的对象在使用时应该取消Java语言访问检查,值为false表示应该实施Java语言访问检查,禁止安全检查,可以提高反射运行速度。
demo3 反射与普通方法对比
1 package cn.xvl.reflection; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 /* 7 * 反射性能对比 8 * 反射会降低性能 9 */ 10 public class demo04 { 11 public static void test01(){ 12 person p = new person(); 13 long starttime = System.currentTimeMillis(); 14 for (int i = 0; i < 1000000000 ; i++) { 15 p.setId(20); 16 } 17 long endtime = System.currentTimeMillis(); 18 System.out.println("普通方法耗时"+(endtime-starttime)); 19 } 20 public static void test02() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{ 21 Class clazz = (Class<person>) Class.forName("cn.xvl.reflection.person"); 22 Method m = clazz.getDeclaredMethod("setId", int.class); 23 person p =(person) clazz.newInstance(); 24 long starttime = System.currentTimeMillis(); 25 for (int i = 0; i < 1000000000; i++) { 26 m.invoke(p, 20); 27 } 28 long endtime = System.currentTimeMillis(); 29 System.out.println("反射耗时"+(endtime-starttime)); 30 } 31 public static void test03() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ 32 Class clazz = (Class<person>) Class.forName("cn.xvl.reflection.person"); 33 Method m = clazz.getDeclaredMethod("setId", int.class); 34 person p =(person) clazz.newInstance(); 35 m.setAccessible(true); 36 long starttime = System.currentTimeMillis(); 37 for (int i = 0; i < 1000000000; i++) { 38 m.invoke(p, 20); 39 } 40 long endtime = System.currentTimeMillis(); 41 System.out.println("反射不进行安全检查耗时"+(endtime-starttime)); 42 } 43 public static void main(String[] args) { 44 test01(); 45 try { 46 test02(); 47 } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException 48 | IllegalArgumentException | InvocationTargetException | InstantiationException e) { 49 // TODO Auto-generated catch block 50 e.printStackTrace(); 51 } 52 try { 53 test03(); 54 } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException 55 | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 56 // TODO Auto-generated catch block 57 e.printStackTrace(); 58 } 59 } 60 }
测试结果:
普通方法耗时26ms
反射耗时1872ms
反射不进行安全检查耗时1238ms