上篇文章我们提到了可以使用反射机制破解单例模式。这篇文章我们就来谈一谈什么是反射,反射有什么用,怎么用,怎么实现反射。
Java的反射(reflection)机制:是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
java虽然不是动态语言,但是它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
优点:
反射机制的功能非常强大,但不能滥用。在能不使用反射完成时,尽量不要使用,原因有以下几点:
缺点:
三种方式
==我们创建一个Person类用于实验,分别使用三种方法获取他们的对象,并打印他们的hashCode(),我们会发现他们的hashcode是相同的,证明他们是获取的是相同的,所有统一个字节码文件(*.class)在一次运行中,只会被加载一次。不论通过哪一种方式获取的对象都是同一个。
package hello;public class ReflectDemo { public static void main(String[] args) throws Exception{ //Class.forName("全类名") Class<?> aClass = Class.forName("hello.Person"); System.out.println(aClass); System.out.println(aClass.hashCode()); //类名.clss Class<Person> personClass = Person.class; System.out.println(personClass); System.out.println(personClass.hashCode()); //对象.getClass() Person person = new Person(); System.out.println(person.getClass()); System.out.println(person.getClass().hashCode()); }}class Person{ private String name; public Person(){ } public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}Class对象里面大概有120多个方法,我们不可能全部都记住,也没必要全部都记住,我们只需要记住常用的方法和功能就可以了。
获取成员变量
获取构造方法
获取成员方法
获取类名
| 方法 | 作用 |
|---|---|
| Field[] getFields() | 获取public的成员变量名 |
| Field getFields(String name) | 获取public的成员变量名,需要指定名称 |
| FIeld[] getDeclaredFields() | 获取所有的成员变量,包括private |
| FIeld getDeclaredField(String name) | 获取指定的成员变量,私有的也可以获取,如果要改这个变量的值需要setAccessible(ture)暴力反射 |
| Constructor<?>[] getConstructors() | 用于返回一个构造函数对象数组,该数组反映此Class对象表示的类的所有公共构造函数。 |
| Constructor | 获取指定参数的构造方法 |
| Constructor | 方法返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类或接口的指定构造函数 |
| Constructor<?>[] getDeclaredConstructors() | 用于返回一个Constructor对象数组,该数组指示此Class对象所表示的类定义的构造函数的类型(Constructor可以是public,private,protected或default) |
| Method[] getMethods() | 公共的所有方法 |
| Method getMethod(String name,类<?>..., parameterType) | 指定公共的其中的方法,parameterType时一个数组 |
| Method[] getDeclaredMethods() | 所有的包括私有的 |
| Method getDeclaredMethod(String name,类<?>...,parameterTypes) | 指定的,parameterTypes表示数组 |
| String getName() | 获取类名程 |
package hello;import com.sun.org.apache.xerces.internal.impl.XMLEntityScanner;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class ReflectDemo { public static void main(String[] args) throws Exception{ //获取class对象 Class<Person> personClass = Person.class; //Field[] getFields() Field[] fields = personClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("******************************"); //FIeld[] getDeclaredFields() Field[] declaredFields = personClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("******************************"); //Constructor<?>[] getConstructors() Constructor<Person> constructor = personClass.getConstructor(); System.out.println(constructor); System.out.println("******************************"); //Method[] getMethods() Method[] methods = personClass.getMethods(); for (Method method : methods) { System.out.println(method); } System.out.println("******************************"); //String getName() System.out.println(personClass.getName()); }}class Person{ public int id; private String name; public Person(){ } public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }}创建一个功能,不改里面的代码,只需要修改配置文件就能调用不同的方法
第一步:创建配置文件,”data.properties"
这个路径一定要写成hello.Preson,写成斜杠会识别不了。
# 这个写全路径类名className=hello.Preson# 这个写类里面想要调用的方法methodName=eat第二步:具体类"Preson.java"
package hello;public class Preson { public String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void eat(){ System.out.println("eat...."); }}第三步:编写实现代码,名成ReflectDemo.java
package hello;import java.io.InputStream;import java.lang.reflect.Method;import java.util.Properties;public class ReflectDemo { public static void main(String[] args) throws Exception{ //加载配置文件 //创建properties对象 Properties properties = new Properties(); //加载配置文件,转为一个集合 ClassLoader classLoader = ReflectDemo.class.getClassLoader(); InputStream resourceAsStream = classLoader.getResourceAsStream("hello/data.properties"); properties.load(resourceAsStream); //获取配置文件定义的数据 String className = properties.getProperty("className"); String methodName = properties.getProperty("methodName"); //加载该类进入内存 Class aClass = Class.forName(className); Object o = aClass.newInstance(); Method method = aClass.getMethod(methodName); method.invoke(o); }}第四步:运行,我们只需要修改properties文件里面的类名和方法就能实现不同类不同方法的创建了。