completed the ArrayFactory
This commit is contained in:
parent
7ccf137898
commit
31f2b7c0f5
12 changed files with 198 additions and 164 deletions
|
|
@ -7,6 +7,8 @@ import com.github.shautvast.rusty.Result;
|
|||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import static com.github.shautvast.reflective.java.Java.DOUBLE;
|
||||
|
|
@ -58,7 +60,9 @@ public class InvokerFactory {
|
|||
}
|
||||
// put argument on the stack
|
||||
insns.add(new InsnNode(AALOAD));
|
||||
insns.add(new TypeInsnNode(CHECKCAST, Java.internalName(mapPrimitiveToWrapper(method.getParameters().get(i).getType()).getName())));
|
||||
String type = internalName(mapPrimitiveToWrapper(method.getParameters().get(i).getType()).getName());
|
||||
System.out.println("--" + type);
|
||||
insns.add(new TypeInsnNode(CHECKCAST, type));
|
||||
unwrapPrimitive(method.getParameters().get(i), insns);
|
||||
}
|
||||
// call the method
|
||||
|
|
@ -76,11 +80,11 @@ public class InvokerFactory {
|
|||
classNode.accept(classWriter);
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
|
||||
// try (FileOutputStream out = new FileOutputStream("C"+method.getName() + ".class")) {
|
||||
// out.write(byteArray);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
try (FileOutputStream out = new FileOutputStream(method.getMetaClass().getName() + "_" + method.getName() + ".class")) {
|
||||
out.write(byteArray);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// load it into the JVM
|
||||
ByteClassLoader.INSTANCE.addClass(className, byteArray);
|
||||
|
|
@ -160,6 +164,7 @@ public class InvokerFactory {
|
|||
}
|
||||
|
||||
private static Class<?> mapPrimitiveToWrapper(Class<?> type) {
|
||||
System.out.println(type);
|
||||
if (type == int.class) {
|
||||
return Integer.class;
|
||||
} else if (type == byte.class) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public class MetaClass {
|
|||
}
|
||||
|
||||
void addField(int access, String name, String descriptor) {
|
||||
fields.put(name, new MetaField(name, access)); //ASM access same as reflect modifiers?
|
||||
fields.put(name, new MetaField(name, access, Java.toClass(descriptor))); //ASM access same as reflect modifiers?
|
||||
}
|
||||
|
||||
public void addMethod(int access, String name, String descriptor) {
|
||||
|
|
@ -62,4 +62,6 @@ public class MetaClass {
|
|||
public String getRawName() {
|
||||
return rawName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ public class MetaField {
|
|||
private final String name;
|
||||
private final int modifiers;
|
||||
|
||||
public MetaField(String name, int modifiers) {
|
||||
private final Class<?> type;
|
||||
|
||||
public MetaField(String name, int modifiers, Class<?> type) {
|
||||
this.name = name;
|
||||
this.modifiers = modifiers;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
|
|
|||
|
|
@ -78,13 +78,13 @@ public class MetaMethod {
|
|||
StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < parms.length(); i++) {
|
||||
String t = Character.toString(parms.charAt(i));
|
||||
if (!"L".equals(t) && buf.length() == 0) {
|
||||
mutableParams.add(new Parameter<>(Java.getClassFromDescriptor(t), t));
|
||||
if (!"[".equals(t) && !"L".equals(t) && buf.length() == 0) {
|
||||
mutableParams.add(new Parameter<>(Java.toClass(t), t));
|
||||
}
|
||||
if (";".equals(t)) {
|
||||
buf.append(t);
|
||||
String desc = buf.toString();
|
||||
mutableParams.add(new Parameter<>(Java.getClassFromDescriptor(desc), correct(desc)));
|
||||
mutableParams.add(new Parameter<>(Java.toClass(desc), correct(desc)));
|
||||
buf = new StringBuilder();
|
||||
} else {
|
||||
buf.append(t);
|
||||
|
|
@ -93,7 +93,7 @@ public class MetaMethod {
|
|||
|
||||
String returnDesc = split[2];
|
||||
this.returnParameter = new Parameter<>(
|
||||
Java.getClassFromDescriptor(returnDesc),
|
||||
Java.toClass(returnDesc),
|
||||
correct(returnDesc));
|
||||
|
||||
return Collections.unmodifiableList(mutableParams);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ public class Parameter<T> {
|
|||
private final String descriptor;
|
||||
|
||||
public Parameter(Class<T> type, String descriptor) {
|
||||
if (type ==null){
|
||||
throw new IllegalArgumentException("Type cannot be null");
|
||||
}
|
||||
this.type = type;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
|
@ -17,10 +20,6 @@ public class Parameter<T> {
|
|||
return type == Void.class;
|
||||
}
|
||||
|
||||
public boolean isPrimitive(){
|
||||
return !descriptor.startsWith("L");
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,70 +6,90 @@ import com.github.shautvast.reflective.java.Java;
|
|||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||
|
||||
/**
|
||||
* Factory class for dynamically creating arrays
|
||||
*/
|
||||
public class ArrayFactory {
|
||||
|
||||
/*
|
||||
should become
|
||||
public static <T> T newArray(Class<T> componentType)
|
||||
or
|
||||
public static <T> T newArray(Class<T> componentType, int... dimensions)
|
||||
private static final ConcurrentMap<String, ArrayCreator> cache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new array of the specified type and dimensions
|
||||
*
|
||||
* @param elementType the array element type
|
||||
* @param dimensions array of ints, ie {10} means 1 dimension, length 10. {10,20} means 2 dimensions, size 10 by 20
|
||||
* @return an object that you can cast to the expected array type
|
||||
*/
|
||||
public static Object newArray(Class<?> componentType, int... dimensions) {
|
||||
return newArray(componentType.getName(), dimensions);
|
||||
public static Object newArray(Class<?> elementType, int... dimensions) {
|
||||
String elementTypeName = Java.internalName(elementType);
|
||||
String syntheticClassName = syntheticClassName(elementTypeName, dimensions);
|
||||
|
||||
return cache.computeIfAbsent(syntheticClassName,
|
||||
k -> createSyntheticArrayCreator(elementTypeName, syntheticClassName, dimensions)).newInstance();
|
||||
}
|
||||
|
||||
public static Object newArray(String componentType, int... dimensions) {
|
||||
ClassNode classNode = ASM.createDefaultClassNode(
|
||||
"ReflectiveCreator" + dimensions.length,
|
||||
private static String syntheticClassName(String elementTypeName, int[] dimensions) {
|
||||
return "RAC" + elementTypeName
|
||||
.replaceAll("[/.\\[;]", "")
|
||||
.toLowerCase() + "L" + dimensions.length;
|
||||
}
|
||||
|
||||
private static ArrayCreator createSyntheticArrayCreator(String componentType, String name, int... dimensions) {
|
||||
ClassNode classNode = createASMClassNode(componentType, name, dimensions);
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
classNode.accept(classWriter);
|
||||
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
|
||||
// try (FileOutputStream out = new FileOutputStream(name + ".class")) {
|
||||
// out.write(byteArray);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
||||
|
||||
try {
|
||||
return (ArrayCreator) (ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassNode createASMClassNode(String componentType, String name, int[] dimensions) {
|
||||
ClassNode classNode = ASM.createDefaultClassNode(name,
|
||||
Java.internalName(ArrayCreator.class));
|
||||
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
||||
"newInstance", "()Ljava/lang/Object;", null, null);
|
||||
classNode.methods.add(methodNode);
|
||||
InsnList insns = methodNode.instructions;
|
||||
|
||||
int localVarIndex = 0;
|
||||
StringBuilder arrayType = new StringBuilder(dimensions.length);
|
||||
String post = "";
|
||||
String pre = "";
|
||||
insns.add(new LdcInsnNode(1));
|
||||
insns.add(new LdcInsnNode(1));
|
||||
insns.add(new LdcInsnNode(1));
|
||||
insns.add(new MultiANewArrayInsnNode("[[[Ljava/lang/String;",3));
|
||||
|
||||
// for (int dim : dimensions) {
|
||||
// insns.add(new LdcInsnNode(dim));
|
||||
// String type = arrayType + pre + Java.internalName(componentType) + post;
|
||||
// insns.add(new TypeInsnNode(ANEWARRAY, type));
|
||||
// insns.add(new VarInsnNode(ASTORE, ++localVarIndex));
|
||||
// arrayType.append("[");
|
||||
// pre = "L";
|
||||
// post = ";";
|
||||
//
|
||||
// }
|
||||
|
||||
// insns.add(new VarInsnNode(ALOAD, localVarIndex));
|
||||
Arrays.stream(dimensions).forEach(d -> insns.add(new LdcInsnNode(d)));
|
||||
insns.add(new MultiANewArrayInsnNode(createArrayType(componentType, dimensions), dimensions.length));
|
||||
insns.add(new InsnNode(ARETURN));
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
classNode.accept(classWriter);
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream("A.class")) {
|
||||
out.write(byteArray);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// load it into the JVM
|
||||
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
||||
try {
|
||||
return ((ArrayCreator) ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance()).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return classNode;
|
||||
}
|
||||
|
||||
private static String createArrayType(String componentType, int[] dimensions) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("[".repeat(dimensions.length));
|
||||
boolean isObject = !componentType.startsWith("[") && componentType.contains("/");
|
||||
if (isObject) {
|
||||
s.append("L");
|
||||
s.append(componentType);
|
||||
} else {
|
||||
s.append(Java.mapPrimitiveOrArrayName(componentType));
|
||||
}
|
||||
if (isObject) {
|
||||
s.append(";");
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
package com.github.shautvast.reflective.array;
|
||||
|
||||
public class Arrays {
|
||||
private Arrays() {
|
||||
}
|
||||
|
||||
public static Object newInstance(Class<?> componentType, int... dimensions)
|
||||
throws IllegalArgumentException, NegativeArraySizeException {
|
||||
return new String[dimensions[1]][2][3];
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String[][][] a = (String[][][])newInstance(String.class, 1, 2, 3);
|
||||
a[0]=new String[1][2];
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ public class ByteClassLoader extends ClassLoader {
|
|||
}
|
||||
|
||||
public void addClass(String name, byte[] bytecode) {
|
||||
Class<?> classDef = defineClass(name, bytecode, 0, bytecode.length);
|
||||
Class<?> classDef = defineClass(null, bytecode, 0, bytecode.length);
|
||||
classes.put(name, classDef);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import org.objectweb.asm.ClassReader;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import static java.lang.reflect.Array.newInstance;
|
||||
|
||||
/*
|
||||
* common utils not for external use
|
||||
*/
|
||||
|
|
@ -107,49 +105,84 @@ public class Java {
|
|||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public static Class<?> getClassFromDescriptor(String descriptor) {
|
||||
int arrayDims = 0;
|
||||
while (descriptor.startsWith("[")) {
|
||||
arrayDims++;
|
||||
descriptor = descriptor.substring(1);
|
||||
} //could be cheaper
|
||||
public static Class<?> toClass(String descriptor) {
|
||||
System.out.println("desc;" + descriptor);
|
||||
try {
|
||||
if (descriptor.length() == 1) {
|
||||
return mapIfPrimitive(descriptor.charAt(0));
|
||||
}
|
||||
if (!descriptor.startsWith("[") && descriptor.endsWith(";")) {
|
||||
descriptor = descriptor.substring(0, descriptor.length() - 1);
|
||||
}
|
||||
int i = 0;
|
||||
while (descriptor.charAt(i) == '[' && i < 256) {
|
||||
i++;
|
||||
}
|
||||
assert i < 256;
|
||||
String dims = descriptor.substring(0, i);
|
||||
String type = descriptor.substring(i);
|
||||
if (i == 0 && type.startsWith("L")) {
|
||||
type = type.substring(1);
|
||||
}
|
||||
type = Java.externalName(type);
|
||||
Class<?> aClass = Class.forName(dims + type);
|
||||
System.out.println(aClass);
|
||||
return aClass;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor.startsWith("L") && descriptor.endsWith(";")) {
|
||||
try {
|
||||
String className = descriptor.substring(1, descriptor.length() - 1).replaceAll("/", ".");
|
||||
Class<?> clazz = Class.forName(className);
|
||||
if (arrayDims > 0) {
|
||||
clazz = newInstance(clazz, new int[arrayDims]).getClass();
|
||||
private static Class<?> mapIfPrimitive(char descriptor) {
|
||||
switch (descriptor) {
|
||||
case 'B':
|
||||
return byte.class;
|
||||
case 'S':
|
||||
return short.class;
|
||||
case 'I':
|
||||
return int.class;
|
||||
case 'J':
|
||||
return long.class;
|
||||
case 'F':
|
||||
return float.class;
|
||||
case 'D':
|
||||
return double.class;
|
||||
case 'C':
|
||||
return char.class;
|
||||
case 'Z':
|
||||
return boolean.class;
|
||||
case 'V':
|
||||
return Void.class;
|
||||
default:
|
||||
System.out.println("desc:" + descriptor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String mapPrimitiveOrArrayName(String type) {
|
||||
switch (type) {
|
||||
case "byte":
|
||||
return "B";
|
||||
case "short":
|
||||
return "S";
|
||||
case "int":
|
||||
return "I";
|
||||
case "long":
|
||||
return "J";
|
||||
case "float":
|
||||
return "F";
|
||||
case "double":
|
||||
return "D";
|
||||
case "char":
|
||||
return "C";
|
||||
case "boolean":
|
||||
return "Z";
|
||||
default:
|
||||
if (type.startsWith("[") || type.contains("/")) {
|
||||
return type;
|
||||
} else {
|
||||
throw new IllegalArgumentException(type + "?");
|
||||
}
|
||||
return clazz;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e); // not supposed to happen
|
||||
}
|
||||
} else {
|
||||
char typeChar = descriptor.charAt(0);
|
||||
boolean isArray = arrayDims != 0;
|
||||
switch (typeChar) {
|
||||
case 'B':
|
||||
return isArray ? newInstance(byte.class, new int[arrayDims]).getClass() : byte.class;
|
||||
case 'C':
|
||||
return isArray ? newInstance(char.class, new int[arrayDims]).getClass() : char.class;
|
||||
case 'D':
|
||||
return isArray ? newInstance(double.class, new int[arrayDims]).getClass() : double.class;
|
||||
case 'F':
|
||||
return isArray ? newInstance(float.class, new int[arrayDims]).getClass() : float.class;
|
||||
case 'I':
|
||||
return isArray ? newInstance(int.class, new int[arrayDims]).getClass() : int.class;
|
||||
case 'J':
|
||||
return isArray ? newInstance(long.class, new int[arrayDims]).getClass() : long.class;
|
||||
case 'S':
|
||||
return isArray ? newInstance(short.class, new int[arrayDims]).getClass() : short.class;
|
||||
case 'Z':
|
||||
return isArray ? newInstance(boolean.class, new int[arrayDims]).getClass() : boolean.class;
|
||||
case 'V':
|
||||
return Void.class;
|
||||
default:
|
||||
throw new RuntimeException(new ClassNotFoundException("unknown descriptor: " + descriptor)); //must not happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package com.github.shautvast.reflective;
|
|||
public class DummyInvoker extends AbstractInvoker {
|
||||
|
||||
public Object invoke(Object instance, Object... arguments) {
|
||||
((ReflectiveTest.Dummy) instance).setIntValue((int)arguments[0]);
|
||||
((ReflectiveTest.Dummy) instance).setByteArrayValue((byte[][])arguments[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class ReflectiveTest {
|
|||
|
||||
@Test
|
||||
void testMethods() {
|
||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
||||
Dummy dummy = getDummy();
|
||||
MetaClass metaDummy = Reflective.getMetaClass(dummy.getClass());
|
||||
assertEquals("com.github.shautvast.reflective.ReflectiveTest$Dummy", metaDummy.getName());
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ public class ReflectiveTest {
|
|||
|
||||
@Test
|
||||
void testInvokeGetter() {
|
||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
||||
Dummy dummy = getDummy();
|
||||
MetaMethod getStringValue = Reflective.getMetaClass(dummy.getClass()).getMethod("getStringValue").orElseGet(Assertions::fail);
|
||||
|
||||
// passing "foo" as the instance is not allowed
|
||||
|
|
@ -60,7 +60,7 @@ public class ReflectiveTest {
|
|||
|
||||
@Test
|
||||
void testInvokeSetters() {
|
||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
||||
Dummy dummy = getDummy();
|
||||
MetaClass metaForClass = Reflective.getMetaClass(dummy.getClass());
|
||||
|
||||
MetaMethod setByte = metaForClass.getMethod("setByteValue").orElseGet(Assertions::fail);
|
||||
|
|
@ -102,7 +102,7 @@ public class ReflectiveTest {
|
|||
|
||||
@Test
|
||||
void testInvocationExceptionHappened() {
|
||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
||||
Dummy dummy = getDummy();
|
||||
MetaClass metaForClass = Reflective.getMetaClass(dummy.getClass());
|
||||
MetaMethod throwEx = metaForClass.getMethod("throwEx").orElseGet(Assertions::fail);
|
||||
|
||||
|
|
@ -110,6 +110,13 @@ public class ReflectiveTest {
|
|||
assertFalse(result.isOk());
|
||||
}
|
||||
|
||||
private static Dummy getDummy() {
|
||||
return new Dummy((byte) 42, (short) 43,
|
||||
44, 45, 46.0F, 47.0,
|
||||
'D', true, "don't panic!",
|
||||
new byte[1][1], new String[]{"Please don't touch that button"});
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
|
|
@ -123,6 +130,8 @@ public class ReflectiveTest {
|
|||
private char charValue;
|
||||
private boolean booleanValue;
|
||||
private String stringValue;
|
||||
private byte[][] byteArrayValue;
|
||||
private String[] stringArrayValue;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
|
@ -135,7 +144,7 @@ public class ReflectiveTest {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String[] privateMethod(){
|
||||
private String[] privateMethod() {
|
||||
return new String[1];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,50 +2,30 @@ package com.github.shautvast.reflective.array;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ArraysTest {
|
||||
|
||||
|
||||
@Test
|
||||
void test1Dim() {
|
||||
Object o = ArrayFactory.newArray(String.class, 1);
|
||||
// assertTrue(o instanceof String[]);
|
||||
assertTrue(o instanceof String[]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test2Dims() {
|
||||
Object o = ArrayFactory.newArray(String.class, 1, 2);
|
||||
// assertTrue(o instanceof String[][]);
|
||||
int[][] ints = (int[][])ArrayFactory.newArray(int[].class, 1);
|
||||
assertEquals(1, ints.length);
|
||||
ints[0] = new int[1]; // will fail if array is not correctly created
|
||||
assertEquals(1, ints[0].length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test3Dims() {
|
||||
String[][][] array = (String[][][]) ArrayFactory.newArray(String[][][].class, 1, 2, 3);
|
||||
assertEquals(1, array.length);
|
||||
array[0] = new String[2][1];
|
||||
array[0][1] = new String[1];
|
||||
String[][][] array = (String[][][]) ArrayFactory.newArray(String.class, 6, 7, 8);
|
||||
assertEquals(6, array.length);
|
||||
assertEquals(7, array[0].length);
|
||||
assertEquals(8, array[0][0].length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test3DimsT() {
|
||||
String[][][] array = new String[1][1][1];
|
||||
assertEquals(1, array.length);
|
||||
array[0] = new String[2][1];
|
||||
|
||||
array[0][0] = new String[1];
|
||||
array[0][1] = new String[1];
|
||||
array[0][0][0]="0,0,0";
|
||||
array[0][1][0]="0,1,0"; // WTF?
|
||||
System.out.println(array[0][1][0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void forName() throws ClassNotFoundException {
|
||||
Class.forName("[Ljava.lang.String;");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue