反射

一、概述

反射(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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值