反射
1,基本概念
反射库提供了一个精心设计的工具集,用来编写能够动态操纵Java代码的程序。能够分析类能力的程序成为反射。反射具有以下特性:
在运行时分析类的能力。
运行时查看对象。
实现通用的数组操作代码。
利用Method对象。
2.Class类
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标示。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择响应的方法执行。这个信息被称为Class对象。
/**
* 反射
*/
public class ReflectDemo {
public static void main(String[] args) {
String s = "java.util.Random";
try {
// newInstance是Class对象的一个静态方法,可以获取当前类型的对象,
// 这个方法调用的是类的默认构造方法,如果没有默认构造会抛出异常信息
Object o = Class.forName(s).newInstance();
System.out.println("o = " + o );
} catch (Exception e) {
e.printStackTrace();
}
/*
获取类的Class对象(包括包路径)
3中获取类对象的方式
// 在知道类型时候获取Class对象
(1)Class cl = Integer.class;
// 在不知道类型的时候,但是存在该类型的变量的时候获取Class对象
(2) Integer a = 3;
Class cl1 = a.getClass();
// 完全不知道当前类型也不存在类的实例时获取Class对象
(3) Class cl2 = Class.forName(a); 此种方法存在异常必须要处理
*/
}
}
2.利用反射分析类的能力
这个是反射最强大的功能,他可以让我们在不知任何该类信息的时候,分析类的信息,并构建该类的对象并使用。
/**
* 反射
*/
public class ReflectDemo {
public static void main(String[] args) {
String name;
// 获取启动时参数,如果存在就使用启动时参数,否则输入自己的类名
if (args.length > 0) {
name = args[0];
}else {
Scanner in = new Scanner(System.in);
System.out.println("Enter class name(e.g. java.lang.String): ");
// 输入 java.lang.String 查看
name = in.next();
}
try {
Class c1 = Class.forName(name);
// 获取当前类的父类
Class superC1 = c1.getSuperclass();
// 返回当前类的所有修饰符
String modifiers = Modifier.toString(c1.getModifiers());
if (modifiers.length() > 0 ){
System.out.print(modifiers + " ");
}
System.out.print("class " + name);
if (superC1 != null && superC1 != Object.class) {
System.out.print(" extends " + superC1.getName());
}
System.out.println("\n{");
// 打印类的构造方法
printConstructors(c1);
System.out.println();
// 打印对象方法的有关信息
printMethods(c1);
System.out.println();
// 打印类实例域信息
printFields(c1);
System.out.println("}");
}catch (Exception e ){
e.getStackTrace();
}
}
/**
* 打印类实例域信息
* @param c1
*/
private static void printFields(Class c1) {
// 获取所有当前类的公有实例域,以及父类的公有实例域
Field[] field1 = c1.getFields();
// 获取所有当前类的实例域,以及父类的实例域
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
// 获取实例域的类型
Class type = field.getType();
// 获取实例域的名称
String name = field.getName();
System.out.print(" ");
// 获取实例域的修饰符
String modifiers = Modifier.toString(field.getModifiers());
if (modifiers.length() > 0 ){
System.out.print(modifiers + " ");
}
System.out.println(type.getName() + " " + name + " ");
}
}
/**
* 打印对象方法的有关信息
* @param c1
*/
private static void printMethods(Class c1) {
// 获取所有当前类的公有方法,以及父类的公有方法
Method[] method1 = c1.getMethods();
// 获取所有当前类的方法,以及父类的方法,但不包括父类继承的方法
Method[] methods = c1.getDeclaredMethods();
for (Method m : methods) {
// 获取方法的返回值
Class type = m.getReturnType();
String name = m.getName();
System.out.print(" ");
// 获取方法的修饰符
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0 ){
System.out.print(modifiers + " ");
}
System.out.print(type.getName() + " " + name + "(");
// 获取方法的所有参数类型
Class[] params = m.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (i > 0) {
System.out.print(", ");
}
System.out.print(params[i].getName()+ " " + name + " ");
}
System.out.println(");");
}
}
/**
* 打印类的构造方法
* @param c1
*/
private static void printConstructors(Class c1) {
// 获取所有当前类的公有构造器
Constructor[] constructor1 = c1.getConstructors();
// 获取所有当前类的构造器
Constructor[] constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// 获取构造方法的名称
String name = constructor.getName();
System.out.print(" ");
// 获取构造方法的修饰符
String modifys = Modifier.toString(constructor.getModifiers());
if (modifys.length() > 0 ) {
System.out.print(modifys + " ");
}
System.out.print(name + "(");
// 获取构造的所有参数类型
Class[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
if (i > 0) {
System.out.print(", ");
}
// 获取每个参数类型的名称
System.out.print(params[i].getName());
}
System.out.println(");");
}
}
}
3.在运行时使用反射分析对象
前面学习了如果在运行时查看任意对象所属类的信息,下面来讲一下如何在运行时,查看对象的具体信息。
亨达外汇http://www.kaifx.cn/broker/ha...
我以书中的通用toString方法来讲解:
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
/**
* 编写通用的toString方法
*/
public class ToStringDemo {
/**
* 范型数组 暂时理解为相当于一个数组
*/
private ArrayList visited = new ArrayList<>();
/**
* 通用 toString方法
*
* @param object 传入任意对象
* @return 返回对象的信息
*/
public String toString(Object object) {
// 判断传入的对象是否为null
if (object == null) {
return "null";
}
// 判断该数组是否包含这个对象
if (visited.contains(object)) {
return "...";
}
// 获取该类的信息
Class cl = object.getClass();
// 判断是否是字符串类型,如果是直接返回字符串信息
if (cl == String.class) {
return (String) object;
}
// 判断是否是数组
if (cl.isArray()) {
// 只有数组才可以使用getComponentType()返回是什么类型的数组
// 如果不是数组将返回null
String r = cl.getComponentType() + "[]{";
// 遍历数组的长度
for (int i = 0; i < Array.getLength(object); i++) {
// 如果不是第一个就加个逗号
if (i > 0) {
r += ",";
}
// 获取数组中i位置的对象的值
Object val = Array.get(object, i);
// 判断当前数组类型是否是基本类型
if (cl.getComponentType().isPrimitive()) {
// 基本类型直接拼接
r += val;
} else {
// 不是基本类型,递归toString方法。判断对象类型是否数组类型
r += toString(val);
}
}
return r + "}";
}
// 获取类型的名称
String r = cl.getName();
do {
r += "[";
// 获取所有的实例域
Field[] fields = cl.getDeclaredFields();
// 设置访问权限,如果没有访问权限,Java安全机制只允许查看任意对象又那些域,而不允许读取他们的值
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
// 判断实例域是否是静态的
if (!Modifier.isStatic(field.getModifiers())) {
if (!r.endsWith("[")) {
r += ",";
}
r += field.getName() + "=";
try {
// 获取实例域的类型
Class t = field.getType();
// 返回当前实例域的值
Object val = field.get(object);
// 判断该实例域是否是基本类型
if (t.isPrimitive()) {
r += val;
} else {
r += toString(val);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
r += "]";
// 获取当前类是否具有父类
cl = cl.getSuperclass();
} while (cl != null);
return r;
}
public static void main(String[] args) {
// 创建一个数组
ArrayList squares = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
squares.add(i * i);
}
System.out.println(squares.toString());
// 调用通用的toString方法
System.out.println(new ToStringDemo().toString(squares));
// 分析结果:
// 当前类包括elementData[] 和size的实例域
// java.util.ArrayList
// [
// elementData=
// class java.lang.Object[]
// 第一个[]代表当前的Integer的value值,第二个[]代表Integer的父类Number类,第三个[]代表着Number的父类Object类
// {java.lang.Integer[value=1][][],java.lang.Integer[value=4][][],java.lang.Integer[value=9][][],java.lang.Integer[value=16][][],java.lang.Integer[value=25][][],null,null,null,null,null},
// size=5
// ]
// ArrayList的父类 AbstractList类
// [modCount=5]
// AbstractList类 父类list类
// []
// list类的父类Object类
// []
}
}
4.通过反射调用任意方法
import java.lang.reflect.Method;
/**
* 利用反射调用任意方法
*/
public class ReflectMethodDemo {
public static void main(String[] args) throws Exception {
// 返回ReflectMethodDemo类的square方法对象
Method square = ReflectMethodDemo.class.getMethod("square", double.class);
// 返回Math类的sqrt方法对象
Method sqrt = Math.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 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) {
double y = 0;
try {
// 核心方法:执行调用法并返回方法的返回值
// 如果是静态方法,则第一个参数为null,不是静态方法表示调用对象要执行的方法
// 如果方法的返回值是基本类型,那么执行后真实的返回值是对应的包装类型,可以使用对应的自动拆箱转换称double类型
y = (Double) f.invoke(null,x);
System.out.printf("%10.4f | %10.4f%n",x, y);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}5.反射编写数组
/**
* 泛型数组实例
*/
public class ArrayLIstDemo {
public static void main(String[] args) {
int[] a = {1,2,3};
a = (int[]) goodCopy(a,10);
System.out.println(Arrays.toString(a));
String[] b = {"Tom","Dick","Harry"};
b = (String[]) goodCopy(b,10);
System.out.println(Arrays.toString(b));
System.out.println("The following call will generate an exception.");
b = (String[]) badCopyOf(b,10);
}
/**
* 返回对象不能进行转换
* @param a
* @param newLength
* @return
*/
public static Object[] badCopyOf(Object[] a, int newLength){
Object[] newArray = new Object[newLength];
System.arraycopy(a,0,newArray,0,Math.min(a.length,newLength));
return newArray;
}
/**
* 利用反射获取类型并创建一个相同类型的数组在进行拷贝就可以了
* @param a
* @param newLength
* @return
*/
public static Object goodCopy(Object a, int newLength) {
Class cl = a.getClass();
if (!cl.isArray()) {
return null;
}
Class compoentType = cl.getComponentType();
int length = Array.getLength(a);
Object newArray = Array.newInstance(compoentType,newLength);
System.arraycopy(a, 0 , newArray,0,Math.min(length,newLength));
return newArray;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。