2

I'm using Eclipse, and it is perfectly happy with the following code:

public interface MessageType
{
    public static final byte   KICK     = 0x01;
    public static final byte   US_PING  = 0x02;
    public static final byte   GOAL_POS = 0x04;
    public static final byte   SHUTDOWN = 0x08;
    public static final byte[] MESSAGES = new byte[] {
        KICK,
        US_PING,
        GOAL_POS,
        SHUTDOWN
    };
}

public class MessageTest implements MessageType
{
    public static void main(String[] args)
    {
        int b = MessageType.MESSAGES.length;    //Not happy
    }
}

However, the platform that I'm running it on crashes at the line marked above. By crash, think an equivalent of a BSOD. Is there anything wrong with my code, or do I need to pursue the developers of the Java VM for my platform?


EDIT:

Ok, thanks for your responses. It turned out to be a bug in the Java VM. To quote the developer, 'gloomyandy',

This is a known problem with interfaces that have a static initializer. It is fixed in the current development builds...

Community
  • 1
  • 1
Eric
  • 95,302
  • 53
  • 242
  • 374
  • which platform are you running this is on, because it seems to run fine on Ubuntu 9.10, with Sun Java 6 – phoenix24 May 09 '10 at 15:01
  • I just ran it on my machine (Java 1.6.0_16) and it didn't complain. I had it print out `b` and it displayed `4`. – Phil May 09 '10 at 15:04
  • It's a rather obscure java subset for a LEGO robotics controller, called LeJOS NXJ. I didn't think to run it on my computer to test! – Eric May 09 '10 at 15:13
  • ( Note that the `MESSAGES` field is not constant. Malicious code could write: `MessageType.MESSAGES[0] = MessageType.SHUTDOWN;`. Instead: Don't abuse interfaces like this. Add a method (in a class) `public static byte[] getMessageCodes() { return MESSAGES.clone(); }`, or better avoid the need to directly expose the information. ) – Tom Hawtin - tackline May 09 '10 at 15:58
  • Not familiar with this one and don't have an NXJ to test against, but it compiles with LeJos 0.85b on OS X, and runs with `nxjpc`. From the readme, I assume you've done the flash step; do you get anything useful from `nxj --debug --verbose` or `nxjconsole`? – Alex Poole May 09 '10 at 16:07
  • @Alex: I get a `Data Abort` displayed on the NXT brick's LCD. The information it gave me wasn't very transparent. – Eric May 09 '10 at 16:19

4 Answers4

3

I don't see any problem with this code, other than that if you are using Java5 or above, you would be better off using an enum:

public enum MessageType
{
    KICK     (0x01),
    US_PING  (0x02),
    GOAL_POS (0x04),
    SHUTDOWN (0x08);

    private byte value;
    MessageType(byte value) { this.value = value; }
    byte getValue() { return value; }
}

public class MessageTest
{
    public static void main(String[] args)
    {
        int b = MessageType.values().length;    //Should be happy :-)
    }
}

Update: to recreate the enum value from its byte representation, you need to supplement MessageType with the following (adapted from Effective Java, 2nd Ed. Item 31):

private static final Map<Byte, MessageType> byteToEnum = new HashMap<Byte, MessageType>();

static { // Initialize map from byte value to enum constant
  for (MessageType type : values())
    byteToEnum.put(type.getValue(), type);
}

// Returns MessageType for byte, or null if byte is invalid
public static MessageType fromByte(Byte byteValue) {
  return byteToEnum.get(byteValue);
}
Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • That was what I intended to do the first time. However, the message type constance is being sent down a DataOutputStream to a second controller, so I need a way to recreate the enum from the byte at the other end (if that makes sense). – Eric May 09 '10 at 16:06
  • Ok, that would do the trick. However, it gets to the point where a numerical constant is just easier. Or it would do if the "numerical constant" didn't error. – Eric May 09 '10 at 19:09
  • @Eric, OTOH with enums you can also easily implement a polymorphic "loader" method to recreate the whole message from raw bytes. To me, that tilts the preference towards enums - but it's a style question and of course you may have different preferences. – Péter Török May 10 '10 at 08:19
1

Seems reasonable...

What if you take the "implements MessageType" off of your class, does it still crash?

bwawok
  • 14,898
  • 7
  • 32
  • 43
  • Nicely diagnosed. However, that created an even stranger behaviour: I got a `NoSuchMethodError` Exception thrown in the main method. – Eric May 09 '10 at 15:11
  • Hard to say, given that I'm not calling any. – Eric May 10 '10 at 14:48
1

The code itself is perfectly sound. I can compile and run it perfectly fine on my Win7 machine (with Java6); it sounds like you're using some unusual system?

amara
  • 2,216
  • 2
  • 20
  • 28
  • Unfortunately so. I'm using a subset called LeJOS NXJ, from http://lejos.sourceforge.net/. – Eric May 09 '10 at 15:19
0

As everybody told, it should work.
You can try this one:

public class MessageTest implements MessageType
{
    public static void main(String[] args)
    {
        int b = MESSAGES.length;    // no MessageType here
    }
}

(MessageType is not needed since the class is implementing it).
I still would prefer the way Péter Török suggested.

Community
  • 1
  • 1
user85421
  • 28,957
  • 10
  • 64
  • 87