Home > OS >  Java deep dive - Question about constants and their representation in compiled code
Java deep dive - Question about constants and their representation in compiled code

Time:12-14

i read Josh Bloch's "Effective Java" atm. And i dont understand these phrases: Programs that use int enums are brittle. Because int enums are constant variables [JLS, 4.12.4], their int values are compiled into the clients that use them [JLS, 13.1]. If the value associated with an int enum is changed, its clients must be recompiled. If not, the clients will still run, but their behavior will be incorrect. Mostly checked text. Can somebody explain it for me in other words?

CodePudding user response:

int and other primitives are stored as values and not as references that would be used for a proper enum value. Now imagine you're using an int constant with value 5 somehwere and the compiler decides to inline it, i.e. it replaces the access to the constant with the value.

An an example assume the following line somewhere in client code:

static int x = Constants.intEnum; //intEnum has value 5

If the compiler inlines it, the byte code would basically resemble this:

static int x = 5; //value is resolved at compile time which is ok because it is constant

Now imagine you'd change intEnum to have a value of 7. If you don't also recompile the code above the byte code would still contain the x = 5 equivalent. Only recompilation of the client would cause this to be updated to x = 7 - and knowing and recompiling all clients of a library might not be so easy or even desirable.

On the other hand, access to a proper enum wouldn't be inlined, i.e. the following would still be the same:

static MyEnum x = MyEnum.FIVE; //This would be the same as Constants.intEnum

Now if you'd change your library and replace FIVE with SEVEN and the client wouldn't be recompiled you should get an exception at runtime telling you that enum value FIVE cannot be found.

Also, if your enum would have a value and a getter for it, e.g. int getSomeValue()then the following should also stay the same, i.e. not be inlined (I'd need to confirm this, so if anyone has proof for or against this, please share in the commets):

static int x = MyEnum.THE_VALUE.getSomeValue(); //may return 5 or 7 at runtime

Now the call to getSomeValue() should be resolved at runtime so if you change from 5 to 7 you'd not need to recompile the client.

CodePudding user response:

There are two aspects to this:

  1. The int enums he's writing about are not 'real enums' like Java enums, but only int values that are defined in / matched with int constants.
  • In Java, enums are class-like things. In almost all aspects, you can implement a Java enum just like a class, with minor restrictions (private constructor, no inheritance)
  • You can also use Java's enum variables like you would use Object variables, with the same operators etc
  • The classical 'int enums' that other languages use will usually not be treated like classes/objects, but - in Java terms - primitives. So this gives the whole 'enum' handling a very different aspect from Java
  1. The problem that he describes ("If the value associated with an int enum is changed, its clients must be recompiled. If not, the clients will still run, but their behavior will be incorrect.") still holds true for some situations concerning Java enums.
  • If you try to store those, you usually(wrongfully) reduce their storage value to an int, the ordinal() value. However, if you change the order of enums by adding/removing/reordering enum constants inside the enum class, their respective ordinal() value will also change. If you then restore an enum from data, you load the old ordinal value but will get the wrong enum constant. So you should always have an individual enum ID in your Java enums, or save and restore by the enum constants' names. This is just a Java analogy to what can happen with other languages when updating libraries.
  • In Java you can also run into problems with enums and updating libraries. But it will not use a wrong enum silently, rather throw a runtime error and inform you that the enum you tried to address does not exist anymore.
  •  Tags:  
  • java
  • Related