反射02

本文深入介绍了Java反射技术的应用,包括如何利用反射创建对象、获取和修改成员变量的值,以及调用成员方法等内容。通过丰富的代码示例展示了反射在实际编程中的强大功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如要转载请标明作者zjrodger和出处:http://blog.youkuaiyun.com/zjrodger/,谢谢微笑

                                                                            笔记目录
(·) 利用反射得到类成员——造方法

    1. Constructor类的用法说明

    2. 创建实例对象

    3. Constructor类的使用演示

    4. 利用反射实现对象工厂。

(·) 利用反射得到类的成员——成员变量
    1. Field类的用法说明
    2.如何得到成员变量的
    3.private成员变量的的获取和修改
    (1) 如何 获得private字段的值
    (2) 如何 修改private字段的值
    (3) 成员变量反射的综合案例将一个对象obj中所有String类型的成员变量值中的'b'替换成'a'。
(·) 利用反射得到类的成员——成员方法
    1. Method类的用法说明
    2. private成员方法的获取和执行
    3. 用反射方式执行某个类中的静态static方法。
(·利用反射操作数组。



(·) 利用反射得到类成员——造方法

1. Constructor类的用法说明

(1)Constructor类代表某个类的一个构造方法。

(2)得到某个类的所有构造方法。

例子:Constructor[] constructors = Class.forName("java.lang.String").getConstructors();

(3)得到某个类的某一个指定构造方法。

例子:String类的构造方法有很多,在此,要获得带有StringBuffer参数的构造方法。

Constructor constructors = Class.forName("java.lang.String").getConstructor(StringBuffer.class);

2. 创建实例对象

(1)一般方式:String str = new String(new StringBuffer("abc"));

(2)反射方式:

方式一:

Constructor constructors = Class.forName("java.lang.String").getConstructor();

constructors.newInstance();

方式二:

ClassObj.newInstance():

例子:String strObj = Class.forName("java.lang.String").newInstance();    

该方法的实际作用和应用场景:

    正常情况下通过反射创建对象的方式:Class对象--------> 反射得到constructor--------> 构造器对象的newInstance()。因为反射技术比较消耗计算机的性能,如果每次都通过反射得到的constructor去创建对象实例,虽然能达到目的,但是程序的性能会大大地降低。

    因此,诞生出了一种新的方式:Class对象 --------> Class对象的newInstance(),该方法内部先得到默认的构造方法(即不带参数的构造方法),然后再调用该构造方法创建实例对象。它利用了缓存机制来保存默认构造方法的实例对象。但该方式仅仅试用于“创建对象时,没有向默认构造器传入任何参数”的情况。

    总结:如果要是调用不带参数的构造方法去创建对象实例的情况下,应该使用Class.newInstance()的方式来创建示例,从而减少性能的消耗。

3. Constructor类的使用演示

【实现功能】

    通过反射来创建并且初始化Person类,然后修改其中的对象属性值

【代码示例】

package com.zjrodger;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Person{
	public String name;
	public int age;
	
	public Person(){};
	public Person(String name){
		this.name = name;
	}
	public Person(int age){
		this.age =age;
	}
	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

public class ReflectionModifyFieldValuesInObj {

	public static void main(String[] args) throws SecurityException, NoSuchMethodException {
		
		Class pc = Person.class;	
		
		//通过遍历目标类所有的构造函数,从而找到每个构造函数所需的参数类型,
		//这样,对于选择自己所需的那个构造函数有一定的参考价值。
		Constructor[] constructors =  pc.getDeclaredConstructors();
		for(Constructor c: constructors){
			System.out.println(c);
		}
				
		//通过newInstance方法来创建并且初始化一个Person对形象,然后再修改其中的属性值
		//注意,只能修改Person类中public的属性。		
		try {
			Constructor constructor = pc.getConstructor(java.lang.String.class, int.class);
			Person p1 = (Person)constructor.newInstance("zjrodger", 26);
			System.out.println("通过反射修改Person对象之前,name属性的值:"+p1.name+"   age属性的值为:"+p1.getAge());
			
			try {
				//修改Person对象的name属性。
				//注意,只能修改Person类中public的属性
				Field nameField = pc.getField("name");
				nameField.set(p1, "zjrodger02");
				
				//修改Person对象的age属性。
				//注意,只能修改Person类中public的属性
				Field ageField = pc.getField("age");
				ageField.setInt(p1, 20);

				System.out.println("修改Person对象之后,name属性的值:"+p1.name+"   age属性的值为:"+p1.getAge());				
							
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			}									
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
【结果演示】

通过反射修改Person对象之前,name属性的值:zjrodger age属性的值为:26
修改Person对象之后,name属性的值:zjrodger02 age属性的值为:20

注意:通过“getField()”方法,只能获得Person类中定义的publi属性所对应的对象,而对于private或者protected属性的获得,若要修改则会抛出异常。

详细的讲解,参考Field类中的getField()方法的API。

4. 利用反射实现对象工厂。

【实现功能】

    利用反射机制创建对象,并将新建对象存入到对象池中。

【前提准备】

    在src下创建包com/zjrodger,并且放入一个名为“className.properties”的属性文件。

【代码示例】

package com.zjrodger;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 实现功能:
 * 利用反射机制创建对象,并将新建对象存入到对象池中。
 * **/
class ObjectPoolFactory {
	//1.定义一个对象池。
	private Map<String, Object> objectPool = new HashMap();
	
	//2.定义一个创建单个对象的方法。
	//该方法只要传入一个String类型的参数,就能根据该参数创建一个对象。
	private Object createObject(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		System.out.println("className = "+className);
		Class<?> oneClass = Class.forName(className);
		Object newObject = oneClass.newInstance();
		System.out.println("new Object = "+newObject);
		return newObject;
	}
	
	//3.定义一个初始化对象池的方法。
	//该方法只要传入一个String类型的属性文件的路径,就能根据该路径读取相应的属性文件的数据,并且初始化对象池。
	private void initialObjectPool(String propertiesPath){
		//读取属性文件中的数据。
		Properties prop = new Properties();
		InputStream inputStream = ObjectPoolFactory.class.getClassLoader().getResourceAsStream(propertiesPath);
		
		try {
			prop.load(inputStream);	
									
			//获得Key的数组。
			for(String keyName: prop.stringPropertyNames()){
				//创建单个对象				
				Object singleObject = this.createObject((String)prop.get(keyName));
				if(singleObject == null){
					System.out.println("initialObjectPool()方法中,singleObject == null");
				}
				this.objectPool.put(keyName, singleObject);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}								
	}

	//4.定义一个构造器。
	public ObjectPoolFactory(String propertiesPath){
			initialObjectPool(propertiesPath);
	}
	
	//5. 定义一个从对象池中获得新建Object的方法
	//传入的参数的要求:
	// 参数要从Properties文件中的Keys中选择。
	public Object getObjectFromPool(String objectName){		
		return objectPool.get(objectName);
	}		
}

public class ObjectPoolFactoryTest{
	public static void main(String[] args) {
		ObjectPoolFactory oneObjectPool = new ObjectPoolFactory("com//zjrodger//className.properties");
		System.out.println(oneObjectPool.getObjectFromPool("DateClass"));
	}
}

5.【参考资料】

《张孝祥_Java高新技术_2010年录制》,19_构造方法的反射应用。



(·) 利用反射得到类的成员——成员变量
1. Field类的用法说明
(1) Field类代表某个类的一个成员变量。
(2) 得到的Field对象是对应到类上边的成员变量,而不是对应到具体某个对象上边的成员变量,因此,Field对象没有具体的变量值。
2.如何得到成员变量的
class MyClass{
    private int x;
    public int y;
    public MyClass(int x, int y){
        this.x = x;
        this.y = y;
    }
}
public clsss MyClass{
    public static void main(String[] args){
        MyClass Obj01 = new MyClass();
        Field fieldY = Obj01.getClass.getField("Y");
    }
}
注释:
(1)"fieldY" 不代表一个具体的值,只类本身(字节码)的一个字段对象,不代表具体对象的变量值。
要想利用fieldY对象得到某个对象中的具体字段Y的值:
int fieldYValue = fieldY.get(Obj01);
(2) getField("Y")得到的 成员变量对象只能是Class中定义的 public的成员变量,而 不能得到private的成员变量。
getDeclaredField("x")得到的 成员变量对象既可以是Class中定义的 public的成员变量,也可以是 private的成员变量。

3.private成员变量的的获取和修改
(1) 如何 获得private字段的值
    通过Class对象的 getDeclaredField("x")方法,可以得到 private的成员变量(该方法也可以得到Class中定义的 public的成员变量)。
(2) 如何 修改private字段的值
package com.zjrodger;
import java.lang.reflect.Field;
class TestClass02 {
  private int x;
  public int y;
  public TestClass02(int x, int y) {
   this.x = x;
   this.y = y;
  }
}
public class TestClassReflection {
 public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
   TestClass02 tc = new TestClass02(10,20);
   Field staticFieldX = tc.getClass().getDeclaredField("x");
   staticFieldX.setAccessible(true);  //术语:暴力反射
   System.out.println(staticFieldX.get(tc));
 }
}

分析:
getDeclaredField("x")得到的 成员变量对象既可以是Class中定义的 public的成员变量,也可以是 private的成员变量。
但是对于得到的 private的成员变量,要想取得其值,必须设定“  staticFieldX.setAccessible(true); ”,
否则就会出现下属异常:
java.lang.IllegalAccessException: Class com.zjrodger.TestClassReflection can not access a member of class com.zjrodger.TestClass with modifiers "private"
【扩展阅读】 使用反射强制给private字段赋值:http://blog.youkuaiyun.com/yaerfeng/article/details/7103397
(3)成员变量反射的综合案例将一个对象obj中所有String类型的成员变量值中的'b'替换成'a'。
关键点1:在对比两个Field的类型是否相同时,需要对,Class字节码的比较,用“==”,而不用equals()。
关键代码:
//从各种类型的字段对象中,找到String类型的字段 :
if(oneField.getType() == java.lang.String.class){}
关键点2:  如何修改private字段的值
关键代码:
//判断oneField代表的字段是否是"private"字段。
    if(oneField.isAccessible() == false){
     oneField.setAccessible(true);
    }

【实现功能】

     将一个对象obj中所有String类型的成员变量值中的'b'替换成'a'。

【代码示例】

package com.zjrodger;

import java.lang.reflect.Field;

class TestClass02 {
	 private int x;
	 public int y;
	 public String str01 = "ball";
	 private String str02 = "basketball";
	 private String str03 = "boom";
	 
	 public TestClass02(int x, int y) {
	  this.x = x;
	  this.y = y;
	 }
	 
	 public void printString(){
		 System.out.println(str01);
		 System.out.println(str02);
		 System.out.println(str03);
	 }
} 

public class TestClassReflection {
	
	/**
	 * 实现功能:
	 * 将一个对象obj中所有String类型的成员变量值中的'b'替换成'a'。
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * **/
	public static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException{
		//得到Obj所对应的那个类中所有的字段,整型,字符串类型,包括public和private的字段。
		Field[] fields = obj.getClass().getDeclaredFields();
		for(Field oneField: fields){
			
			//从各种类型的字段对象中,找到String类型的字段
			if(oneField.getType() == java.lang.String.class){	

				//如果oneField代表的字段是"private"字段。		
				if(oneField.isAccessible() == false){
					oneField.setAccessible(true);	
					System.out.println(oneField.toString());					
				}
				//如果oneField代表的字段是"public"字段。
				String oldString = (String)oneField.get(obj);								 												
				String newString = oldString.replace('b', 'a');
				oneField.set(obj, newString);
			}
		}
	}
	
	public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException{
		TestClass02 tc = new TestClass02(10,20);
		tc.printString();
		TestClassReflection.changeStringValue(tc);
		tc.printString();
	}
}



(·) 利用反射得到类的成员——成员方法
1. Method类的用法说明

(1) Method类代表某个类中的一个成员方法。

(2) 得到类中的某一个方法

Method methodCharAtObj = Class.forName("java.lang.String").getMethod("charAt", int.class);

(3) 调用方式

通常方法:

String testString = new String("abc");

System.out.println(str.charAt(1));

反射方式:
利用反射方式调用String对象中的charAt()方法。

String testString = new String("abc");

Method methodCharAtObj = Class.forName("java.lang.String").getMethod("charAt", int.class);

methodCharAtObj.invoke(testString,1) ;

第一步: Methord 文件名 = String.class.getMethord(想要得到的方法名,和数据类型.class);

第二步调用Methord方法中的invoke()方法,调用其方法。

(4) invoke()方法的注意点

如果传递给Method对象的invoke()方法的一个参数为null,则说明该method对象对应的是一个静态方法


2. private成员方法的获取和执行
(1) 通过Class对象的 getDeclaredMethod("x")方法,可以得到 private的成员方法(该方法也可以得到Class中定义的 public的成员方法)。
(2) 通过Method对象的 setAccessible(true)方法来设置私有Method对象的访问权限,从而可以访问私有方法。
    实际上, setAccessible(true)方法并不属于Method,而是从属于它的父类AccessibleObject,因此,Method,Constructor,Field都可以调用该方法,
从而实现通过反射来调用private()方法,private构造器和private属性。
(3) 示例代码
Method setNameMethod = person01.getClass().getDeclaredMethod("setName", String.class);
   setNameMethod.setAccessible(true);
   setNameMethod.invoke(person01, "Chenyang");
   System.out.println(person01.getName());

3. 用反射方式执行某个类中的静态static方法。

class Person02{
   public static void printInfo(){ 
  System.out.println("In Person Class");
 }  
}

 Method staticMethod = person01.getClass().getDeclaredMethod("printInfo", null);
 staticMethod.invoke(null, null);



(·利用反射操作数组。
关键类:java.reflect.Array
没有办法得到数组中元素的类型。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值