R
Roedy Green
I wrote a simple enum-using class and decompiled it. Now all sorts of
things about enum make sense.
to understand this paste this into documents and view them side by
side in your IDE.
Here is the original code -- a enum to track the various flavours of
Windows:
package com.mindprod.htmlmacros;
import java.util.EnumSet;
import java.util.Set;
/**
* enum of possible Windows OSes. May be used freely for any purpose
but military.
* @author Roedy Green copyright 2005 Canadian Mind Products
*/
public enum WindowsOS {
WIN95( "W95", "Windows 95"),
WIN98( "W98", "Windows 98"),
WINME( "Me", "Windows Me"),
WINNT( "NT", "Windows NT" ),
WIN2K( "W2K", "Windows 2000" ),
WINXP( "XP", "Windows XP" ),
WIN2K3("W2K3","Windows 2003");
private String shortName;
private String longName;
private static boolean DEBUGGING = true;
/**
* Enum constant constructor that captures two extra facts about
the enum.
* @param short name for the os e.g. Me
* @param long name of the OS e.g. "Windows XP"
*/
WindowsOS ( String shortName, String longName )
{
this.shortName = shortName;
this.longName = longName;
}
/**
* @return short name
*/
public String getShortName ()
{
return this.shortName;
}
/**
* @return long name
*/
public String getLongName ()
{
return this.longName;
}
/**
* Static method to construct a string mentioning multiple OSes,
* by slashes.
* @param choices, EnumSet of just the oses you want included
* @return a String of the form "Windows 95/98/Me"
*/
public static String OSes( EnumSet<WindowsOS> choices )
{
StringBuilder sb = new StringBuilder( 40 );
for ( WindowsOS o : choices )
{
sb.append( '/' );
sb.append( o.shortName );
}
if ( sb.length() == 0 )
{
return "";
}
else
{
// chop lead / and prepend "windows "
return "Windows " + sb.toString().substring( 1 );
}
}
/**
* test harness
*
* @param args not used
*/
public static void main ( String[] args )
{
if ( DEBUGGING )
{
// You don't use a constructor to create EnumSet objects.
EnumSet<WindowsOS> justThese = EnumSet.of( WIN2K, WINXP,
WINME );
// prints "Windows Me/W2K/XP"
// note they come out in proper order.
System.out.println( WindowsOS.OSes ( justThese ) );
}
}
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is the decomiled code, showing what actually makes it into byte
code.
package com.mindprod.htmlmacros;
import java.io.PrintStream;
import java.util.EnumSet;
import java.util.Iterator;
public final class WindowsOS extends Enum
{
public static final WindowsOS[] values()
{
return (WindowsOS[])$VALUES.clone();
}
public static WindowsOS valueOf(String s)
{
return
(WindowsOS)Enum.valueOf(com/mindprod/htmlmacros/WindowsOS, s);
}
private WindowsOS(String s, int i, String s1, String s2)
{
super(s, i);
shortName = s1;
longName = s2;
}
public String getShortName()
{
return shortName;
}
public String getLongName()
{
return longName;
}
public static String OSes(EnumSet enumset)
{
StringBuilder stringbuilder = new StringBuilder(40);
WindowsOS windowsos;
for(Iterator iterator = enumset.iterator();
iterator.hasNext(); stringbuilder.append(windowsos.shortName))
{
windowsos = (WindowsOS)iterator.next();
stringbuilder.append('/');
}
if(stringbuilder.length() == 0)
return "";
else
return (new StringBuilder()).append("Windows
").append(stringbuilder.toString().substring(1)).toString();
}
public static void main(String args[])
{
if(DEBUGGING)
{
EnumSet enumset = EnumSet.of(WIN2K, WINXP, WINME);
System.out.println(OSes(enumset));
}
}
public static final WindowsOS WIN95;
public static final WindowsOS WIN98;
public static final WindowsOS WINME;
public static final WindowsOS WINNT;
public static final WindowsOS WIN2K;
public static final WindowsOS WINXP;
public static final WindowsOS WIN2K3;
private String shortName;
private String longName;
private static boolean DEBUGGING = true;
private static final WindowsOS $VALUES[];
static
{
WIN95 = new WindowsOS("WIN95", 0, "W95", "Windows 95");
WIN98 = new WindowsOS("WIN98", 1, "W98", "Windows 98");
WINME = new WindowsOS("WINME", 2, "Me", "Windows Me");
WINNT = new WindowsOS("WINNT", 3, "NT", "Windows NT");
WIN2K = new WindowsOS("WIN2K", 4, "W2K", "Windows 2000");
WINXP = new WindowsOS("WINXP", 5, "XP", "Windows XP");
WIN2K3 = new WindowsOS("WIN2K3", 6, "W2K3", "Windows 2003");
$VALUES = (new WindowsOS[] {
WIN95, WIN98, WINME, WINNT, WIN2K, WINXP, WIN2K3
});
}
}
Note how java generates you some methods in the same class!
It composes you a values and a valueOf method that does not need a
Class parameter.
it makes your constructor private.
I generates two extra secret fields to your constructor, the enum name
and the ordinal. This mean the enum constants don't have to count
themselves or register themselves. That is all done at compile time.
It creates static finals for each enum constant an the code to
initialise them using your constructors.
It creates a constant array of enum objects, one of each flavour
called $VALUES[] to use in the values method. IT can also be used by
the name method to convert
In this case no enum constant had any of its own fields or methods.
Note the true enum class is hard coded in all over the place. This is
no object-type erasure crap.
The $VALUE array could have been used by methods like
first, last, count, ordinalToEnum, but I have not found any trace of
such methods. You can't get at the $VALUES without patching byte code
since that is not a legal java identifier. So I guess every time you
wan that information you need to do a values() to clone the array just
to find out how long it is, or to index it in a read only way to
convert ordinal back to enum.
Note that the generic EnumSet handles all enums. There is no
corresponding customised code generated for the EnumSet.
It is not obvious from this code, but the bit masks used in EnumSet
computations are not built into the enum constants. They are generated
from the ordinal number as needed on the fly with shifting and
masking.
It is also not obvious from this code, but EnumSet.of figures out the
class of the enums by looking up the class of the first parameter.
There is NOT an EnumSet class generated for each Enum class.
--
Bush crime family lost/embezzled $3 trillion from Pentagon.
Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video.
http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green.
See http://mindprod.com/iraq.html photos of Bush's war crimes
things about enum make sense.
to understand this paste this into documents and view them side by
side in your IDE.
Here is the original code -- a enum to track the various flavours of
Windows:
package com.mindprod.htmlmacros;
import java.util.EnumSet;
import java.util.Set;
/**
* enum of possible Windows OSes. May be used freely for any purpose
but military.
* @author Roedy Green copyright 2005 Canadian Mind Products
*/
public enum WindowsOS {
WIN95( "W95", "Windows 95"),
WIN98( "W98", "Windows 98"),
WINME( "Me", "Windows Me"),
WINNT( "NT", "Windows NT" ),
WIN2K( "W2K", "Windows 2000" ),
WINXP( "XP", "Windows XP" ),
WIN2K3("W2K3","Windows 2003");
private String shortName;
private String longName;
private static boolean DEBUGGING = true;
/**
* Enum constant constructor that captures two extra facts about
the enum.
* @param short name for the os e.g. Me
* @param long name of the OS e.g. "Windows XP"
*/
WindowsOS ( String shortName, String longName )
{
this.shortName = shortName;
this.longName = longName;
}
/**
* @return short name
*/
public String getShortName ()
{
return this.shortName;
}
/**
* @return long name
*/
public String getLongName ()
{
return this.longName;
}
/**
* Static method to construct a string mentioning multiple OSes,
* by slashes.
* @param choices, EnumSet of just the oses you want included
* @return a String of the form "Windows 95/98/Me"
*/
public static String OSes( EnumSet<WindowsOS> choices )
{
StringBuilder sb = new StringBuilder( 40 );
for ( WindowsOS o : choices )
{
sb.append( '/' );
sb.append( o.shortName );
}
if ( sb.length() == 0 )
{
return "";
}
else
{
// chop lead / and prepend "windows "
return "Windows " + sb.toString().substring( 1 );
}
}
/**
* test harness
*
* @param args not used
*/
public static void main ( String[] args )
{
if ( DEBUGGING )
{
// You don't use a constructor to create EnumSet objects.
EnumSet<WindowsOS> justThese = EnumSet.of( WIN2K, WINXP,
WINME );
// prints "Windows Me/W2K/XP"
// note they come out in proper order.
System.out.println( WindowsOS.OSes ( justThese ) );
}
}
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is the decomiled code, showing what actually makes it into byte
code.
package com.mindprod.htmlmacros;
import java.io.PrintStream;
import java.util.EnumSet;
import java.util.Iterator;
public final class WindowsOS extends Enum
{
public static final WindowsOS[] values()
{
return (WindowsOS[])$VALUES.clone();
}
public static WindowsOS valueOf(String s)
{
return
(WindowsOS)Enum.valueOf(com/mindprod/htmlmacros/WindowsOS, s);
}
private WindowsOS(String s, int i, String s1, String s2)
{
super(s, i);
shortName = s1;
longName = s2;
}
public String getShortName()
{
return shortName;
}
public String getLongName()
{
return longName;
}
public static String OSes(EnumSet enumset)
{
StringBuilder stringbuilder = new StringBuilder(40);
WindowsOS windowsos;
for(Iterator iterator = enumset.iterator();
iterator.hasNext(); stringbuilder.append(windowsos.shortName))
{
windowsos = (WindowsOS)iterator.next();
stringbuilder.append('/');
}
if(stringbuilder.length() == 0)
return "";
else
return (new StringBuilder()).append("Windows
").append(stringbuilder.toString().substring(1)).toString();
}
public static void main(String args[])
{
if(DEBUGGING)
{
EnumSet enumset = EnumSet.of(WIN2K, WINXP, WINME);
System.out.println(OSes(enumset));
}
}
public static final WindowsOS WIN95;
public static final WindowsOS WIN98;
public static final WindowsOS WINME;
public static final WindowsOS WINNT;
public static final WindowsOS WIN2K;
public static final WindowsOS WINXP;
public static final WindowsOS WIN2K3;
private String shortName;
private String longName;
private static boolean DEBUGGING = true;
private static final WindowsOS $VALUES[];
static
{
WIN95 = new WindowsOS("WIN95", 0, "W95", "Windows 95");
WIN98 = new WindowsOS("WIN98", 1, "W98", "Windows 98");
WINME = new WindowsOS("WINME", 2, "Me", "Windows Me");
WINNT = new WindowsOS("WINNT", 3, "NT", "Windows NT");
WIN2K = new WindowsOS("WIN2K", 4, "W2K", "Windows 2000");
WINXP = new WindowsOS("WINXP", 5, "XP", "Windows XP");
WIN2K3 = new WindowsOS("WIN2K3", 6, "W2K3", "Windows 2003");
$VALUES = (new WindowsOS[] {
WIN95, WIN98, WINME, WINNT, WIN2K, WINXP, WIN2K3
});
}
}
Note how java generates you some methods in the same class!
It composes you a values and a valueOf method that does not need a
Class parameter.
it makes your constructor private.
I generates two extra secret fields to your constructor, the enum name
and the ordinal. This mean the enum constants don't have to count
themselves or register themselves. That is all done at compile time.
It creates static finals for each enum constant an the code to
initialise them using your constructors.
It creates a constant array of enum objects, one of each flavour
called $VALUES[] to use in the values method. IT can also be used by
the name method to convert
In this case no enum constant had any of its own fields or methods.
Note the true enum class is hard coded in all over the place. This is
no object-type erasure crap.
The $VALUE array could have been used by methods like
first, last, count, ordinalToEnum, but I have not found any trace of
such methods. You can't get at the $VALUES without patching byte code
since that is not a legal java identifier. So I guess every time you
wan that information you need to do a values() to clone the array just
to find out how long it is, or to index it in a read only way to
convert ordinal back to enum.
Note that the generic EnumSet handles all enums. There is no
corresponding customised code generated for the EnumSet.
It is not obvious from this code, but the bit masks used in EnumSet
computations are not built into the enum constants. They are generated
from the ordinal number as needed on the fly with shifting and
masking.
It is also not obvious from this code, but EnumSet.of figures out the
class of the enums by looking up the class of the first parameter.
There is NOT an EnumSet class generated for each Enum class.
--
Bush crime family lost/embezzled $3 trillion from Pentagon.
Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video.
http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green.
See http://mindprod.com/iraq.html photos of Bush's war crimes