工学1号馆

home

java反射的应用

By Wu Yudong on June 12, 2015

原创文章,转载请注明: 转载自工学1号馆

最近在学习java的反射机制,在《java核心系列11-反射》中,总结了java反射的,这篇文章将实战中体会java反射的强大和优势。

使用反射编写泛型数组代码

【例1】假设有这样一个需求:设计一个通用的程序,将一个任意类型的数组的长度扩大为指定的长度

比如将一个指定类型的对象数组扩展:

Employee[] a = new Employee[100];
a = Arrays.copyOf(a, 2 * a.length);

但是上面的代码并不具有通用性,接着看看下面的代码:

public static Object[] badCopyOf(Object[] a, int newLength) {
	Object[] newArray = new Object[newLength];
	System.arraycopy(a, 0, newArray, 0, Math.max(a.length, newLength));
	return newArray;
}

上面的代码返回值的类型为Object[],在转换为 Employee的时候产生异常。

这里需要java.lang.reflect包中的Array类的一些方法,其中最关键的是newInstance,它能够构造新数组。

Object  newArray = Array.newInstance(componentType,  newLength);

这个方法中需要两个参数:数组的类型和长度。

这里的关键是获取数组的类型,这里分三步:

1、获取数组a的类对象

2、确定这个参数是数组

3、使用Class类的getComponentType方法确定数组对应的类型

看下面的代码:

public static Object goodCopyOf(Object a, int newLength) {
	Class cl = a.getClass();
	if(!cl.isArray()) return null;
	Class componentType = cl.getComponentType();
	int length = Array.getLength(a);
	Object newArray = Array.newInstance(componentType, newLength);
	System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
	return newArray;
}

下面是完整的测试代码:

import java.lang.reflect.Array;
import java.util.Arrays;

public class test {
	public static Object[] badCopyOf(Object[] a, int newLength) {
		Object[] newArray = new Object[newLength];
		System.arraycopy(a, 0, newArray, 0, Math.max(a.length, newLength));
		return newArray;
	}
	public static Object goodCopyOf(Object a, int newLength) {
		Class cl = a.getClass();
		if(!cl.isArray()) return null;
		Class componentType = cl.getComponentType();
		int length = Array.getLength(a);
		Object newArray = Array.newInstance(componentType, newLength);
		System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
		return newArray;
	}
	public static void main(String[] args) {
		int[] a = {1, 2, 3};
		a = (int[])goodCopyOf(a, 10);
		System.out.println(Arrays.toString(a));
		String[] name = {"wu", "yu", "dong"};
		name = (String[])goodCopyOf(name, 10);
		System.out.println(Arrays.toString(name));
		//error!  name = (String[])badCopyOf(name, 10);
	}
}

【例2】打印通用对象,如果对象是数组,逐个元素打印,如果是其他的对象,则直接打印对象

private static void printObject(Object obj) {
	Class clazz = obj.getClass();
	if(clazz.isArray()) {
		int len = Array.getLength(obj);
		for(int i = 0; i <len; i++) {
			System.out.println(Array.get(obj, i));
		}
	} else {
		System.out.println(obj);
	}
}

调用任意方法

利用反射技术还可以获取类的指定方法,使用Method对象实现C语言中的函数指针的所有操作。

import java.lang.reflect.Method;

public class MethodPointerTest {
	public static void main(String[] args) throws Exception{
		Method square = MethodPointerTest.class.getMethod("square", double.class);
		Method sqrt = MethodPointerTest.class.getMethod("sqrt", double.class);
		printTable(1, 10, 10, square);
		printTable(1, 10, 10, sqrt);

	}
	
	public static double square(double x) {
		return x * x;
	}
	
	public static double sqrt(double x) {
		return Math.sqrt(x);
	}
	
	public static void printTable(double from, double to, int n, Method f) {
		System.out.println(f);
		double dx = (to - from) / (n - 1);
		for(double x = from; x <= to; x += dx) {
			try {
				double y = (Double)f.invoke(null, x);
				System.out.printf("%10.4f | %10.4f%n", x, y);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}

第六行还可以换成:Method sqrt = Math.class.getMethod("sqrt", double.class); 同时把类中的静态方法sqrt删除

运行结果如下:

public static double MethodPointerTest.square(double)
1.0000 | 1.0000
2.0000 | 4.0000
3.0000 | 9.0000
4.0000 | 16.0000
5.0000 | 25.0000
6.0000 | 36.0000
7.0000 | 49.0000
8.0000 | 64.0000
9.0000 | 81.0000
10.0000 | 100.0000
public static double MethodPointerTest.sqrt(double)
1.0000 | 1.0000
2.0000 | 1.4142
3.0000 | 1.7321
4.0000 | 2.0000
5.0000 | 2.2361
6.0000 | 2.4495
7.0000 | 2.6458
8.0000 | 2.8284
9.0000 | 3.0000
10.0000 | 3.1623

如果文章对您有帮助,欢迎点击下方按钮打赏作者

Comments

No comments yet.
To verify that you are human, please fill in "七"(required)