`
xyheqhd888
  • 浏览: 409287 次
  • 性别: Icon_minigender_1
  • 来自: 秦皇岛
社区版块
存档分类
最新评论

使用反射生成与操作对象(二)

阅读更多

1. 修改成员值:

    尽管直接存取类的域成员是不被鼓励的,但仍可以直接存取公开的域成员,甚至也可以通过反射机制来存取私有域成员。下面以一个实例来说明,首先编写一个TestField类。

   

package ysu.hxy;

public class TestField
{
   public int testInt;
   public String testString;

   public String toString()
	{
	   return testInt + ":" +testString;
	}
}

 下面的范例利用反射机制动态加载类来存取域成员:

package ysu.hxy;

import java.lang.reflect.Field;

public class AssignFieldDemo 
{
	public static void main(String[] args) 
	{
		try
		{
			Class c = Class.forName(args[0]);
			Object targetObj = c.newInstance();
            
			//返回域成员
			Field testInt = c.getField("testInt");
			testInt.setInt(targetObj,99);

			Field testString = c.getField("testString");
			testString.set(targetObj,"caterpillar");

			System.out.println(targetObj);
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			System.out.println("没有指定类");
		}
		catch(ClassNotFoundException e)
		{
			System.out.println("找不到指定的类");
		}
		catch(SecurityException e)
		{
			e.printStackTrace();
		}
		catch(NoSuchFieldException e)
		{
			System.out.println("找不到指定的域成员");
		}
		catch(InstantiationException e)
		{
			e.printStackTrace();
		}
		catch(IllegalAccessException e)
		{
			e.printStackTrace();
		}
	}
}

运行结果:

D:\hxy>java ysu.hxy.AssignFieldDemo ysu.hxy.TestField
99:caterpillar

如果有必要,也可以通过反射机制存取私有的域成员,如:

Field privateField = c.getDeclaredField("privateField");
privateField.setAccessible(true);
privateField.setInt(targetObj,99);

2.再看数组对象:

  在Java中数组也是一个对象,也会有一个Class实例来表示它。如下:

package ysu.hxy;

public class ArrayDemo {
    public static void main(String[] args) {
        short[] sArr = new short[5];
        int[] iArr = new int[5];
        long[] lArr = new long[5];
        float[] fArr = new float[5];
        double[] dArr = new double[5];
        byte[] bArr = new byte[5];
        boolean[] zArr = new boolean[5];
        String[] strArr = new String[5];

        System.out.println("short 数组类:" + sArr.getClass());
        System.out.println("int 数组类:" + iArr.getClass());
        System.out.println("long 数组类:" + lArr.getClass());
        System.out.println("float 数组类:" + fArr.getClass());
        System.out.println("double 数组类:" + dArr.getClass());
        System.out.println("byte 数组类:" + bArr.getClass());
        System.out.println("boolean 数组类:" + zArr.getClass());
        System.out.println("String 数组类:" + strArr.getClass());
    }
}

  运行结果:

D:\hxy>java ysu.hxy.ArrayDemo
short 数组类:class [S
int 数组类:class [I
long 数组类:class [J
float 数组类:class [F
double 数组类:class [D
byte 数组类:class [B
boolean 数组类:class [Z
String 数组类:class [Ljava.lang.String;

若要使用反射机制动态生成数组,可以使用java.lang.reflect.Array来协助。下面的这个范例示范了如何生成String数组:

package ysu.hxy;

import java.lang.reflect.Array;

public class NewArrayDemo
{
	public static void main(String[] args) 
	{
		Class c = String.class;
		Object objArr = Array.newInstance(c,5);

		for(int i = 0;i < 5;i++)
		{
			Array.set(objArr,i,i+"");
		}

		for(int i = 0;i < 5;i++)
		{
			System.out.print(Array.get(objArr,i) + " ");
		}
		System.out.println();

		String[] strs = (String[]) objArr;
		for(String s : strs)
		{
			System.out.print(s+ " ");
		}
	}
}

 Array.newInstance()的第一个参数指定元素类型,而第二个参数指定数组长度。此方法还有另一个版本,用于创建二维数组,如下:

package onlyfun.caterpillar;
 
import java.lang.reflect.Array;
 
public class NewArrayDemo2 {
    public static void main(String[] args) {
        Class c = String.class;
        
        // 打算建立一个3*4数组
        int[] dim = new int[]{3, 4};
        Object objArr = Array.newInstance(c, dim);
        
        for(int i = 0; i < 3; i++) {
            Object row = Array.get(objArr, i);
            for(int j = 0; j < 4; j++) {
                Array.set(row, j, "" + (i+1)*(j+1));
            }
        }
        
        for(int i = 0; i < 3; i++) {
            Object row = Array.get(objArr, i);
            for(int j = 0; j < 4; j++) {
                System.out.print(Array.get(row, j) + " ");
            }
            System.out.println();
        }
    }
}

 如果要得知数组元素的类型,可以在取得数组的Class实例之后,使用Class实例的getComponentType()方法,所取回的是元素的Class实例。例如:

int[] iArr = new int[5];
System.out.println(iArr.getClass().getComponentType());

3. Proxy类:

    java.lang.reflect.Proxy类,可协助实现动态代理功能。例如:假设打算开发一个HelloSpeaker类,其中有一个hello()方法,想要在这个hello()调用前后加上记录的功能,但又不想将记录的功能写到HelloSpeaker类中。这时可以使用Proxy类来实现动态代理。

    要实现动态代理,首先要定义所要代理的接口。如下定义了有hello()方法的IHello接口。

package ysu.hxy;

public interface IHello
{
	public void hello(String name);
}

 HelloSpeaker类实现了IHello接口,如下:

package ysu.hxy;

public class HelloSpeaker implements IHello 
{
	public void hello(String name)
	{
		System.out.println("Hello," + name);
	}
}

 可以实现一个处理记录的处理器(Handler),让处理器在调用hello()方法的前后进行记录的动作。一个处理器必须实现java.lang.reflect.InvocationHandler接口,InvocationHandler有一个invoke()方法必须实现

package ysu.hxy;
import java.util.logging.*;
import java.lang.reflect.*;

public class LogHandler implements InvocationHandler 
{
	private Logger logger = 
		Logger.getLogger(this.getClass().getName());
    
	private Object delegate;

	//绑定要代理的对象
	public Object bind(Object delegate)
	{
		this.delegate = delegate;
		//建立并返回代理对象 
		return Proxy.newProxyInstance(
			delegate.getClass().getClassLoader(),
			//要被代理的接口
			delegate.getClass().getInterfaces(),
				this);
	}

	//代理要调用的方法,并在其前后增加行为
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
	{
			 Object result = null;
			 try
			  {
				 logger.log(Level.INFO,"method starts..." + method.getName());
				 result = method.invoke(delegate,args);
				 logger.log(Level.INFO,"method endss..." + method.getName());
			  }
			  catch(Exception e)
			  {
				 logger.log(Level.INFO,e.toString());
			  }
		return result;		
	}
}

 主要的概念是使用Proxy.newProxyInstance()方法建立一个代理对象,建立代理对象时必须告知所要代理的操作接口,然后可以操作所建立的代理对象,在每次操作时会调用InvocationHandler的invoke()方法,invoke()方法会传入被代理对象的方法名称与运行变量,实际上要运行的方法交由method.invoke()。在method.invoke()前后加上记录动作,method.invoke()返回的对象是实际方法运行后的回传结果。先来看看一个运行的例子:

package ysu.hxy;

public class ProxyDemo
{
	public static void main(String[] args) 
	{
		LogHandler handler = new LogHandler();
		IHello speaker = new HelloSpeaker();

		//代理speaker的对象
		IHello speakerProxy = 
			(IHello)handler.bind(speaker);

		speakerProxy.hello("Justin");
	}
}

 运行结果:

D:\hxy>java ysu.hxy.ProxyDemo
2009-4-6 19:06:24 ysu.hxy.LogHandler invoke
信息: method starts...hello
Hello,Justin
2009-4-6 19:06:24 ysu.hxy.LogHandler invoke
信息: method endss...hello

通过代理机制,在不将记录动作写入HelloSpeaker类程序代码的情况下,可以为其加入记录的功能。这只是在hello()方法前后由代理对象speakerProxy先执行记录功能而已,真正运行hello()方法时才使用speaker对象。

分享到:
评论

相关推荐

    Java反射 JavaBean对象自动生成插入,更新,删除,查询sql语句操作.docx

    在Java反射JavaBean对象自动生成插入、更新、删除、查询sql语句操作中,主要使用了Java反射机制来获取JavaBean对象的信息,然后根据这些信息生成对应的sql语句。例如,通过Java反射机制可以获取JavaBean对象的成员...

    C#,利用反射动态创建对象

    要使用反射创建对象,首先需要获取目标类型的Type对象。这可以通过以下两种方式完成: - 使用`typeof`关键字:`Type myType = typeof(MyClass);` - 使用`Type.GetType()`方法:`Type myType = Type.GetType(...

    在反射动态机制生成对象的实体

    反射是Java编程语言的一个核心特性,它允许程序在运行时检查、操作类的信息以及创建对象。通过反射,开发者可以实现高度灵活的应用程序,例如框架、插件系统等,其中非常重要的一环就是能够动态地创建对象。本文将...

    C#反射生成SQL实例

    反射生成SQL实例的核心在于,它允许程序在运行时动态地获取类型信息,并根据这些信息创建和执行SQL语句。以下是一些关键知识点: 1. **反射基础**:C#中的System.Reflection命名空间包含了所有与反射相关的类。其中...

    C#泛型、反射实例、自动生成sql语句

    在C#中,利用泛型和反射可以创建灵活的数据库操作库,自动根据实体类生成对应的SQL语句。例如,我们可以定义一个泛型方法,接受一个类型参数,这个类型对应于数据库表的实体模型: ```csharp public void Save(T ...

    注解反射生成SQL语句

    例如,我们可以创建一个自定义的处理器,该处理器会在编译期间检查带有特定注解的类,并自动生成相应的DAO(数据访问对象)类,这些DAO类已经包含了基于注解信息生成的SQL方法。 总的来说,结合注解和反射,开发者...

    java使用反射创建并操作对象的方法

    Java 使用反射创建并操作对象的方法 Java 的反射机制允许程序在运行时动态地创建和操作对象,这是 Java 程序设计中非常重要的一种技术。下面我们将详细介绍 Java 使用反射创建并操作对象的方法。 反射机制概述 ...

    动态代码的使用(反射和动态生成类)

    动态代码的使用(反射和动态生成类) 在软件开发中,尤其是在框架和底层开发时,为了更灵活地控制代码,常常需要进行一些动态的操作。动态代码的使用可以分为两大类:反射和动态生成类。 一、反射的使用 反射是...

    Qt 使用QMetaObject实现反射机制代码demo

    在编程领域,反射机制是一种强大的特性,允许程序在运行时检查自身的行为,包括类的信息、对象的状态以及函数的调用等。在C++的世界里,Qt框架提供了一种实现反射的手段,即QMetaObject系统。这个系统允许我们动态地...

    仿hibernate动态生成sql保存对象

    Hibernate允许开发者将Java对象与数据库表进行映射,通过对象的CRUD(创建、读取、更新、删除)操作实现对数据库的数据操作。在Hibernate中,我们通常使用注解来定义这些映射,比如`@Entity`表示这是一个可持久化的...

    利用java反射将json字符串转成对象.zip

    现在我们有了一个包含JSON数据的Map,可以开始使用反射来创建对应的Java对象。假设我们有一个User类: ```java public class User { private String name; private int age; // getters and setters } ``` 接...

    使用反射获取和设置对象的值

    - **代码生成和编译**:例如,Apache的Velocity和FreeMarker模板引擎使用反射生成运行时代码。 - **元编程**:允许在运行时检查和修改程序的行为。 - **插件系统**:允许加载未知类并执行其方法。 - **序列化和反...

    Java反射 JavaBean对象自动生成插入,更新,删除,查询sql语句操作

    Java反射 JavaBean 对象自动生成插入、更新、删除、查询 SQL 语句操作 Java 反射是 Java 语言中一个强大的功能,它允许开发者在运行时检查和修改类、方法、字段的行为。Java 反射机制可以动态地创建对象、调用方法...

    C# 根据字符串动态生成控件(反射原理),可鼠标拖动

    通过反射,我们可以获取类、接口、属性、方法和事件等元数据信息,并在运行时创建和操作对象。在C#中,`System.Reflection`命名空间提供了关于反射所需的所有类和方法。 动态生成控件是指在程序运行时根据需求创建...

    反射查询SQL框架

    在IT行业中,反射查询SQL框架是一种高级编程技术,它结合了面向对象的编程特性与数据库操作,使得开发者可以通过对象和属性来动态构建SQL语句,从而实现对数据库的增、删、改、查(CRUD)操作。这种技术极大地提高了...

    java 代码反射生成工具_generatorConfig

    Java 反射生成工具_generatorConfig 是一个用于自动化生成Java Bean及Mapper XML文件的实用工具。在Java开发中,反射机制是一种强大的技术,它允许程序在运行时检查和修改类、对象及其属性。generatorConfig则是利用...

    java反射全解(反射原理+反射API详解+反射与数组+反射与泛型+反射源码与性能开销+反射优缺点+反射与内省)

    要想使用反射,首先需要获得待操作的类所对应的 Class 对象。java.lang.Class 是所有反射 API 的入口点。通过 Class 对象,可以获悉整个类的结构,包括其modifiers、superclass、实现的 interfaces、fields 和 ...

    反射+注解自定义ORM

    在Java编程中,ORM(Object-Relational Mapping)是一种技术,它允许程序员使用面向对象的方式来操作数据库,将数据库中的表映射为Java对象,而无需编写大量的SQL语句。本主题探讨的是如何通过反射和注解来自定义ORM...

    android 使用反射机制操作数据库 插入 查询

    本文将深入探讨如何使用反射机制来操作SQLite数据库,包括插入数据和查询数据,以实现更加灵活和高效的数据库操作。 首先,我们要了解反射的概念。在Java中,反射是一种强大的工具,它允许我们在运行时检查类、接口...

    JAVA反射机制动态调用 计算器对象的加法,减法函数;JAVA反射机制修改一个学生对象 的私有数据成员

    总结起来,Java反射机制提供了一种强大的工具,让我们可以在运行时动态地操作类和对象,这包括调用方法和访问私有字段。但同时,也需要注意其可能带来的副作用。在上述示例中,我们展示了如何利用反射来实现计算器的...

Global site tag (gtag.js) - Google Analytics