Java反射机制是在运行状态中
类
,都能够知道这个类的所有属性
和方法
;对象
,都能够调用这个对象的所有属性
和方法
。这种动态获取信息以及动态调用对象的功能称为Java语言的反射机制。即,通过反射,该类对我们来说是完全透明的,可以获取任何有关它的信息。
Class.newInstance()
)就可完成。实例:
package reflection.testdemo; interface Fruit { // 水果接口 public void eat() ; // 吃水果 } class Apple implements Fruit{ // 定义苹果 public void eat() { System.out.println("吃苹果。"); } } class Orange implements Fruit{ public void eat() { System.out.println("吃橘子。"); } } class Factory{ public static Fruit getInstance(String className){ Fruit fruit = null ; try{ fruit = (Fruit) Class.forName(className).newInstance() ; }catch(Exception e ){ e.printStackTrace() ; } return fruit ; } } public class FactoryDemo{ public static void main(String args[]){ // 通过工厂类取得接口实例,传入完整的包.类名称 Fruit fruit = Factory.getInstance("reflection.testdemo.Apple") ; if(fruit != null){ // 判断是否取得接口实例 fruit.eat() ; } } }
如果不用反射,那么如果再加一个西瓜类,就得在Factory里判断,每添加一个类都要修改一次Factory。但用了反射,只用在调用的时候传入完整的类名就可完成。
结果:用反射,修改一处代码;不用反射,修改两处代码。
Java有3种方法可以获取Class信息:
类名.class
获取类信息(静态)
类
的静态变量class
获取:Class cls = String.class;
。Class.forName("类名")
获取类信息 (动态)
Class类
的完整类名,可以通过静态方法Class.forName()
获取:Class cls = Class.forName("类名");
。obj.getClass()
获取类信息。运行期间,通过当前对象获取类信息
getClass()
方法获取:String s = "Hello"; Class cls = s.getClass();
。获得Class后,可以调用具体的方法:
Method[] all = cls.getDeclaredMethods()
动态获取类的方法
信息;Field[] all = cls.getDeclaredFields()
动态获取类声明的属性
信息;Constructor[] constructors = cls.getDeclaredConstructors()
动态获取类的构造器
信息;获取方法:
// 动态加载类 Class cls = Class.forName(className); // 动态获取类的方法信息 Method[] all = cls.getDeclaredMethods();
实例:
package class_information; import java.lang.reflect.Method; /** * 动态获取类的方法信息 * getDeclaredMethods * * 类的全名:class_information.Foo * 编译后:class_information.Foo.class * @author chenzufeng */ public class Foo { public int test() { return 5; } public double test1() { return 5d; } public static void main(String[] args) { getClassMethod(); } /** * 动态的加载类信息到方法区,并且返回对应的Class对象! * Class对象可以访问类的全部信息! * * 将className对应的类文件,从磁盘中加载到内存方法区,返回这个类的信息 */ public static void getClassMethod() { String className = "class_information.Foo"; try { // 动态加载类 Class cls = Class.forName(className); // 动态获取类的方法信息 Method[] all = cls.getDeclaredMethods(); for (Method method : all) { System.out.println(method.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
输出结果:
main test getClassMethod test1
实例:
package class_method; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * 动态调用类的方法 * @author chenzufeng */ public class InvokeClassMethod { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { List<String> list = new ArrayList<>(); list.add("Tom"); list.add("Jack"); // 1. 动态获取类信息 Class cls = list.getClass(); // 2. 通过[方法名]和[参数类型]找到对应的方法:remove Method method = cls.getDeclaredMethod("remove", new Class[] {int.class}); // 3. 调用方法,传递对象和具体参数 Object value = method.invoke(list, new Object[] {0}); System.out.println(value); // Tom } }
获取方法:
// 动态加载类 Class cls = Class.forName(className); // 动态获取类声明的属性信息 Field[] all = cls.getDeclaredFields();
实例:
package class_information; import java.lang.reflect.Field; /** * 动态获取类的属性信息 * * @author chenzufeng */ public class Eoo { int id; String name; double salary; public Eoo() {} public Eoo(int id, String name, double salary) { super(); this.id = id; this.name = name; this.salary = salary; } /** * 动态获取一个类的全部属性信息 * 1. 动态加载一个类到方法区 * 2. 动态获取类的属性信息 */ public static void getClassFields() throws ClassNotFoundException { String className = "class_information.Eoo"; // 动态加载类 Class cls = Class.forName(className); // 动态获取类声明的属性信息 Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { // getName获取属性的名字 System.out.println(field.getName()); } } public static void main(String[] args) throws ClassNotFoundException { getClassFields(); } }
输出结果:
id name salary
实现过程(利用反射API实现动态属性访问):
实例:
package attribute_value; import java.lang.reflect.Field; /** * 动态获取类的属性值 * @author chenzufeng */ public class Goo { public int id; public String name; public Goo() {} public Goo(int id, String name) { super(); this.id = id; this.name = name; } /** * 获取obj对象的 fieldName对应属性的值 * @param object 对象 * @param filedName 属性 * @return 属性值 */ public Object getAttributeValue(Object object, String filedName) { try { /* * 1. 获取类信息:找到对象的类型信息 * Java有3种方法可以获取Class信息 * a) 类名.class获取类信息(静态) * b) Class.forName("类名") 获取类信息 (动态) * c) obj.getClass()获取类信息。运行期间,通过当前对象获取类信息 */ Class cls = object.getClass(); /* * 2. 找到属性:在信息中找属性信息 * getDeclaredField按照属性名在cls中查找类信息。当属性没有找到时候,抛出异常! */ Field field = cls.getDeclaredField(filedName); /* * 3. 在对象上获取属性的值 * get方法:在一个对象上获取属性的值,对象上没有对应的属性,抛出异常 */ Object value = field.get(object); return value; } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } return null; } public static void testGetAttributeValue() { Goo goo = new Goo(1, "Tom"); Object id = goo.getAttributeValue(goo, "id"); Object name = goo.getAttributeValue(goo, "name"); System.out.println(id + " " + name); } public static void main(String[] args) { testGetAttributeValue(); // 1 Tom } }
获取方法:
// 动态加载类 Class cls = Class.forName(className); // 动态获取类的构造器信息 Constructor[] constructors = cls.getDeclaredConstructors();
实例:
/** * 动态获取类的构造器信息 */ public static void getAllConstructors() throws ClassNotFoundException { String className = "class_information.Eoo"; // 动态加载类 Class cls = Class.forName(className); // 动态获取类的构造器信息 Constructor[] constructors = cls.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.print(constructor.getName()); /* * 获取构造器的参数类型列表 * Parameter参数;Type类型 * Class[] 代表所有参数的类型列表 */ Class[] types = constructor.getParameterTypes(); System.out.println(Arrays.toString(types)); } }
输出结果:
class_information.Eoo[] class_information.Eoo[int, class java.lang.String, double]
// 动态加载类会遇见必检异常:java.lang.ClassNotFoundException Class cls = Class.forName(className); // cls.newInstance()调用无参数构造器创建对象 Object obj = cls.newInstance();
实例:
public class Date { public Date() { this(System.currentTimeMillis()); } public Date(long date) { fastTime = date; } }
package create_object; import java.util.Date; /** * 调用无参构造器创建对象 * @author chenzufeng */ public class UseConstructorWithoutParameter { public static void main(String[] args) throws Exception { createObject(); } /** * 动态调用无参数构造器创建对象 * 1.动态加载类 * 2.利用class的方法newInstance创建对象 * * 注意:对象所属类必须有无参数构造器,否则出异常 */ public static void createObject() throws ClassNotFoundException, IllegalAccessException, InstantiationException { String className = "java.util.Date"; Class cls = Class.forName(className); // cls.newInstance()调用无参数构造器创建对象 Object object = cls.newInstance(); System.out.println("动态的创建对象:"); System.out.println(object); // 静态的创建对象!编译已经就固定了! Date date = new Date(); System.out.println("静态的创建对象:"); System.out.println(date); } }
输出结果:
动态的创建对象: Sun Feb 07 21:18:50 CST 2021 静态的创建对象: Sun Feb 07 21:18:50 CST 2021
// 动态加载类 Class cls = Class.forName(className); // 动态获取指定参数类型的构造器 Constructor constructor = cls.getDeclaredConstructor(paramTypes); // 执行构造器constructor.newInstance()方法,创建对象 Object obj = constructor.newInstance(params);
实例:
package create_object; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * 调用有参构造器创建对象 * @author chenzufeng */ public class UseConstructorWithParameter { public static void main(String[] args) { testCreateObject(); } /** * 调用有参构造器创建对象:className + paramTypes共同决定调用哪个构造器! * @param className 调用className对应类的有参数构造器 * @param paramTypes 代表对应构造器的参数列表 * @param params 执行构造器还需要具体的参数params,为构造器参数列表赋值 * @return 创建的对象 */ public static Object createObject(String className, Class[] paramTypes, Object[] params) { try { // 1.动态加载类 Class cls = Class.forName(className); // 2.动态获取指定参数类型的构造器 Constructor constructor = cls.getDeclaredConstructor(paramTypes); // 3.执行构造器newInstance()方法,创建对象 Object object = constructor.newInstance(params); return object; } catch (ClassNotFoundException | NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { e.printStackTrace(); } return null; } /** * 调用有参构造器创建对象 * new Date(long date) * new String("Hello") * new String(byte[],"utf-8"); */ public static void testCreateObject() { /* * 动态调用 new Date(long date); */ String className = "java.util.Date"; // paramTypes类型列表:Class类型的数组 Class[] paramTypes = {long.class}; // 实际参数列表:params Object[] params = {1000L*60*60*24*365}; Object object = createObject(className, paramTypes, params); System.out.println(object); /* * 动态调用 new String("Hello"); * {} 只能用在声明变量时候直接初始化,不能用于赋值语句! * 赋值语句可以使用 new Object[]{"Hello"} */ className = "java.lang.String"; paramTypes = new Class[] {String.class}; params = new Object[] {"Hello"}; object = createObject(className, paramTypes, params); System.out.println(object); /* * 动态调用 new String(byte[],"utf-8"); */ object = createObject("java.lang.String", new Class[] {byte[].class, String.class}, new Object[] {new byte[] {65, 66, 67, 68}, "UTF-8"}); System.out.println(object); } }
输出结果:
Fri Jan 01 08:00:00 CST 1971 Hello ABCD
1.Java反射机制
2.Java——反射的意义及优缺点