如要转载请标明作者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. 利用反射实现对象工厂。
【实现功能】
利用反射机制创建对象,并将新建对象存入到对象池中。
【前提准备】
【代码示例】
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_构造方法的反射应用。
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");
}
}
注释:
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));
}
}
java.lang.IllegalAccessException: Class com.zjrodger.TestClassReflection can not access a member of class com.zjrodger.TestClass with modifiers "private" |
//从各种类型的字段对象中,找到String类型的字段 :
if(oneField.getType() == java.lang.String.class){}
//判断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类代表某个类中的一个成员方法。
(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对象对应的是一个静态方法。
Method setNameMethod = person01.getClass().getDeclaredMethod("setName", String.class);
setNameMethod.setAccessible(true);
setNameMethod.invoke(person01, "Chenyang");
System.out.println(person01.getName());
class Person02{
public static void printInfo(){
System.out.println("In Person Class");
}
}
Method staticMethod = person01.getClass().getDeclaredMethod("printInfo", null);
staticMethod.invoke(null, null);