14

I'm attempting to create a Java object array and place the array inside itself at its second index (in order to represent a self-similar fractal with the array), but when I try to access theArray[1][1][0], I get this error:

Main.java:11: error: array required, but Object found.

This is what I've tried so far, and I'm not sure why it's not working:

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Object[] theArray = new Object[2];
        theArray[0] = "This array should contain itself at its second index.";
        theArray[1] = theArray; //Now I'm attempting to put the array into itself.
        System.out.println(theArray[1][1][0]) //Main.java:11: error: array required, but Object found
    }
}

Is it actually possible to put a Java array inside itself, as I'm attempting to do here?

Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • Hint: Read up on the Java `instanceof` operator. You'll need that. – Hot Licks May 21 '13 at 20:48
  • You could use `((Object[])((Object[])theArray[1])[1])[0]` :) – Eng.Fouad May 21 '13 at 21:04
  • @Eng.Fouad That reminds me of some obfuscation I've seen that collapsed everything into `Object[]` instances, resulting in wild series of casts; it definitely is a bit obscure at first sight. – FThompson May 21 '13 at 21:13

4 Answers4

19

theArray[1] is of compile-time type Object (since it comes from an array of Objects).

You need to cast it to Object[] to use it as an array.


The fundamental problem you're encountering is that although an array that contains itself is a perfectly valid object, it isn't a valid type.

You can nest array types arbitrarily deeply – Object[][][][][][][][][][][][][] is a valid type.
However, the "bottom level" of the type can't be an array.

You're trying to create a type which is an array of itself.
Using generics, that would be possible:

class Evil extends ArrayList<Evil> { }
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Right. An element of your `Object[]` array is, to the compiler, just an `Object`. It needs to be cast to `Object[]` using the `(Object[])` cast operation. This causes the compiler to generate a runtime check to assure that it really is an `Object[]` the way you say it is. – Hot Licks May 21 '13 at 20:46
  • @HotLicks: Actually, the runtime check comes from the JITter, I believe. – SLaks May 21 '13 at 20:48
  • `System.out.println((Object[])(theArray[1])[1][0]);` seems to produce the same error. – Anderson Green May 21 '13 at 20:50
  • 1
    @AndersonGreen: That's because `(Object[])(theArray[1])[1]` is also an `Object`. Can you understand why? – SLaks May 21 '13 at 20:51
  • 1
    @AndersonGreen You're just getting the error one array further down now (because it doesn't know that `theArray[1][1]` is an Array...) – Henry Keiter May 21 '13 at 20:51
  • @SLaks - The runtime check is generated by compiler as a `castcheck` bytecode (or is it `checkcast` -- never can remember which). This bytecode produces a runtime check in the JVM interpreter or in JITCed code. If the bytecode is omitted the JVM class verifier will complain of the type mismatch, just as the compiler does. – Hot Licks May 21 '13 at 21:02
  • @HotLicks: I see. I'm used to C#, which will (I think) emit a single `castclass` instruction, which implies a typecheck. – SLaks May 21 '13 at 21:11
  • @SLaks: strictly speaking you can't nest array types arbitrarily deeply: you can't have any more than 255 dimensions. However, that's not a limitation you're likely to bump into unless you're writing some extremely twisted code. – Luke Woodward May 21 '13 at 21:56
  • 1
    @LukeWoodward: I never knew that; thanks! http://ideone.com/IS5yuV http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.11 – SLaks May 21 '13 at 22:00
  • @SLaks: looks like you found the reference before I did. I was spending too long searching around in the JLS when it's actually in the JVM spec. I was just about to post a link to a SO question but you beat me to it. – Luke Woodward May 21 '13 at 22:07
2

You're running into a casting error since you've declared theArray to be an Array of Objects. As a result, you can't promise Java that theArray[1] is an Array--it could be any kind of Object. You'll need to break up your access to do what you want:

Object[] innerArray = (Object[]) theArray[1];
System.out.println(innerArray[0] == theArray[0]); // Always true since innerArray IS theArray
while (true) {
    // Careful! This loops forever!
    // set innerArray = innerArray[1] = theArray = theArray[1] = innerArray... 
    // all of these are the exact same object (but you have to tell Java their type every time)
    innerArray = (Object[]) innerArray[1]; 
    System.out.println(innerArray[0]);
}
Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
  • BTW, that will never (AFAIK?) crash. – SLaks May 21 '13 at 20:49
  • It's the same array; it will never run out. And it won't leak memory or stack, either. – SLaks May 21 '13 at 20:49
  • @SLaks Why would this not run out? Each iteration sets `innerArray` to point to its own second element... unless I've done something stupid without noticing? – Henry Keiter May 21 '13 at 20:52
  • 1
    `innerArray[1]` _is_ `innerArray`. – SLaks May 21 '13 at 20:53
  • `innerArray` takes value of `theArray[1]`; `innerArray` takes value of `innerArray[1]`, which is `theArray[1]`, which is `innerArray`. Thus, the line `innerArray = (Object[]) innerArray[1]` actually does nothing, and the loop is, in fact, infinite. – afsantos May 21 '13 at 20:59
  • Thank you guys; I had misinterpreted the OP's setup. I got distracted by the nested-arrays-casting problem and forgot the array actually contained itself. – Henry Keiter May 21 '13 at 21:04
1

Your code is equivalent to

Object arr = theArray[1];  // arr is an Object here, not an array 

But you could do

Object[] arr = (Object[] ) theArray[1];    // Now it is an array
fastcodejava
  • 39,895
  • 28
  • 133
  • 186
0

This can be done quite easily with ArrayLists:

ArrayList list = new ArrayList();
list.add(list);

So now

System.out.println(list.get(0));

and

System.out.println(((ArrayList)list.get(0)).get(0)); //Casting because .get() returns an Object

Both will output the same thing.

You can take this to an arbitrarily large number of levels, if you want to:

        System.out.println(((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)((ArrayList)list.get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0)).get(0));
FaeFeyFa
  • 1
  • 2