在任何语言里,数组都是基本的数据类型,我们这一节将讲述如何生成数组操作。
数组操作包括以下几个:
- 创建数组
- 获取数组长度
- 获取数组每个元素的内容
- 为数组元素赋值
我们接下来对每种操作进行详解。
创建数组
我们知道在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);
}
}
 
  
  
  
 
