ASMSupport教程4.11 生成数组操作

在任何语言里,数组都是基本的数据类型,我们这一节将讲述如何生成数组操作。

数组操作包括以下几个:

  1. 创建数组
  2. 获取数组长度
  3. 获取数组每个元素的内容
  4. 为数组元素赋值

我们接下来对每种操作进行详解。

创建数组

我们知道在java中创建数有以下几种方式:

  1. 只为数组的分配一定大小的空间,比如:int[][] i1 = new int[2][2];
  2. 如果是多维数组只为部分维度分配空间,比如:int[][] i2 = new int[2][];
  3. 在创建数组的时候为每个元素赋值,比如:String[] s1 = { "array \"s1\" first value", "array \"s1\" second value" };
  4. 这种方式和第三中方式差不多,只不过这里创建的是多维数组,比如: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):

  • 参数:
  1. 当前需要创建的数组值是什么类型(类型是ArrayClass)
  2. 为其每一个维分配的空间数, 这是个变元参数,为什么变元参数,在我们用第二种方式创建数组的时候将会用到。
  • 返回类型:

这个方法返回的是一个jw.asmsupport.operators.array.ArrayValue类型,这个类型就是表示一个数组。我们看到第一个参数是jw.asmsupport.clazz.ArrayClass类型的, 我们通过AClassFactory的getArrayClass方法获取其对应的AClass.这里介绍下getArrayClass的方法:

getArrayClass有三个重载的方法:

  1. getArrayClass(Class arrayCls): 这里的参数类型是一个Array的类型。比如我们需要获取一个int[]类型的ArrayClass,那么我们可以通过getArrayClass(int[].class)获取
  2. getArrayClass(Class cls, int dim): 这里的第一参数是一个任意类型的Class。第二个参数表示需要创建的ArrayClass的维数。通过这个方法得到的将是一个以第一个参数为基本类型,维数为第二个参数的ArrayClass。比如:getArrayClass(int.class, 2)将得到一个int[][]类型的ArrayClass;getArrayClass(int[].class, 2)将得到一个int[][][]类型的ArrayClass。
  3. 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" };

这里有五个方法可以实现这种方式:

  1. public ArrayValue newArrayWithValue(final ArrayClass aClass, final Object arrayObject)
  2. public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized[] values)
  3. public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized[][] values)
  4. public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized[][][] values)
  5. public ArrayValue newArrayWithValue(final ArrayClass aClass, final Parameterized[][][][] values)

第2,3,4,5方法实际上是通过调用第一方法实现的,所以这里我们重点讨论第一个方法。这些方法都是有两个参数:

  1. 第一个参数是数组类型和newArray操作是一样的。
  2. 第二个参数是我们设置的默认值,虽然我们定义的是个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):

  • 参数
  1. 数组对象
  2. 数组的每个维度的下标,比如我们要获取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):

  • 参数
  1. 数组对象
  2. 第一维的数组的下标
  3. 第二维开始,每个维度的下标
  • 返回类型

返回类型是jw.asmsupport.operators.array.ArrayLoader,他是asmsupport对获取获取数组元素操作的抽象.

为数组元素赋值

为数组元素赋值采用的方法是jw.asmsupport.block.ProgramBlock的:

public final ArrayStorer arrayStore(IVariable arrayReference, Parameterized value, Parameterized dim, Parameterized... dims):

  • 参数
  1. 数组对象
  2. 为数组元素赋予的值
  3. 第一维的数组的下标
  4. 第二维开始,每个维度的下标
  • 返回类型

返回类型是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);
    }
}

你可能感兴趣的:(ASMSupport教程4.11 生成数组操作)