首先从运行原理了解为什么要用反射,当我们执行一段代码时,代码经过javac编译得到.class
的字节码文件,再经过类加载器的loadClass()方法创建Class类对象到堆中;当我们实例化一个对象时,该对象会自动匹配到对应堆中的Class类对象,进而调用方法,操作属性等。至此程序结束。
但通过上述方式,我们写好程序运行后,如果突然需要加载另一个类时,就需要停止运行并要写一段代码去实例化新需求的类,对服务器来说会造成一定的影响;这时就体现出了反射的优势,反射机制可以通过修改配置文件,而无需修改源码对类进行重新加载。
反射是动态获取信息及动态调用对象方法的方式,Java本身是一种静态语言,而经过反射后让Java有了一定的动态性,变为一种“准动态语言”。
通过外部文件配置,在不修改源码的情况下,来控制程序反射实例看不懂的话,后边自Class类开始会有各方法的分布介绍
A.java
package Sentiment.refelction; public class A { private String name="refelction"; public int age=10; public void a(){ System.out.println("this is =>A"); } public void b(){ System.out.println("this is =>B"); } }
re.properties(配置文件)
path=Sentiment.refelction.A method=a
此时如果我们想调用a()方法,有如下几种方法:
A cat = new A(); cat.a();
该方式读取后由于path类型为String,所以无法正常读取到我们的类方法
Properties properties = new Properties(); properties.load(new FileInputStream("re.properties")); String path = properties.get("path").toString(); //Sentiment.refelction.A String method = properties.get("method").toString(); // a new path().a(); //报错
这时就可以通过反射将String类型的path,转为Class类型的对象进行调用
//(1) 获取Class类型的对象c1 Class c1 = Class.forName(path); //System.out.println(c1); //(2) 通过c1 得到加载的类 Sentiment.refelction.A的对象实例 Object o = c1.newInstance(); System.out.println("o的运行类型是:"+o.getClass()); //(3)通过c1 得到加载的类Sentiment.refelction.A 的method的方法对象"a" Method method1 =c1.getMethod(method); //(4)通过method1 调用方法对象来实现调用方法 method1.invoke(o);//传统方法 对象.方法() ,反射 方法.invoke(对象)
此时如果用户,想要调用A.java中的b()方法,就体现出了反射的优势。
还是先看传统方法,需要将a改为b,即修改源码
A cat = new A(); cat.b();
而反射机制则可以通过修改配置文件,而无需修改源码。在用户需求较大时,可以完全体现反射优势
path=Sentiment.refelction.A method=a
可以动态的创建和使用对象(也是框架底层核心).使用灵活,没有反射机制,框架技术就失去底层支撑。
使用反射基本是解释执行,对执行速度有影响.
运行同一内容耗时对比
1.Class也是类,也继承Object类
2.Class类对象不是new出来的,而是系统创建的 (都是通过Classloader类创建的)
3.每个类的Class类对象,在内存中只有一份,因为类只加载一次
public class Class01 { public static void main(String[] args) throws ClassNotFoundException { //每个类的Class类对象,在内存中只有一份,因为类只加载一次 Class c1 = Class.forName("Sentiment.refelction.A"); Class c2 = Class.forName("Sentiment.refelction.A"); System.out.println(c1.hashCode()); System.out.println(c2.hashCode()); } }
4.每个类的实例都会记得自己是由哪个Class 实例所生成(如最开始的运行原理图所示Cat会找到对应的Cat类对象)
5.通过Class对象可以完整地得到一个类的完整结构,通过一系列API
6.Class对象是存放在堆的
7.类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码变量名,方法名,访问权限等等)
Car.java
package Sentiment.refelction; public class Car { public String brand="宝马"; public int price = 5000000; public String color = "白色"; @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", price=" + price + ", color='" + color + '\'' + '}'; } }
Class02.java
package Sentiment.refelction; import java.lang.reflect.Field; public class Class02 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException { String path="Sentiment.refelction.Car"; //1. 获取Car类对应的Class对象 Class c1 = Class.forName(path); //2. 输出c1 System.out.println(c1); //显示c1对象是哪个类的Class对象 Sentiment.refelction.Car System.out.println(c1.getClass());//输出c1运行类型 java.lang.Class //3.获取包名 System.out.println(c1.getPackage().getName()); //4.得到类的全路径 System.out.println(c1.getName()); //5. 通过c1创建对象实例 Car car = (Car)c1.newInstance(); System.out.println(car); //输出car时自动调用toString()方法 //6. 通过反射获取属性 Field brand = c1.getField("brand"); System.out.println(brand.get(car)); //7.通过反射给属性赋值 brand.set(car,"奔驰"); System.out.println(brand.get(car)); //8.获取所有属性及属性值 Field[] fields = c1.getFields(); for(Field f : fields){ System.out.print(f.getName()+":"); //属性名 System.out.print(f.get(car)+" "); //属性值 } } }
1.已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能跑出ClassNotFoundException
Class c1=Class.forName("Sentiment.refelction.Car")
多用于配置文件,读取类全路径,加载类
2.若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高
Class c2=Car.class
多用于参数传递,比如通过反射得到对应构造器对象
3.前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
Car car = new Car(); Class c3 = car.getClass();
多用于通过创建好的对象,获取Class对象.
4.通过类加载器来获取Class类对象
//(1)先得到加载器 ClassLoader classLoader = car.getClass().getClassLoader(); //(2)通过类加载器得到Class对象 Class c4 =classLoader.loadClass(path);
5.基本数据(int, char, boolean,float,double,byte,long,short)按如下方式得到Class类对象
Class c5 = 基本数据类型.class
6.基本数据类型对应的包装类,可以通过type得到Class类对象
Class c6 = 包装类.type
GetClass.java
package Sentiment.refelction; public class GetClass { public static void main(String[] args) throws ClassNotFoundException { //1.Class.forName) String path="Sentiment.refelction.Car"; //通过读取配置文件获取 Class c1 = Class.forName(path); System.out.println(c1); //2.类名.class,用于参数传递 Class c2 = Car.class; System.out.println(c2); //3.对象.getClass(),用于有对象实例 Car car = new Car(); Class c3 = car.getClass(); System.out.println(c3); //4.通过类加载器来获取Class类对象 //(1)先得到加载器car ClassLoader classLoader = car.getClass().getClassLoader(); //(2)通过类加载器得到Class对象 Class c4 =classLoader.loadClass(path); System.out.println(c4); //5.基本数据(int, char, boolean,float,double,byte,long,short)按如下方式得到Class类对象 Class c5 = int.class; Class<Character> characterClass = char.class; //6.基本数据类型对应的包装类,可以通过type得到Class类对象 Class<Integer> type = Integer.TYPE; Class<Character> type1 = Character.TYPE; System.out.println(type); }
静态加载:编译时加载相关的类,如果没有该类就会报错,依赖性很强
动态加载:运行时加载需要的类,如果运行时不用该类则不回加载,也不会报错,降低了依赖性
先看看常规的静态加载方法ClassLoad.java
package Sentiment.refelction; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Scanner; public class ClassLoad { public static void main(String[] args) throws Exception { Scanner scanner = new Scanner(System.in); String key = scanner.next(); switch (key){ case "1": Dog dog = new Dog(); dog.cry(); break; case "2": System.out.println("ok"); break; default: System.out.println("Do nothing!"); }} }
当编译时,即使还没有输入key=1
,也就是还没有调用new Dog()
就会报错找不到该类
而当使用动态加载,也就是反射机制时
package Sentiment.refelction; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Scanner; public class ClassLoad { public static void main(String[] args) throws Exception { Scanner scanner = new Scanner(System.in); String key = scanner.next(); switch (key){ //静态加载 case "1": //Dog dog = new Dog(); //dog.cry(); //break; //反射动态加载 case "2": Class c1 = Class.forName("Person"); Object o = c1.newInstance(); Method method = c1.getMethod("hi"); method.invoke(o); System.out.println("ok"); break; default: System.out.println("Do nothing!"); }} }
在没有调用Person类和hi方法的情况下,可以直接执行
当输入3时会调用default方法,并不会加载Person类,只有在key=2
需要加载Person类时,才会报错
上述方法应用实例:ReflectionUtils.java
package Sentiment.refelction; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionUtils { public static void main(String[] args) throws ClassNotFoundException { new ReflectionUtils().api(); } public void api() throws ClassNotFoundException { Class c1 = Class.forName("Sentiment.refelction.Person");//获取Class对象 //getName:获取全类名 System.out.println(c1.getName()); //getSimpleName:获取简单类名 System.out.println(c1.getSimpleName()); //getFields:获取所有pubulic修饰的属性,包括本类以及父类的 Field[] fields = c1.getFields(); for (Field field : fields) { System.out.println("本类以及父类的属性="+field.getName()); } //getDeclaredFields:获取本类中所有属性 Field[] declaredFields = c1.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性="+declaredField.getName()); } //getMethods:获取所有public修饰的方法,包含本类以及父类的(父类包括Object类) Method[] methods = c1.getMethods(); for (Method method : methods) { System.out.println("本类以及父类的public方法="+method.getName()); } //getDeclaredMethods:获取本类中的所有方法 Method[] declaredMethods = c1.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中的所有方法="+declaredMethod); } //getConstrctors:获取所有本类的public修饰的构造器 Constructor[] constructors = c1.getConstructors(); for (Constructor constructor : constructors) { System.out.println("本类的public构造器="+constructor); } //getDeclaredConstructors:获取本类中的所有构造器 Constructor[] declaredConstructors = c1.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.println("本类中的所有构造器= "+declaredConstructor); } //getPackage:以Package形式返回包信息 System.out.println("包信息"+c1.getPackage()); //getSuperClass:以Class形式返回父类信息 System.out.println("父类的class对象= "+c1.getSuperclass()); //getInterfaces:以Class[]形式返回接口信息 Class[] interfaces = c1.getInterfaces(); for (Class anInterface : interfaces) { System.out.println("接口信息= "+anInterface); } //getAnnotations:以Annotation[]形式返回注解信息 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("注解信息= "+annotation); } } } interface IA{ } interface IB{ } class B{ public String hobby; public void hi(){ } public B() { } } @Deprecated class Person extends B implements IA,IB{ //属性 public String name; protected int age; String job; private double sal; //方法 public void m1(){ } protected void m2(){ } void m3(){ } private void m4(){ } //构造方法 public Person() { } public Person(String name) { this.name = name; } }
运行结果(各方法间用---
分割)
Sentiment.refelction.Person ----------------------------- Person ----------------------------- 本类以及父类的属性=name 本类以及父类的属性=hobby ----------------------------- 本类中所有属性=name 本类中所有属性=age 本类中所有属性=job 本类中所有属性=sal ----------------------------- 本类以及父类的public方法=m1 本类以及父类的public方法=hi 本类以及父类的public方法=wait 本类以及父类的public方法=wait 本类以及父类的public方法=wait 本类以及父类的public方法=equals 本类以及父类的public方法=toString 本类以及父类的public方法=hashCode 本类以及父类的public方法=getClass 本类以及父类的public方法=notify 本类以及父类的public方法=notifyAll ----------------------------- 本类中的所有方法=protected void Sentiment.refelction.Person.m2() 本类中的所有方法=void Sentiment.refelction.Person.m3() 本类中的所有方法=private void Sentiment.refelction.Person.m4() 本类中的所有方法=public void Sentiment.refelction.Person.m1() ----------------------------- 本类的public构造器=public Sentiment.refelction.Person() 本类的public构造器=public Sentiment.refelction.Person(java.lang.String) ----------------------------- 本类中的所有构造器= public Sentiment.refelction.Person() 本类中的所有构造器= public Sentiment.refelction.Person(java.lang.String) ----------------------------- 包信息package Sentiment.refelction ----------------------------- 父类的class对象= class Sentiment.refelction.B ----------------------------- 接口信息= interface Sentiment.refelction.IA 接口信息= interface Sentiment.refelction.IB ----------------------------- 注解信息= @java.lang.Deprecated() -----------------------------
上述三类API实例代码:ReflectionUtils02.java
package Sentiment.refelction; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionUtils02 { public static void main(String[] args) throws ClassNotFoundException { new ReflectionUtils02().api2(); } public void api2() throws ClassNotFoundException { Class c1 = Class.forName("Sentiment.refelction.Student");//获取Class对象 System.out.println("------------------------------"); System.out.println("java.lang.feflect.Field类API"); System.out.println("------------------------------"); //getDeclaredFields:获取本类中所有属性 Field[] declaredFields = c1.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性="+declaredField.getName()+" 该类的属性值="+declaredField.getModifiers()+" 类型是="+declaredField.getType()); } System.out.println("------------------------------"); System.out.println("java.lang.reflect.Method类API"); System.out.println("------------------------------"); //getDeclaredMethods:获取本类中的所有方法 Method[] declaredMethods = c1.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中的所有方法="+declaredMethod.getName()+" 该方法的属性值="+declaredMethod.getModifiers()+" 该方法的返回类型="+declaredMethod.getReturnType()); //方法的形参类型 Class[] parameterTypes = declaredMethod.getParameterTypes(); for (Class parameterType : parameterTypes) { System.out.println("形参类型= "+parameterType); } } System.out.println("------------------------------"); System.out.println("java.lang.reflect.Constructor类API"); System.out.println("------------------------------"); //getDeclaredConstructors:获取本类中的所有构造器 Constructor[] declaredConstructors = c1.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.println("本类中的所有构造器= "+declaredConstructor.getName()+" 该构造器的属性值= "+declaredConstructor.getModifiers()); Class[] parameterTypes = declaredConstructor.getParameterTypes(); for (Class parameterType : parameterTypes) { System.out.println("形参类型= "+parameterType); } } }} class Student { //属性 int age; public String name; private String grade; protected static double score; //方法 public void m1(int age ,String name,double score){ } protected String m2(){ return null; } void m3(){ } private void m4(){ } //构造方法 Student() { } public Student(int age) { this.age = age; } private Student(int age, String name, String grade) { this.age = age; this.name = name; this.grade = grade; } }
运行结果(以---
做各类分割)
Object o = c3.newInstance();
Constructor constructor = c3.getConstructor(String.class); //先得到构造器 Object tana = constructor.newInstance("tana"); //创建实例,传入实参
setAccessible
爆破Constructor declaredConstructor = c3.getDeclaredConstructor(int.class,String.class); //先得到构造器 declaredConstructor.setAccessible(true); //爆破访问private构造器/方法/属性 Object mumu = declaredConstructor.newInstance(100, "mumu"); //创建实例,传入实参
实例代码:ReflectionCreate.java
package Sentiment.refelction; import java.lang.reflect.Constructor; public class ReflectionCreate { public static void main(String[] args) throws Exception { //获取类的Class对象 Class<?> c3 = Class.forName("Sentiment.refelction.User"); //通过public的无参构造器创建实例 Object o = c3.newInstance(); System.out.println(o); //通过pulic的有参构造创建实例 Constructor constructor = c3.getConstructor(String.class); Object tana = constructor.newInstance("tana"); System.out.println("tana = "+tana); //通过非public的有参构造器创建对象 Constructor<?> declaredConstructor = c3.getDeclaredConstructor(int.class,String.class); declaredConstructor.setAccessible(true); Object mumu = declaredConstructor.newInstance(100, "mumu");; System.out.println("mumu = "+mumu); } } class User{ //属性 private int age=10; private String name="Sentiment"; //构造方法 public User() { } public User(String name) { this.name = name; } private User(int age, String name) { this.age = age; this.name = name; } public String toString() { return "User{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
运行结果
User{age=10, name='Sentiment'} tana = User{age=10, name='tana'} mumu = User{age=100, name='mumu'}
获取public属性
Field age = c4.getField("age"); //age为属性名 age.set(o,100); //修改属性值;o为对象实例 System.out.println(age.get(o));
获取private属性
Field name = c4.getDeclaredField("name"); //name为属性名 name.setAccessible(true); //爆破 name.set(o,"tana"); //修改属性值,o为对象实例 System.out.println(name.get(null)); //static修饰的对象,也可以用null代替
实例代码:ReflectionCreate02.java
package Sentiment.refelction; import java.lang.reflect.Field; public class ReflectionCreate02 { public static void main(String[] args) throws Exception{ Class c4 = Class.forName("Sentiment.refelction.human"); Object o = c4.newInstance(); //获取public属性 Field age = c4.getField("age"); age.set(o,100); //修改属性值 System.out.println(age.get(o)); //获取private属性 Field name = c4.getDeclaredField("name"); name.setAccessible(true); name.set(o,"tana"); //修改属性值 System.out.println(name.get(null)); } } class human{ //属性 public int age=10; private static String name ="Sentiment"; //构造器 public human() { } @Override public String toString() { return "human{" + "age=" + age +", name"+name+'}'; } }
运行结果
100 tana
调用public方法
Method say1 = c5.getMethod("say1", String.class); //say1为String类型的方法 say1.invoke(o,"Sentiment");
调用private方法
Method say2 = c5.getDeclaredMethod("say2", int.class, String.class, char.class); //say2方法及其类型 say2.setAccessible(true); System.out.println(say2.invoke(o,10,"tana",'M'));
实例代码:ReflectionCreate03.java
package Sentiment.refelction; import java.lang.reflect.Method; public class ReflectionCreate03 { public static void main(String[] args) throws Exception{ Class c5 = Class.forName("Sentiment.refelction.man"); Object o = c5.newInstance(); //调用public方法 Method say1 = c5.getMethod("say1", String.class); say1.invoke(o,"Sentiment"); //调用private方法 Method say2 = c5.getDeclaredMethod("say2", int.class, String.class, char.class); say2.setAccessible(true); System.out.println(say2.invoke(o,10,"tana",'M')); System.out.println(say2.invoke(null,20,"mumu",'M')); //静态方法可以用null代替实例对象 } } class man{ //属性 public int age; private static String name; //构造方法 public man() { } //方法 public void say1(String a){ System.out.println("this is =>"+a); } private static String say2(int a,String b, char c){ return a+" "+b+" "+c; } }
Work1.java
package Sentiment.refelction; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Work1 { public static void main(String[] args) throws Exception{ Class c1 = Class.forName("Sentiment.refelction.Test"); Object o = c1.newInstance(); Field name = c1.getDeclaredField("name"); name.setAccessible(true); name.set(o,"tana"); Method getName = c1.getMethod("getName"); System.out.println(getName.invoke(o)); } } class Test{ private String name = "Sentiment"; public String getName(){ return name; } }
a.txt
Work2.java
package Sentiment.refelction; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class Work2 { public static void main(String[] args) throws Exception{ Class c2 = Class.forName("java.io.File"); Constructor[] c = c2.getDeclaredConstructors(); for (Constructor Constructor : c) { System.out.println(Constructor); } //获取构造器public java.io.File(java.lang.String) Constructor declaredConstructor = c2.getDeclaredConstructor(String.class); String path="D:\\a.txt"; //实例化类 Object path1 = declaredConstructor.newInstance(path); //获取createNewFile方法 Method createNewFile = c2.getMethod("createNewFile"); createNewFile.invoke(path1); System.out.println(path1.getClass()); System.out.println("创建文件成功:"+path); } }