------
Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
取得构造方法还有一个途径就是Class实例方法.getConstructors() 它返回类的所有公共构造方法数组,然后可以遍历整个结果,利用.getGenericParameterTypes()分析参数类型,最后选择适合的构造方法。这种方法适用于黑箱操作,毕竟开发的时候不大可能完全了解可能加载的构造方法列表。
JAVA的反射(java.lang.reflect)机制提供了在运行时加载类,取得类信息,构造类实例对象,取得和设置静态和实例字段,取得和引发(invoke)类的静态和实例方法的一系列工具,为各种框架和应用带来了极高的动态扩展能力,并且提供了运行时改变业务逻辑的可能,这个特性不能不了解一下。
下面我分别作一些简单的例子来试试这些功能
为了方便测试 做一个测试的目标和简单输出语句
class ReflectPoint extends Rflt implements Point {
int x, y;
String comment;
int[] val;
private static int rect(int xl, int yl) {
return xl * yl;
}
@Override
public String toString() {
return "ReflectPoint [x=" + x + ", y=" + y + ", comment=" + comment
+ ", val=" + Arrays.toString(val) + "]";
}
public ReflectPoint(int x, int y, String comment, int[] val) {
super();
this.setX(x);
this.y = y;
this.comment = comment;
this.val = val;
}
@Override
public int getX() {
return x;
}
private void setX(int x) {
this.x = x;
}
@Override
public int getY() {
return y;
}
void setY(int y) {
this.y = y;
}
private static boolean not(boolean b) {
return !b;
}
@Override
protected String getComment() {
return comment;
}
}
abstract class Rflt {
abstract String getComment();
}
interface Point {
int getX();
int getY();
}
public static void sp(Object o) {
if (o == null) {
System.out.println("null");
}
if (o.getClass().isArray()) {
StringBuilder sb = new StringBuilder();
int len = Array.getLength(o);
sb.append('[');
for (int i = 0; i < len; i++) {
if (i != 0) {
sb.append(':');
}
sb.append(Array.get(o, i));
}
sb.append(']');
System.out.println(sb);
} else {
System.out.println(o);
}
}
首先试试取得类:
private static void testClass() {
// 构造一个样例
int[] val={3,4,7};
ReflectPoint rp=new ReflectPoint(12, 25, "ref test", val);
//取得类的3种常见方式 1.直接用类名.class 2.用已知类实例的.getClass()
//3.用Class的静态方法forName(String className) !!注意这种方式如果在classpath下找不到类会引发ClassNotFoundException
Class c1=ReflectPoint.class,c2=rp.getClass(),c3=null;
try {
c3=Class.forName("com.itheima.ReflectPoint");
} catch (ClassNotFoundException e) {
throw new RuntimeException("ClassNotFound");
}
//以下三个输出都是class com.itheima.ReflectPoint
sp(c1);
sp(c2);
sp(c3);
//类路径错误的例子
try {
Class.forName("com.test.IdontExist");
} catch (ClassNotFoundException e) {
//throw new RuntimeException("ClassNotFound");
sp("com.test.IdontExists not found");
}
//三种方式取得的Class实例在同一个类加载器下是单例,所以可以用==来比较,当然用.equals也行
sp(c1==c2);//true
sp(c1==c3);//true
}
那么有了类,试试构建实例对象
private static void testConstructer() {
// 构造必要的数据
int[] val = { 3, 4, 7 };
int x = 12, y = 25;
String comm = "cons test";
// 取得Constructor
// 这里使用了直接指定参数列表取得指定的构造函数的方式,当然如果参数不匹配会导致NoSuchMethodException
// 而当前运行时上下文无权限访问(修饰符限定)时,会导致SecurityException 就要改用暴力反射才能继续了
Constructor<ReflectPoint> constructor=null;
try {
constructor= ReflectPoint.class.getConstructor(int.class,int.class,String.class,int[].class);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException("Constructor can not get");
}
//构造实例
//这里直接用.newInstance()方法即可,当然:参数列表必须匹配
ReflectPoint rp=null;
if(constructor!=null){
try {
rp=constructor.newInstance(x,y,comm,val);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Construct Instance fail");
}
}
//测试一下实例
if(rp!=null){
sp(rp);
sp(rp.x);
sp(rp.y);
sp(rp.comment);
sp(rp.val);//OK 构造成功 字段都取得了
}
}
取得构造方法还有一个途径就是Class实例方法.getConstructors() 它返回类的所有公共构造方法数组,然后可以遍历整个结果,利用.getGenericParameterTypes()分析参数类型,最后选择适合的构造方法。这种方法适用于黑箱操作,毕竟开发的时候不大可能完全了解可能加载的构造方法列表。
取得字段的例子,这里使用了暴力反射,而且逐个修改了传入的对象的字段:
/*
* 测试时传入的对象 int[] val = { 3, 4, 7 }; ReflectPoint rp = new ReflectPoint(12,
* 25, "ref test", val); testFields(rp);
*/
private static void testFields(Object o) {
// 现在,传入了一个Object类型对象 显然信息是极少的
// 那么就必须用反射来获取他的各种信息
// 这里测试获取他的字段并作修改
// 修改前
sp(o);
// ReflectPoint [x=12, y=25, comment=ref test, val=[3, 4, 7]]
// 这里为了取得所有的成员字段,使用了getDeclared系列方法和setAccessible强制访问,所谓的暴力反射
Field[] fields = o.getClass().getDeclaredFields();
for (Field field : fields) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
// 可以根据字段类型判断
if (field.getType().isPrimitive()) {
// 也可以根据字段名称判断
switch (field.getType().getName()) {
// 简单修改一下整形内容
case "int":
int mod = 0;
switch (field.getName()) {
case "x":
mod = 7;
break;
case "y":
mod = -10;
break;
default:
break;
}
try {
// 用get方法取,用set方法写入
field.set(o, (int) (field.get(o)) + mod);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Field " + e.getMessage());
}
break;
default:
break;
}
} else {
switch (field.getType().getName()) {
// 修改String 这里类型名是完整的限定名
case "java.lang.String":
try {
field.set(o, (String) (field.get(o)) + "edited");
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Field " + e.getMessage());
}
break;
// 数组类型名为'['+元素类型名 基本类型用一个大写字符表示, I表示int
case "[I":
try {
Object arr = field.get(o);
int[] val = new int[Array.getLength(arr) + 2];
int sum = 0;
for (int i = 0; i < Array.getLength(arr); i++) {
int intValue = Array.getInt(arr, i);
sum += intValue;
val[i] = intValue;
}
val[val.length - 2] = 787;
val[val.length - 1] = sum + 787;
field.set(o, val);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Field " + e.getMessage());
}
break;
default:
break;
}
}
}
// 修改后
sp(o);
// ReflectPoint [x=19, y=15, comment=ref testedited, val=[3, 4, 7, 787,
// 801]]
// 可以看到修改成功了
}
最后 测试一下方法的反射
private static void testMethod() {
// 还是先准备一个对象
int[] val = { 3, 4, 7 };
ReflectPoint rp = new ReflectPoint(12, 25, "ref test", val);
// 还是暴力一下,拿到所有方法
Method[] mths = rp.getClass().getDeclaredMethods();
for (Method method : mths) {
if (!method.isAccessible()) {
method.setAccessible(true);
}
// 先看看相关的信息
sp(method.getName());
sp(method.getModifiers());
sp(method.getParameterTypes());
sp(method.getReturnType());
// 调用一下试试看
Object result = null;
Class<?>[] paraType = method.getParameterTypes();
int paraCount = paraType.length;
Object[] paras = new Object[paraCount];
for (int i = 0; i < paraCount; i++) {
paras[i] = defaultValue(paraType[i]);
}
switch (method.getParameterTypes().length) {
case 0:
try {
result = method.invoke(rp);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException("Method " + e.getMessage());
}
break;
case 1:
try {
result = method.invoke(rp, paras[0]);
} catch (IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Method " + e.getMessage());
}
break;
case 2:
try {
result = method.invoke(rp, paras[0], paras[1]);
} catch (IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Method " + e.getMessage());
}
break;
// 再多参数就不管了
default:
break;
}
sp(method);
if (result != null) {
sp(result);
}else{
sp("null|void");
}
}
}
private static Object defaultValue(Class<?> cls) {
if (cls.isPrimitive()) {
switch (cls.getName()) {
case "byte":
case "char":
case "short":
case "int":
case "long":
return (byte) 0;
case "float":
case "double":
return 0.0f;
case "boolean":
return false;
case "void":
return null;
}
} else {
try {
return cls.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
sp("unable to init default instance");
return null;
}
}
// TODO Auto-generated method stub
return null;
}