一、概述
反射(Reflection)是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。动态获取类中信息,就是java反射。
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中的应用。
Java反射机制的用途:
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3)在运行时判断任意一个类所具有的成员变量和方法
4)在运行时调用任意一个对象的方法
反射用到的类: java.lang.Class; java.lang.reflect.*;
二、反射的实现步骤
1.得到类的Class
得到Class对象的三种方法
1)对象.getClass()
String str = “abc”; Class<?> cls = str .getClass();
必须要明确具体的类,并创建对象,因此比较麻烦
2)类名.class
Class<?> cls = String.class;
比第一种方法较简单,但还是要明确具体的类以及该类的一个静态成员
3)Class.forName(类的全名)
Class<?> cls = Class.forName(“java.lang.String” );
无需知道具体的类,只要有类的字符串名称即可,方便,扩展性强
以如下Person类为例:
package cn.itcast.bean;
public class Person {
private int age;
private String name;
public Person(int age, String name){
super();
this.age = age;
this.name = name;
System.out.println("Person param run..."+this.name +":"+this.age);
}
public Person(){
super();
System.out.println("person run");
}
public void show(){
System.out.println(name +"...show run..."+age);
}
private void privateMethod(){
System.out.println("method run");
}
public void paramMethod(String str, int num){
System.out.println("paramMethod run..."+str+":"+num);
}
public static void staticMethod(){
System.out.println("static method run");
}
}
import cn.itcast.bean.Person;
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException{
getClassObject_1();
System.out.println("----------------");
getClassObject_2();
System.out.println("----------------");
getClassObject_3();
}
/*
方式一: 对象.getClass()
*/
public static void getClassObject_1(){
Person p = new Person();
Class clazz = p.getClass();
Person p1 = new Person();
Class clazz1 = p1.getClass();
System.out.println(clazz == clazz1);
System.out.println(clazz);
}
/*
方式二: 类名.class
*/
public static void getClassObject_2(){
Class clazz = Person.class;
Class clazz1 = Person.class;
System.out.println(clazz == clazz1);
System.out.println(clazz);
}
/*
方式三: Class.forName(类的全名)
*/
public static void getClassObject_3() throws ClassNotFoundException{
//可以把类的字符串名称写到配置文件中,然后读取出来
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
System.out.println(clazz);
}
}
2.由Class获得该类的信息(构造函数,字段,方法)
获取构造方法:
1)得到这个类的所有构造方法:
Constructor[] cons = Class.forName(“cn.itcast.bean.Person”).getConstructors();
2)获取某一个构造方法:
Constructor con=Person.class.getConstructor(String.class,int.class);
创建实例对象:
1)传统方式:Person p = new Person(“Lisa”,25);
2)反射方式:Person p= (Person)con.newInstance(“Lisa”,25);
/*
* 获取Class中的构造方法
*/
import cn.itcast.bean.Person;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception{
createNewObject_1();
System.out.println("---------------");
createNewObject_2();
}
public static void createNewObject_1() throws
ClassNotFoundException, InstantiationException, IllegalAccessException{
String name = "cn.itcast.bean.Person";
Class clazz = Class.forName(name);
//产生Person类的对象
Object obj = clazz.newInstance(); //调用Person的空参构造函数
}
public static void createNewObject_2() throws ClassNotFoundException,
InstantiationException, NoSuchMethodException, IllegalAccessException,
InvocationTargetException{
String name = "cn.itcast.bean.Person";
Class clazz = Class.forName(name);
//获取指定的构造对象
Constructor constructor = clazz.getConstructor(int.class, String.class);
//通过该构造器对象的newInstance方法进行对象初始化
Object obj = constructor.newInstance(26,"Hiking");
}
}
获取 Field:
Field getField(String s); //只能获取public field
Field getDeclaredField(String s); //可以获取public 和 private field
setAccessible(ture); //对私有字段的访问取消权限检查,暴力访问
set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值
Object get(Object obj);//返回指定对象上Field表示的字段的值。
/*
* 获取Class的字段
*/
import cn.itcast.bean.Person;
import java.lang.reflect.Field;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception{
getFieldDemo();
}
public static void getFieldDemo() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
//getField只能获取public field
//Field field = clazz.getField("age");
//getDeclaredField可以获取public 和 private field
Field field = clazz.getDeclaredField("age");
//对私有字段的访问取消权限检查,暴力访问
field.setAccessible(true);
Object obj = clazz.newInstance();
//为对象的属性赋值
field.set(obj, 89);
//获取某对象的某属性值
Object o = field.get(obj);
System.out.println(field);
}
}
获取 Method:
Method[] getMethods(); //只能获取public method
Method[] getDeclaredMethods(); //可获取 public 和 private 方法
Method getMethod(“方法名”,参数.class(如果是空参可以写null));
Object invoke(Object obj ,参数); //调用方法。如果方法是静态,invoke方法中的对象参数可以为null。
/*
* 获取Class中的方法
*/
import cn.itcast.bean.Person;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception{
getMethodDemo_1();
System.out.println("--------------");
getMethodDemo_2();
System.out.println("--------------");
getMethodDemo_3();
}
public static void getMethodDemo_1() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
//getMethods()只能获取public method
Method[] methods = clazz.getMethods();
//getDeclaredMethods()可获取 public 和 private 方法
methods = clazz.getDeclaredMethods();
for(Method method: methods){
System.out.println(method);
}
}
public static void getMethodDemo_2() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
//获取空参数一般方法
Method method = clazz.getMethod("show", null);
Object obj = clazz.newInstance();
Constructor constructor =
clazz.getConstructor(int.class, String.class);
obj = constructor.newInstance(26,"Emily");
method.invoke(obj, null);
}
public static void getMethodDemo_3() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
//获取空参数一般方法
Method method =
clazz.getMethod("paramMethod", String.class, int.class);
Object obj = clazz.newInstance();
Constructor constructor = clazz.getConstructor();
obj = constructor.newInstance();
method.invoke(obj, "Eva",33);
}
}
实例一:电脑运行
package cn.itcast.reflect.test;
public interface PCI {
public void open();
public void close();
}
package cn.itcast.reflect.test;
public class SoundCard implements PCI{
public void open(){
System.out.println("sound open");
}
public void close(){
System.out.println("sound close");
}
}
package cn.itcast.reflect.test;
public class NetCard implements PCI{
public void open(){
System.out.println("net open");
}
public void close(){
System.out.println("net close");
}
}
package cn.itcast.reflect.test;
public class Mainboard {
public void run(){
System.out.println("main board run...");
}
public void usePCI(PCI p){
if(p != null){
p.open();
p.close();
}
}
}
pci.properties
pci1=cn.itcast.reflect.test.SoundCard
pci2=cn.itcast.reflect.test.NetCard
package cn.itcast.reflect.test;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
public class ReflectTest {
public static void main(String[] args) throws Exception{
Mainboard mb = new Mainboard();
mb.run();
File configFile = new File("pci.properties");
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(configFile);
prop.load(fis);
for(int x = 0; x < prop.size(); x++){
String pciName = prop.getProperty("pci"+(x+1));
Class clazz = Class.forName(pciName);
PCI p = (PCI)clazz.newInstance();
mb.usePCI(p);
}
fis.close();
}
}
实例二:通过类名反射调用该类的main()方法
import java.lang.reflect.Method;
class Test{
public static void main(String[] args){
for(String arg: args){
System.out.println(arg);
}
}
}
public class PerformedMain {
public static void main(String[] args) throws Exception{
/*普通方式
Test.main(new String[]{"123","456","789"});
System.out.println("----------------");
*/
//反射方式
String className = args[0];
Class clazz = Class.forName(className);
Method methodMain = clazz.getMethod("main", String[].class);
//方式一:强制转换为超类Object,不用拆包
methodMain.invoke(null, (Object)new String[]{"123","456","789"});
//方式二:将数组打包,编译器拆包后就是一个String[]类型的整体
methodMain.invoke(null, new Object[]{new String[]{"123","456","789"}});
}
}
以上程序中利用两种方法来获取传入的String[]对象,都要进行强制转换。这是因为invoke()方法兼容了JDK1.5和JDK1.4两个版本,而这两个版本的参数有所不同,JDK1.5版本中传入的是多个Object对象,而JDK1.4版本传入的是一个数组对象,数组内传递所有参数。因此,在向invoke()传入参数时,为了避免编译器把String[]对象当做jdk1.4版本的参数对待,所以使用(Object)进行强制转换。
三、数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用。
Array工具类用于完成对数组的反射操作。
import java.lang.reflect.Array;
import java.util.Arrays;
public class ArrayReflect {
public static void main(String[] args){
int[] a1 = new int[]{1,2,3};
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass().equals(a2.getClass())); //true
System.out.println(a1.getClass().equals(a3.getClass())); //false
System.out.println(a1.getClass().equals(a4.getClass())); //false
System.out.println(a1.getClass().getName()); //[I
System.out.println(a4.getClass().getName()); //[Ljava.lang.String;
System.out.println(a1.getClass().getSuperclass()); //class java.lang.Object
System.out.println(a4.getClass().getSuperclass()); //class java.lang.Object
Object obj1 = a1;
Object obj2 = a3;
Object obj3 = a4;
//Object[] obj11 = a1; //不对。因为a1中的元素是int类型,基本数据类型不是Object
Object[] obj13 = a3;
Object[] obj14 = a4;
System.out.println(a1); //[I@659e0bfd
System.out.println(a4); //[Ljava.lang.String;@2a139a55
System.out.println(Arrays.asList(a1)); //[[I@659e0bfd] //a1就被当作是一个object
System.out.println(Arrays.asList(a4)); //ArrayReflect.java //a4是Object类型的数组
//对数组的反射操作: 打印数组元素
printObject(a1);
printObject(a4);
printObject("abc");
}
private static void printObject(Object obj){
Class clazz = obj.getClass();
if(clazz.isArray()){
int len = Array.getLength(obj);
for (int x = 0; x < len; x++){
System.out.println(Array.get(obj, x));
}
}
else
System.out.println(obj);
}
}