反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有修饰符所修饰的属性和方法,不管是public还是private还是其他修饰符所修饰的属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能称为java的反射机制。通俗的理解为:在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。
2.反射机制能做些什么?
(1)在运行时判断任意一个对象所属的类;
(2)在运行时构造任意一个类的对象;例如:在刚学JDBC时用过一行代码, Class.forName("com.mysql.jdbc.Driver.class").newInstance();这行代码是生成驱动对象实例,用到的是反射,并且现在很多JAVA框架都用到反射机制,hibernate、struts都是用反射机制实现的。
(3)在运行时判断任意一个类所具有的成员变量和方法;
(4)在运行时调用任意一个对象的方法;
(5)生成动态代理。
3.反射机制的原理是什么?
我们编写出来的是.java文件,然后编译之后生成对应的.class文件,每个.class文件都有对应的class对象,在运行状态时,如果我们要产生某个类的对象,Java虚拟机会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象被加载到内存中,就可以用它来产生该类型的所有对象,访问java对象的属性,方法,构造方法等;
4.反射机制相关的API:
在这里先看一下JAVA为我们提供了那些反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
这五个类中给我们提供了很多的属性和方法,下面我来给大家介绍一下主要的方法:
-----------------------------------关于得到类中方法的函数--------------------------------------------------------------
(1)getDeclareMethods();获取所有的方法。
(2)getReturnType();获得方法的返回类型。
(3)getParameterTypes();获得方法的传入参数类型。
(4)getDeclaredMethod("方法名",参数类型.class,.........);获得特定的方法。
-----------------------------------关于得到类中构造函数的函数----------------------------------------------------------
(1)getDeclaredConstructors();获得所有的构造函数
(2)getDeclaredConstructor(参数类型.class,...........);获得特定的构造函数
-----------------------------------关于得到类中父类和父接口-------------------------------------------------------------
(1)getSuperclass();获取某类的父类
(2)getInterfaces();获得某类实现的接口
以上只是简单的介绍了一些关键的方法,想了解更多,还是需要看JAVA的API.
5.在实践中学会运用反射机制
(1)通过一个对象获得完整的包名和类名
package reflect;
public class Microstrong {
public static void main(String[] args) {
Microstrong microstrong=new Microstrong();
System.out.println(microstrong.getClass().getName());
}
}
结果:
reflect.Microstrong
package reflect;
public class Microstrong {
public static void main(String[] args) {
Class> class1=null;
Class> class2=null;
Class> class3=null;
//第一种方法:
try {
class1=Class.forName("reflect.Microstrong");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//第二种方法:java中每个类型都有class属性.
class2=Microstrong.class;
//第三种方法:java语言中任何一个java对象都有getClass方法
class3=new Microstrong().getClass();
System.out.println("类名称"+class1.getName());
System.out.println("类名称"+class2.getName());
System.out.println("类名称"+class3.getName());
}
}
类名称reflect.Microstrong
类名称reflect.Microstrong
类名称reflect.Microstrong
package reflect;
import java.io.Serializable;
public class Microstrong implements Serializable{
public static void main(String[] args) throws Exception {
Class> class1 = Class.forName("reflect.Microstrong");
// 取得父类
Class> parentClass = class1.getSuperclass();
System.out.println("class1的父类为:" + parentClass.getName());
// class1的父类为: java.lang.Object
// 获取所有的接口
Class> intes[] = class1.getInterfaces();
System.out.println("class1实现的接口有:");
for (int i = 0; i < intes.length; i++) {
System.out.println((i + 1) + ":" + intes[i].getName());
}
}
}
结果:
class1的父类为:java.lang.Object
class1实现的接口有:
1:java.io.Serializable
-----------下面这个例子直接说明两个问题:-------------
(4)获取某个类中的全部构造函数 (5)通过反射机制实例化一个类的对象
package reflect;
import java.lang.reflect.Constructor;
public class Microstrong{
public static void main(String[] args) throws Exception {
Class> class1 = null;
class1 = Class.forName("reflect.Microstrong");
// 第一种方法:实例化默认构造方法,调用set赋值
User user = (User) class1.newInstance();
user.setAge(24);
user.setName("Microstrong");
System.out.println(user);
// 第二种方法:取得全部的构造函数,使用构造函数赋值
Constructor> cons[] = class1.getConstructors();
// 查看每个构造函数需要的参数
for (int i = 0; i < cons.length; i++) {
Class> classParameter[] = cons[i].getParameterTypes();
System.out.print("cons[" + i + "] (");
for (int j = 0; j < classParameter.length; j++) {
if (j == classParameter.length - 1)
System.out.print(classParameter[j].getName());
else
System.out.print(classParameter[j].getName() + ",");
}
System.out.println(")");
}
user = (User) cons[0].newInstance("Microstrong");
System.out.println(user);
user = (User) cons[1].newInstance(24, "Microstrong");
System.out.println(user);
}
}
class User {
private int age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this.name = name;
}
public User(int age, String name) {
super();
this.age = age;
this.name = name;
}
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 [age=" + age + ", name=" + name + "]";
}
}
User [age=24, name=Microstrong]
cons[0] (int,java.lang.String)
cons[1] (java.lang.String)
cons[2] ()
User [age=24, name=Microstrong]
User [age=0, name=Microstrong]
(6)获取某个类的全部属性
package reflect;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Microstrong implements Serializable{
public static void main(String[] args) throws Exception {
Class> class1 = Class.forName("reflect.Microstrong");
System.out.println("===============本类属性===============");
// 取得本类的全部属性
Field[] field = class1.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 权限修饰符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class> type = field[i].getType();
System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");
}
System.out.println("==========实现的接口或者父类的属性==========");
// 取得实现的接口或者父类的属性
Field[] filed1 = class1.getFields();
for (int j = 0; j < filed1.length; j++) {
// 权限修饰符
int mo = filed1[j].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class> type = filed1[j].getType();
System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";");
}
}
}
结果:
===============本类属性===============
private static final long serialVersionUID;
==========实现的接口或者父类的属性==========
-------(6.1)获得特定的属性:
package reflect;
import java.lang.reflect.Field;
public class Microstrong{
private String TAG="Microstrong";
public static void main(String[] args) throws Exception {
//获取类
Class class1=Class.forName("reflect.Microstrong");
//获取TAG属性
Field idf=class1.getDeclaredField("TAG");
//实例化这个类赋给object
Object object = class1.newInstance();
//打破封装
idf.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给object对象的TAG属性赋值
idf.set(object, "microstrong_microstrong"); //set
//get
System.out.println(idf.get(object));
}
}
结果:
microstrong_microstrong
(7)获取某个类的全部方法
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Microstrong{
public static void main(String[] args) throws Exception {
Class> class1 = Class.forName("reflect.Microstrong");
Method method[] = class1.getMethods();
for (int i = 0; i < method.length; ++i) {
//返回值的类型
Class> returnType = method[i].getReturnType();
//参数的类型
Class> para[] = method[i].getParameterTypes();
//方法的修饰符
int temp = method[i].getModifiers();
System.out.print(Modifier.toString(temp) + " ");
System.out.print(returnType.getName() + " ");
System.out.print(method[i].getName() + " ");
System.out.print("(");
for (int j = 0; j < para.length; ++j) {
System.out.print(para[j].getName() + " " + "arg" + j);
if (j < para.length - 1) {
System.out.print(",");
}
}
Class> exce[] = method[i].getExceptionTypes();
if (exce.length > 0) {
System.out.print(") throws ");
for (int k = 0; k < exce.length; ++k) {
System.out.print(exce[k].getName() + " ");
if (k < exce.length - 1) {
System.out.print(",");
}
}
} else {
System.out.print(")");
}
System.out.println();
}
}
}
public static void main ([Ljava.lang.String; arg0) throws java.lang.Exception
public final void wait () throws java.lang.InterruptedException
public final void wait (long arg0,int arg1) throws java.lang.InterruptedException
public final native void wait (long arg0) throws java.lang.InterruptedException
public boolean equals (java.lang.Object arg0)
public java.lang.String toString ()
public native int hashCode ()
public final native java.lang.Class getClass ()
public final native void notify ()
public final native void notifyAll ()
除了main函数外,还多了其他很多方法,因为JAVA中所有的类都继承Object类,这些方法是object的方法。
package reflect;
import java.lang.reflect.Method;
public class Microstrong{
public static void main(String[] args) throws Exception {
Class> clazz = Class.forName("reflect.Microstrong");
// 调用Microstrong类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// 调用Microstrong的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 24, "Microstrong");
}
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法reflect1");
}
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法reflect2");
System.out.println("age -> " + age + ". name -> " + name);
}
}
Java 反射机制 - 调用某个类的方法reflect1
Java 反射机制 - 调用某个类的方法reflect2
age -> 24. name -> Microstrong
(9)反射机制的动态代理
package reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Microstrong {
public static void main(String[] args) throws Exception {
MyInvocationHandler demo = new MyInvocationHandler();
Subject sub = (Subject) demo.bind(new RealSubject());
String info = sub.say("Microstrong", 20);
System.out.println(info);
}
}
// 定义项目接口
interface Subject {
public String say(String name, int age);
}
// 定义真实项目
class RealSubject implements Subject {
public String say(String name, int age) {
return name + " " + age;
}
}
/**
* 在java中有三种类加载器。
*
* 1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
*
* 2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre/lib/ext目录中的类
*
* 3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
*
* 如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
*/
class MyInvocationHandler implements InvocationHandler {
private Object obj = null;
public Object bind(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object temp = method.invoke(this.obj, args);
return temp;
}
}
Microstrong 20
6. 反射机制的应用实例
(1)在泛型为Integer的ArrayList中存放一个String类型的对象。注意:我亲自测试在泛型为String的ArrayList中存放一个Integer类型的对象是行不通的。
package reflect;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Microstrong {
public static void main(String[] args) throws Exception {
ArrayList list = new ArrayList();
Method method = list.getClass().getMethod("add", Object.class);
method.invoke(list, "Java反射机制Microstrong");
System.out.println(list.get(0));
}
}
Java反射机制Microstrong
(2)通过反射取得并修改数组的信息
package reflect;
import java.lang.reflect.Array;
public class Microstrong {
public static void main(String[] args) throws Exception {
int[] temp = { 11, 21, 31, 41, 51 };
Class> demo = temp.getClass().getComponentType();
System.out.println("数组类型: " + demo.getName());
System.out.println("数组长度 " + Array.getLength(temp));
System.out.println("数组的第一个元素: " + Array.get(temp, 0));
Array.set(temp, 0, 100);
System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0));
}
}
结果:
数组类型: int
数组长度 5
数组的第一个元素: 11
修改之后数组第一个元素为: 100
(3)通过反射机制修改数组的大小
package reflect;
import java.lang.reflect.Array;
public class Microstrong {
public static void main(String[] args) throws Exception {
int[] temp = { 11, 21, 31, 41, 51, 61, 71, 81, 91 };
int[] newTemp = (int[]) arrayInc(temp, 15);
print(newTemp);
String[] atr = { "a", "b", "c" };
String[] str1 = (String[]) arrayInc(atr, 8);
print(str1);
}
// 修改数组大小
public static Object arrayInc(Object obj, int len) {
Class> arr = obj.getClass().getComponentType();
Object newArr = Array.newInstance(arr, len);
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newArr, 0, co);
return newArr;
}
// 打印
public static void print(Object obj) {
Class> c = obj.getClass();
if (!c.isArray()) {
return;
}
System.out.println("数组长度为: " + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + " ");
}
System.out.println();
}
}
数组长度为: 15
11 21 31 41 51 61 71 81 91 0 0 0 0 0 0
数组长度为: 8
a b c null null null null null
package reflect;
public class Microstrong {
public static void main(String[] args) throws Exception {
fruit f = Factory.getInstance("reflect.Orange");
if (f != null) {
f.eat();
}
}
}
interface fruit {
public abstract void eat();
}
class Apple implements fruit {
public void eat() {
System.out.println("Apple");
}
}
class Orange implements fruit {
public void eat() {
System.out.println("Orange");
}
}
/**
* 对于普通的工厂模式当我们在添加一个子类的时候,就需要对应的修改工厂类。 当我们添加很多的子类的时候,会很麻烦。
* 现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。
* 但是需要知道完整的包名和类名,我们可以使用properties配置文件来完成配置并读取配置文件。
*/
class Factory {
public static fruit getInstance(String ClassName) {
fruit f = null;
try {
f = (fruit) Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
Orange
在使用jdbc时侯,编写访问数据库时有10个表,每个表都有增删改查的操作,那时候我还不知道有反射机制这个概念,所以就对不同的表创建不同的dao类,这样不仅开发速率低,而且代码冗余。了解java反射机制后,只需要写一个dao类,四个方法,增删改查,传入不同的对象,无需为每一个表都创建dao类。
7反射加配置文件,使我们的代码更加灵活
assembly.load("当前程序集的名称").CreateInstance("当前命名空间的名称",要实例化的类名);
优点:很容易的方便我们变换数据库,例如我们将系统的数据库从MySQL升级到Oracle,我们不需要写两份dao层,在配置文件的内容中改一下,JAVA中的配置文件为.properties,称作属性文件。通过反射读取里边的内容。
8、反射机制的优点和缺点:
静态编译:静态编译就是在编译的时候把你所有的模块都编译进exe里去。
动态编译:动态编译是从Java 6版本开始的,可以在运行期直接编译.java文件,执行.class,并且能够获得相关的输入输出,甚至还能监听相关的事件。
反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性。比如,一个大型的软件,不可能一次就把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时或出现Bug了 ,我们不可能要用户把以前的卸载,再重新安装新的版本。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
它的缺点是(1)对性能有影响,反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。(2)安全限制 ,使用反射技术要求程序必须在一个没有安全限制的环境中运行。(3)内部暴露,由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法)。