在任何语言里,数组都是基本的数据类型,我们这一节将讲述如何生成数组操作。
数组操作包括以下几个:
- 创建数组
- 获取数组长度
- 获取数组每个元素的内容
- 为数组元素赋值
我们接下来对每种操作进行详解。
创建数组
我们知道在java中创建数有以下几种方式:
- 只为数组的分配一定大小的空间,比如:int\[\]\[\] i1 = new int\[2\]\[2\];
- 如果是多维数组只为部分维度分配空间,比如:int\[\]\[\] i2 = new int\[2\]\[\];
- 在创建数组的时候为每个元素赋值,比如:String\[\] s1 = { "array \\"s1\\" first value", "array \\"s1\\" second value" };
- 这种方式和第三中方式差不多,只不过这里创建的是多维数组,比如:String\[\]\[\] s2 = { { "s2\[0\]\[0\]", "s2\[0\]\[1\]" }, { "s2\[1\]\[0\]", "s2\[1\]\[1\]" } };
那么我么如何使用ASMSupport创建上面的四种数组呢,我们按照上面介绍的四种方式的顺序来介绍。
1.只为数组的分配一定大小的空间,创建int\[\]\[\] i1 = new int\[2\]\[2\];
这种方式创建数组我们需要使用的是如下方法:
jw.asmsupport.block.ProgramBlock.newArray(final ArrayClass aClass, final Parameterized... allocateDims):
- 参数:
- 当前需要创建的数组值是什么类型(类型是ArrayClass)
- 为其每一个维分配的空间数, 这是个变元参数,为什么变元参数,在我们用第二种方式创建数组的时候将会用到。
- 返回类型:
这个方法返回的是一个jw.asmsupport.operators.array.ArrayValue类型,这个类型就是表示一个数组。我们看到第一个参数是jw.asmsupport.clazz.ArrayClass类型的, 我们通过AClassFactory的getArrayClass方法获取其对应的AClass.这里介绍下getArrayClass的方法:
getArrayClass有三个重载的方法:
- getArrayClass(Class<?> arrayCls): 这里的参数类型是一个Array的类型。比如我们需要获取一个int\[\]类型的ArrayClass,那么我们可以通过getArrayClass(int\[\].class)获取
- getArrayClass(Class<?> cls, int dim): 这里的第一参数是一个任意类型的Class。第二个参数表示需要创建的ArrayClass的维数。通过这个方法得到的将是一个以第一个参数为基本类型,维数为第二个参数的ArrayClass。比如:getArrayClass(int.class, 2)将得到一个int\[\]\[\]类型的ArrayClass;getArrayClass(int\[\].class, 2)将得到一个int\[\]\[\]\[\]类型的ArrayClass。
- getArrayClass(AClass cls, int dim): 这个方法和上面那个方法类似,只是将第一个个参数类型变成了AClass。其他相同这里还可以通过getProductClass(Class<?> cls)方法获取ArrayClass,和 getArrayClass(Class<?> arrayCls)用法相同。只是返回类型是AClass。我们可以将其强制转换成ArrayClass。
介绍了这么多,那么我们就可以用下面的代码来生成字节码内容:
ArrayValue av = newArray(AClassFactory.getArrayClass(int\[\]\[\].class), Value.value(2), Value.value(2)); LocalVariable i1 = createArrayVariable("i1", AClassFactory.getArrayClass(int\[\]\[\].class), false, av);
解释下上面的代码,首先通过newArray方法创建一个数组值av,再创建一个i1变量并将av赋值给i1再创建System.out.println(ArrayUtils.toString(i1)),下面是对应的生成的代码:
2.如果是多维数组只为部分维度分配空间,创建int\[\]\[\] i2 = new int\[2\]\[\];
这里我们用的方法和上面第一种方式的一样,唯一不同的就是我们的变元参数的传递,这里我们只需要传递第一个维度的值就可以了,这也就是为什么需要用变元参数的原因。代码如下:
av = newArray(AClassFactory.getArrayClass(int\[\]\[\].class), Value.value(2)); LocalVariable i2 = createArrayVariable("i2", AClassFactory.getArrayClass(int\[\]\[\].class), false, av);
3.在创建数组的时候为每个元素赋值,创建String\[\] s1 = { "array \\"s1\\" first value", "array \\"s1\\" second value" };
这里有五个方法可以实现这种方式:
- public ArrayValue newArrayWithValue(final ArrayClass aClass, final Object arrayObject)
- public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized\[\] values)
- public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized\[\]\[\] values)
- public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized\[\]\[\]\[\] values)
- public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized\[\]\[\]\[\]\[\] values)
第2,3,4,5方法实际上是通过调用第一方法实现的,所以这里我们重点讨论第一个方法。这些方法都是有两个参数:
- 第一个参数是数组类型和newArray操作是一样的。
- 第二个参数是我们设置的默认值,虽然我们定义的是个Object类型的,但是在实际应用的时候必须得是Parameterized的数组类型否则会抛异常。至于是几维数组,则根据我们所定义的类型而定。其实asmsupport始终保持着类似于java的编程方式。比如我们创建一个二维数组那么我们可以说设置这个值为:new Parameterized\[\]{new Parameterized\[\]{p1, p2}}。
我们可以通过下面的代码实现:
av = newArrayWithValue(AClassFactory.getArrayClass(String\[\].class), new Value\[\]{Value.value("array \\"s1\\" first value"), Value.value("array \\"s1\\" second value")}); LocalVariable s1 = createArrayVariable("s1", AClassFactory.getArrayClass(String\[\].class), false, av);
4.创建多维数组的时候同时赋值,创建String\[\]\[\] s2 = { { "s2\[0\]\[0\]", "s2\[0\]\[1\]" }, { "s2\[1\]\[0\]", "s2\[1\]\[1\]" } }
这里其实用的也是第三种方式的asmsupport的方法,只不过这个时候我们需要传入一个二维数组:
Value s200 = Value.value("s2\[0\]\[0\]"); Value s201 = Value.value("s2\[0\]\[1\]"); Value s210 = Value.value("s2\[1\]\[0\]"); Value s211 = Value.value("s2\[1\]\[1\]");av = newArrayWithValue(AClassFactory.getArrayClass(String[][].class), new Value[][]{new Value[]{s200, s201}, new Value[]{s210, s211}}); LocalVariable s2 = createArrayVariable("s2", AClassFactory.getArrayClass(String[][].class), false, av);
这里就是创建数组的部分。
获取数组的长度
获取数组长度采用的方法是jw.asmsupport.block.ProgramBlock的:
public final ArrayLength arrayLength(IVariable arrayReference, Parameterized... dims):
- 参数
- 数组对象
- 数组的每个维度的下标,比如我们要获取i\[0\]\[1\].length, 我们就调用arrayLength(a, Value.value(0), Value.value(1))
- 返回类型
返回类型是jw.asmsupport.operators.array.ArrayLength,他是asmsupport对获取length操作的抽象.
获取数组每个元素的内容
获取每个元素采用的方法是jw.asmsupport.block.ProgramBlock的:
public final ArrayLoader arrayLoad(IVariable arrayReference, Parameterized pardim, Parameterized... parDims):
- 参数
- 数组对象
- 第一维的数组的下标
- 第二维开始,每个维度的下标
- 返回类型
返回类型是jw.asmsupport.operators.array.ArrayLoader,他是asmsupport对获取获取数组元素操作的抽象.
为数组元素赋值
为数组元素赋值采用的方法是jw.asmsupport.block.ProgramBlock的:
public final ArrayStorer arrayStore(IVariable arrayReference, Parameterized value, Parameterized dim, Parameterized... dims):
- 参数
- 数组对象
- 为数组元素赋予的值
- 第一维的数组的下标
- 第二维开始,每个维度的下标
- 返回类型
返回类型是jw.asmsupport.operators.array.ArrayStorer,他是asmsupport对获取获取数组元素操作的抽象.
实例
我们需要生成如下代码:
public static void willGenerate(){ int\[\]\[\] i1 = new int\[2\]\[2\]; System.out.println("i1 = " + ArrayUtils.toString(i1));int[][] i2 = new int[2][]; System.out.println("i2 = " + ArrayUtils.toString(i2)); String[] s1 = { "array \"s1\" first value", "array \"s1\" second value" }; System.out.println("s1 = " + ArrayUtils.toString(s1)); String[][] s2 = { { "s2[0][0]", "s2[0][1]" }, { "s2[1][0]", "s2[1][1]" } }; System.out.println("s2 = " + ArrayUtils.toString(s2)); //获取数组长度操作 System.out.println("length of s2 is " + s2.length); System.out.println("length of s2[0] is " + s2[0].length); //获取数组内容的操作 System.out.println("value of s2[0] is " + ArrayUtils.toString(s2[0])); System.out.println("value of s2[0][0] is " + ArrayUtils.toString(s2[0][0])); //为数组内容赋值的操作 s2[0] = new String[]{ "new s2[0][0]", "new s2[0][1]" }; s2[1][0] = "new s2[1][0]"; System.out.println("new value of s2 is : " + ArrayUtils.toString(s2));
}
对应的asmsupport的代码如下:
package example.operators;import org.apache.commons.lang.ArrayUtils; import org.objectweb.asm.Opcodes;
import jw.asmsupport.Parameterized; import jw.asmsupport.block.method.common.StaticMethodBody; import jw.asmsupport.clazz.AClass; import jw.asmsupport.clazz.AClassFactory; import jw.asmsupport.creator.ClassCreator; import jw.asmsupport.definition.value.Value; import jw.asmsupport.definition.variable.LocalVariable; import jw.asmsupport.operators.array.ArrayValue;
import example.AbstractExample;
/**
在这个例子中我们将实现数组的相关操作
@author 温斯群(Joe Wen)
*/ public class ArrayOperatorGenerate extends AbstractExample {
/**
* @param args
*/
public static void main(String[] args) {
ClassCreator creator = new ClassCreator(Opcodes.V1_5, Opcodes.ACC_PUBLIC , "generated.operators.ArrayOperatorGenerateExample", null, null);
creator.createStaticMethod("main", new AClass[]{AClassFactory.getProductClass(String[].class)}, new String[]{"args"}, null, null,
Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, new StaticMethodBody(){
@Override
public void generateBody(LocalVariable... argus) {
/*
* 1.首先我们需要创建一个数组。我们有两只方式创建数组,第一种是在创建数组的时候
* 为其分配数组空间。第二种是创建数组的时候为其分配初试值
*/
//int[][] i1 = new int[1][2];
//System.out.println(ArrayUtils.toString(i1));
/*
*
* 对应如下代码:
* int[][] i1 = new int[1][2];
* System.out.println("i1 = " + ArrayUtils.toString(i1));
*/
ArrayValue av = newArray(AClassFactory.getArrayClass(int[][].class), Value.value(2), Value.value(2));
LocalVariable i1 = createArrayVariable("i1", AClassFactory.getArrayClass(int[][].class), false, av);
invoke(systemOut, "println", append(Value.value("i1 = "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", i1)));
/*
* 下面一段代码将生成如下代码:
* int[][] i2 = new int[2][];
* System.out.println("i2 = " + ArrayUtils.toString(i2));
*/
av = newArray(AClassFactory.getArrayClass(int[][].class), Value.value(2));
LocalVariable i2 = createArrayVariable("i2", AClassFactory.getArrayClass(int[][].class), false, av);
invoke(systemOut, "println", append(Value.value("i2 = "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", i2)));
/*
* 对应如下代码:
* String[] s1 = new String[]{"array \"s1\" first value", "array \"s1\" second value"};
* System.out.println("s1 = " + ArrayUtils.toString(s1));
*/
av = newArrayWithValue(AClassFactory.getArrayClass(String[].class), new Value[]{Value.value("array \"s1\" first value"), Value.value("array \"s1\" second value")});
LocalVariable s1 = createArrayVariable("s1", AClassFactory.getArrayClass(String[].class), false, av);
invoke(systemOut, "println", append(Value.value("s1 = "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", s1)));
/*
* 对应如下代码:
* String[][] s2 = {{"s2[0][0]", "s2[0][1]"},{"s2[1][0]", "s2[1][1]"}};
* System.out.println("s2 = " + ArrayUtils.toString(s2));
*/
Value s200 = Value.value("s2[0][0]");
Value s201 = Value.value("s2[0][1]");
Value s210 = Value.value("s2[1][0]");
Value s211 = Value.value("s2[1][1]");
av = newArrayWithValue(AClassFactory.getArrayClass(String[][].class),
new Value[][]{new Value[]{s200, s201}, new Value[]{s210, s211}});
LocalVariable s2 = createArrayVariable("s2", AClassFactory.getArrayClass(String[][].class), false, av);
invoke(systemOut, "println", append(Value.value("s2 = "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", s2)));
/*
* 接下来我们将获取数组的长度:
* 代码如下:
* System.out.println("length of s2 is " + s2.length);
* System.out.println("length of s2[0] is " + s2[0].length);
*/
invoke(systemOut, "println", append(Value.value("length of s2 is "), arrayLength(s2)));
invoke(systemOut, "println", append(Value.value("length of s2[0] is "), arrayLength(s2, Value.value(0))));
/*
* 接下来我们将实现如何获取数组的值
* 代码如下:
* System.out.println("value of s2[0] is " + ArrayUtils.toString(s2[0]));
* System.out.println("value of s2[0][0] is " + s2[0][0]);
*/
//s2[0]
Parameterized arrayLoader = arrayLoad(s2, Value.value(0));
invoke(systemOut, "println", append(Value.value("value of s2[0] is "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", arrayLoader)));
//s2[0][0]
arrayLoader = arrayLoad(s2, Value.value(0), Value.value(0));
invoke(systemOut, "println", append(Value.value("value of s2[0][0] is "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", arrayLoader)));
/*
* 接下来是如何实现为数组单元赋值的操作
* 代码如下
* s2[0] = new String[]{"new s2[0][0]", "new s2[0][1]"};
* s2[1][0] = "new s2[1][0]"
* System.out.println("new value of s2 is : " + ArrayUtils.toString(s2));
*/
arrayStore(s2, newArrayWithValue(AClassFactory.getArrayClass(String[].class), new Parameterized[]{Value.value("new s2[0][0]"), Value.value("new s2[0][1]")}), Value.value(0));
arrayStore(s2, Value.value("new s2[1][0]"), Value.value(1), Value.value(0));
invoke(systemOut, "println", append(Value.value("new value of s2 is : "), invokeStatic(AClassFactory.getProductClass(ArrayUtils.class), "toString", s2)));
runReturn();
}
});
generate(creator);
}
}