Issue with static code in Android - java

I am building my own class, which is similar to an Enum. Here's the code:
public final class MyClass {
public final static MyClass V1 = new MyClass("v1");
public final static MyClass V2 = new MyClass("v2");
public final static MyClass V3 = new MyClass("v3");
private static Map<String, MyClass> values;
private final String name;
private MyClass(String name) {
this.name = name;
if (values == null)
values = new HashMap<>();
values.put(name,this);
}
public static MyClass[] values() {
return values.values().toArray(new MyClass[values.size()]);
}
public static MyClass valueOf(String key) {
return values.get(key);
}
public String getName() {
return name;
}
public String toString() {
return getName();
}
public static void print() {
Iterator<Map.Entry<String, MyClass>> i = values.entrySet().iterator();
while (i.hasNext()) {
String key = i.next().getKey();
System.out.println(MyClass.class.getSimpleName() + ": " + key + ", " + values.get(key));
}
}
}
I am observing a weird behavior: when I try to invoke MyClass.valueOf("v1") I get null.
I tried to debug and:
the constructor is invoked long before valueOf is invoked (when I invoke print, it gets invoked 3 times)
values gets populated (last constructor invocation, of course, takes the map size to 3, as expected.
when in valueOf, values is empty
====UPDATE
ONLY if I am in debug mode and put a breakpoint in the print method, then I can see the "enum-like-class" values printed in the console. When I do htis, valueOf returns the correct results.
What's happening?

Currently, the best way I found to tackle the issue is to move values definition and initialization before the other static variables.
This way, it gets initialized before the constructors are invoked.
Look at this: Static initializer not called on Activity creation

Related

Implementing same behavior between Enums : this static method cannot hide the instance method from interface

I have a common process with different progress values and step number, depending on the user.
To solve this I've made an interface :
public interface Progress {
int getTotalStepNumber();
int getIndex();
String getMessage();
#Override
String toString();
}
So a step process implementation is like this, litteraly, it is an enumeration of the steps for this process :
public enum ProgressImplementationOfProcessOne implements Progress {
STEP_ONE(1, "Step one message."),
STEP_TWO(2, "Step two message.");
// ... etc. with more steps
/**
* Number of steps for this process.
*/
private static final int STEPS = 2;
private int index;
private String message;
ProgressImplementationOfProcessOne(int index, String message) {
this.index = index;
this.message = message;
}
#Override
public int getTotalStepNumber() { return STEPS; }
#Override
public int getIndex() { return this.index; }
#Override
public String getMessage() { return this.message; }
#Override
public String toString() { return this.message; }
}
But then I thought it would be nice to find the corresponding step from implementation as well, with the method valueOf() of enumerations. So I added the following lines to my interface :
default Progress valueOf(String s) {
for (Progress progress : this.getValues()) {
if (progress.getMessage().equals(s)) {
return progress
}
}
return null;
}
default Progress valueOf(int i) {
for (Progress progress : this.getValues()) {
if (progress.getIndex() == this.getIndex()) {
return progress;
}
}
return null;
}
Since there is no getValues() method in the interface Progress I added the following method to it (thinking "the enum implementation will handle it natively").
default List<Progress> getValues() { return null; }
But I don't understand why I get this error for each ProgressImplementation :
This static method cannot hide the instance method from Progress..
I know I could do it by creating an additional class ProgressStep which replace an enum value, and replace enum by classes with attributes and so on, but since enum can handle multiple values I thought it could have been easier with it.
Simply rename the valueOf to something like valueOfEnum, as valueOf is already specified by java.lang.Enum.
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
The comment on that method contains following section:
Note that for a particular enum type T, the implicitly declared public static T valueOf(String) method on that enum may be used instead of this method to mapfrom a name to the corresponding enum constant. All theconstants of an enum type can be obtained by calling the implicit public static T[] values() method of that type
Emphasis mine
As you can see, valueOf(String s) is already declared on every enum class which in turn is the reason, you can't have it in an interface on any enum

Returning the updated variable passing through private methods

I noticed a scenario today. When we pass a parameter on private methods, the entity will return the revised values but not primitives.
Here is my sample code,
/**
* #author gowthami
*
*/
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
String s = "gowth";
System.out.println("before " + s);
concateMe(s, "ami");
System.out.println("after " + s);
BeanTest bt = new BeanTest();
bt.setId("1");
System.out.println("before");
System.out.println(bt.getId());
System.out.println(bt.getName());
setBeanTestName(bt, "gowthami");
System.out.println("after");
System.out.println(bt.getId());
System.out.println(bt.getName());
String st = new String("gowth");
System.out.println("before " + st);
concateMe(st, "ami");
System.out.println("after " + st);
}
private static void setBeanTestName(BeanTest bt, String string) {
bt.setName(string);
}
private static void concateMe(String s, String string) {
s = s+string;
System.out.println("inside method " + s);
}
}
BeanTest.java
public class BeanTest {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
So the bean is getting updated even though we are not returning it from private method but a string is not. Can someone explain me whats happening on JVM level?
This is because Java follows Call by value, not Call by reference.
When you are passing s you are actually passing value of s, not the actual s. So though you are changing s in concateMe(), it will not change in your main method.
When you are passing bt, then the change is affecting as you are changing the field variable of that reference. But if you change the reference, then there will be no effect. You can add this in main method:
System.out.println("before......");
System.out.println(bt.getId());
System.out.println(bt.getName());
changeBeanTest(bt);
System.out.println("after");
System.out.println(bt.getId());
System.out.println(bt.getName());
Suppose your changeBeanTest is like this:
private static void changeBeanTest(BeanTest tempBeanTest) {
BeanTest bt = new BeanTest();
bt.setId("2");
bt.setName("Trump");
tempBeanTest = bt;
}
run this. There will be no change to bt sent from main().
The Bean is a full object in java passed by reference to the private method so it is the same instance in the main method and the private method.
You are modifying the values of that instance so the changes show up in both places.
The string is more or less a primitive and passed as a copy of the value instead of the exact instance from main. It is a new instance in the private method and so you are modifying a new variable. The changes don't show up in the main method as it is a different entity.
String s = "gowth"; in this line s is pointing to "gowth" from String Pool.When you are calling
private static void concateMe(String s, String string) here String s is different from caller method String s.Here String s scope is local to method ContactMe,But contactMe local String s pointing same "gowth" which is pointed by Caller class String s.After s = s + string;since String is immutable the method local reference String s pointing a different String "gowthami",but caller method String s is still pointing to "gowth".So you are getting this output.
But in case of Bean both the object pointing same String reference,Once we made any change in reference it would be reflected for both object.

Best practice to prevent further instantiation of java classes

I have some class storing keys with important information. No one else is allowed to create a key, since a key relys on static information (like certain directory structures etc.).
public final class KeyConstants
{
private KeyConstants()
{
// could throw an exception to prevent instantiation
}
public static final Key<MyClass> MY_CLASS_DATA = new Key<MyClass>("someId", MyClass.class);
public static class Key<T>
{
public final String ID;
public final Class<T> CLAZZ;
private Key(String id, Class<T> clazz)
{
this.ID = id;
this.CLAZZ = clazz;
}
}
}
This example is simplyfied.
I wanted to test the consequences of a wrong key (exception handling, etc.) and instantiated the class via reflection in a JUnit test case.
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(String.class, Class.class);
c.setAccessible(true);
#SuppressWarnings ("unchecked")
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c.newInstance("wrongId", MyClass.class);
Then I asked myself how could I prevent further instantiation of the key class (i. e. preventing further object creating via reflection)?
enums came to my mind, but they don't work with generics.
public enum Key<T>
{
//... Syntax error, enum declaration cannot have type parameters
}
So how can I keep a set of n instances of a generic class and prevent further instantiation?
So how can I keep a set of n instances of a generic class and prevent
further instantiation?
If you truly want to use this pattern, then no one (including you) should be able to instantiate a Key object. In order to keep a set of n instances in a class with this pattern, you could have a private constructor, a static method for access and a SecurityManager to prevent reflection. And since you want to be able to access the keys as pubic constants, I would try something like this..
public class KeyConstants{
// Here are your n instances for public access
public static final int KEY_1 = 1;
public static final int KEY_2 = 2;
.
.
.
public static final int KEY_N = 'n';
// now you can call this method like this..
// Key mKey = KeyConstants.getKey(KeyConstants.KEY_1);
public static Key getKey(int key){
List keys = Key.getInstances();
switch(key){
case KEY_1:
return keys.get(0);
case KEY_2:
return keys.get(1);
.
.
.
case KEY_N:
return keys.get(n);
default:
// not index out of bounds.. this means
// they didn't use a constant
throw new IllegalArgumentException();
}
}
static class Key<T>{
private static List<Key> instances;
private String ID;
private Class<T> CLAZZ;
private Key(String id, Class<T> clazz){
this.ID = id;
this.CLAZZ = clazz;
}
public static List<Key> getInstances(){
if(instances == null){
instances = new ArrayList<Key>();
//populate instances list
}
return instances;
}
}
}
Use SecurityManager to prevent reflection access.
//attempt to set your own security manager to prevent reflection
try {
System.setSecurityManager(new MySecurityManager());
} catch (SecurityException se) {
}
class MySecurityManager extends SecurityManager {
public void checkPermission(Permission perm) {
if (perm.getName().equals("suppressAccessChecks"))
throw new SecurityException("Invalid Access");
}
}
This will throw a SecurityException anytime someone attempts to access a private variable or field in your class (including access attempts via reflection).
I'm not sure I fully understand your question, but if a private constructor is not sufficient, can you use a more dynamic approach and throw an exception in the constructor after a signal is given? For example:
public static class Key<T>
{
private static boolean isLocked = false;
// Call this method when you want no more keys to be created
public static void lock() { isLocked = true; }
...
private Key(String id, Class<T> clazz)
{
if (isLocked) throw new IllegalStateException("Cannot create instances of Key");
this.ID = id;
this.CLAZZ = clazz;
}
}
Then - and this is the disadvantage - you will have to call Key.lock() once you want to prevent more instances being created.
As you showed in your code to prevent instantiating KeyConstants you can throw some Exception inside private-non-argument constructor.
Harder part is way to block creating KeyConstants.Key constructor from outside of KeyConstants class.
Some wild idea
Maybe create Exception in your constructor and check how its stack trace looks like. When I add this code to constructor
private Key(String id, Class<T> clazz) {
StackTraceElement[] stack = new Exception().getStackTrace();
for (int i=0; i<stack.length; i++){
System.out.println(i+") "+stack[i]);
}
this.ID = id;
this.CLAZZ = clazz;
}
and create instance of Key with reflection like
Constructor<?> c = KeyConstants.Key.class.getDeclaredConstructor(
String.class, Class.class);
c.setAccessible(true);
KeyConstants.Key<MyClass> r = (KeyConstants.Key<MyClass>) c
.newInstance("wrongId", MyClass.class);
I get
0) KeyConstants$Key.<init>(Test.java:38)
1) sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
2) sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
3) sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
4) java.lang.reflect.Constructor.newInstance(Constructor.java:525)
so maybe just if 4th element of stack is java.lang.reflect.Constructor.newInstance throw Exception to prevent executing rest of constructors code like:
if (stack.length>=4 && stack[4].toString().startsWith("java.lang.reflect.Constructor.newInstance")){
throw new RuntimeException("cant create object with reflection");
}
I came across some Multiton patterns recently, where I tried to handle problems with unique enum keys, that gave me the idea of another approach.
The keys can be used for information flow as I intended, or even as keys for typesafe heterogeneous container, where they can perform compile-time casting.
Key-defining class
public class KeyConstants
{
public static final KeysForIntegers SOME_INT_KEY = KeysForIntegers.KEY_2;
public static final KeysForStrings SOME_STRING_KEY = KeysForStrings.KEY_1;
public interface Key<Type>
{
public Class<Type> getType();
}
/* Define methods that classes working with the keys expect from them */
public interface KeyInformation
{
public String getInfo1();
// and so on...
}
public enum KeysForStrings implements Key<String>, KeyInformation
{
KEY_1("someId");
public final String ID;
private KeysForStrings(String id)
{
ID = id;
}
#Override
public String getInfo1()
{
return "Good piece of information on " + ID + ".";
}
#Override
public Class<String> getType()
{
return String.class;
}
}
public enum KeysForIntegers implements Key<Integer>, KeyInformation
{
KEY_2("bla");
public final String ID;
private KeysForIntegers(String id)
{
this.ID = id;
}
#Override
public String getInfo1()
{
return "Some info on " + ID + ".";
}
#Override
public Class<Integer> getType()
{
return Integer.class;
}
}
}
Example key-using class
public class KeyUser
{
public static void main(String[] args)
{
KeysForIntegers k1 = KeyConstants.SOME_INT_KEY;
KeysForStrings k2 = KeyConstants.SOME_STRING_KEY;
processStringKey(k2);
useIntKey(k1);
Integer i = useIntKey(KeyConstants.SOME_INT_KEY);
processStringKey(KeyConstants.SOME_STRING_KEY);
}
/* My methods should just work with my keys */
#SuppressWarnings ("unchecked")
public static <TYPE, KEY extends Enum<KeysForIntegers> & Key<TYPE> & KeyInformation> TYPE useIntKey(KEY k)
{
System.out.println(k.getInfo1());
return (TYPE) new Object();
}
public static <KEY extends Enum<KeysForStrings> & KeyInformation> void processStringKey(KEY k)
{
System.out.println(k.getInfo1());
// process stuff
}
}
I have another approach, you can bound an interface in a way to only be implemented by enum.
With that approach you have a fixed set of instances at compile time.
If you want to add lazy loading, the enums implementing it should be proxies that load the desired object if it is requested. The class or classes that are hidden behind the proxies should only be visible to them, so that they have exclusive access to the constructor.
public class User {
public static <S> S handleKey(FixedInstanceSet<S,?> key) {
return key.getKey();
}
}
interface FixedInstanceSet<S, T extends Enum<T> & FixedInstanceSet<S,T>>
{
public S getKey();
}
enum StringKeys implements FixedInstanceSet<String, StringKeys> {
TOP, DOWN, LEFT, RIGHT;
#Override
public String getKey() { return null; }
}
enum IntKeys implements FixedInstanceSet<Integer, IntKeys > {
TOP, DOWN, LEFT, RIGHT;
#Override
public Integer getKey() { return null; }
}
/*
* Bound mismatch: The type NotWorking is not a valid substitute for the bounded
* parameter <T extends Enum<T> & FixedInstanceSet<S,T>> of the type
* FixedInstanceSet<S,T>
*/
//class NotCompiling implements FixedInstanceSet<String, NotCompiling> {
//
// #Override
// public String getKey() { return null; }
//}
If I understand you correctly, you don't want your class to be instantiated.
You can set the default constructor to private
private Key() throws IllegalStateException //handle default constructor
{
throw new IllegalStateException();
}
This will prevent its improper instantiation.
Update:
added throw IllegalStateException

Using wild cards with static classes in java

The idea I'm going for is that I have a bunch of actions/functions that happen in our program. They're all predefined and separated into categories. So there might be a category for admin actions that then defines a bunch of static codes for actions that are in the admin actions category.
Since the categories and actions are fixed, they're all in static classes.
These static category classes all implement an interface, ICategory:
public static interface ICategory{
int getCateogory();
String getCategoryName();
String getFunctionName(int function);
}
Each of these static classes is added to a static Map:
private static Map<Integer, Class<? extends ICategory>> catMap = new HashMap<Integer, Class<? extends ICategory>>();
Basically there's an integer code associated with each category. What I'm trying to do is just made a human readable string that I can print out when I receive the category and action codes. What I would like to do is something like
ICategory whatever = catMap.get(catNumber);
System.out.println(whatever.getCategoryName());
System.out.println(whatever.getFunctionName(actionCode));
So catMap.get(catNumber) will actually return the proper static class, but I then don't know how I can use that returned class to access these static methods. I can do it with regular instances of a class, just fine, but doing it with static classes has got me puzzled.
Clarification of Problem:
Some Clarification of The problem I'm trying to solve in case you guys have suggestions of better / more intuitive ways to do this:
Basically I'm interpreting commands from some piece of custom hardware at my company. It's a little data collection gizmo that has a bunch of predefined messages/functions that I have to interpret.
These functions are split into various categories: Display, Keypad, Acquisition, etc.
So basically I have a mapping like this:
Display Category: 128
ShowGraph: 01
ShowText: 02
Keypad Category: 129
F1: 01
F2: 02
MenuKey: 03
I'm making a little stream display that prints the stream of commands out in human readable format. So I'd just print out a big list of something like
Got Category Display, Function ShowGraph
Got Category Keypad, Function MenuKey
Normally I'd use a map for this, but what I want is to also use the functions in each category as constants because I'll have to reference them in if-statements and often times send those same categories back to the little gizmo.
For Instance:
sendMessage(Categories.DisplayCategory.getCategoryInt(), Categories.DisplayCategory.SHOW_GRAPH);
More Code as requested:
public class Functions {
public static interface ICategory{
int getCateogory();
String getCategoryName();
String getFunctionName(int function);
}
private static Map<Integer, Class<? extends ICategory>> catMap = new HashMap<Integer, Class<? extends ICategory>>();
public static String getCategoryString(int category) {
Class<? extends ICategory> clazz = catMap.get(category);
System.out.println(catMap.toString());
if(clazz != null){
try{
Method m = clazz.getMethod("getCategoryName", Integer.class);
return (String) m.invoke(0, category);
}catch (Exception e){
return null;
}
}else{
System.out.println("clazz was null");
return null;
}
}
public static class SystemKey implements ICategory{
public static int CATEGORY = 134;
private static Map<Integer, String> fmap = new HashMap<Integer, String>();
#Override
public int getCateogory() {
return CATEGORY;
}
#Override
public String getCategoryName() {
return "SystemKey";
}
#Override
public String getFunctionName(int function) {
return fmap.get(function);
}
}
public static class SystemCat implements ICategory{
public static int CATEGORY = 128;
private static Map<Integer, String> fmap = new HashMap<Integer, String>();
public static final int POWER_UP = 0x01;
public static final int END_OF_TRANSMIT = 0x02;
public static final int CLEAR_TO_SEND = 0x03;
public static final int NET_TEST = 0x05; /*Fom station to ctrlr*/
public static final int NET_OK = 0x06; /*Response to controller*/
public static final int MAIN_MENU = 0x07;
static{
catMap.put(CATEGORY, SystemCat.class);
fmap.put(POWER_UP, "POWER_UP");
fmap.put(END_OF_TRANSMIT, "END_OF_TRANSMIT");
fmap.put(CLEAR_TO_SEND, "CLEAR_TO_SEND");
fmap.put(NET_TEST, "NET_TEST");
fmap.put(NET_OK, "NET_OK");
fmap.put(MAIN_MENU, "MAIN_MENU");
}
#Override
public int getCateogory() {
return CATEGORY;
}
#Override
public String getCategoryName() {
return "System";
}
#Override
public String getFunctionName(int function) {
return fmap.get(function);
}
}
public static class SoftKey implements ICategory{
public static int CATEGORY = 129;
private static Map<Integer, String> fmap = new HashMap<Integer, String>();
public static final int F1 = 0x20;
public static final int F2 = 0x21;
public static final int F3 = 0x22;
public static final int F4 = 0x23;
public static final int F5 = 0x24;
static{
catMap.put(CATEGORY, SoftKey.class);
fmap.put(F1, "F1");
fmap.put(F2, "F2");
fmap.put(F3, "F3");
fmap.put(F4, "F4");
fmap.put(F5, "F5");
#Override
public int getCateogory() {
return CATEGORY;
}
#Override
public String getCategoryName() {
return "SoftKey";
}
#Override
public String getFunctionName(int function) {
return fmap.get(function);
}
}
public static void main (String[] args) throws Exception{
System.out.println(Functions.getCategoryString(128));
}
}
Update
As I suspected, the solution is quite simple. There are different ways to do this, here is one, I seem to remember calling it Registry, back in the days when Patterns were known as Idioms. You are almost there, what you need is following changes:
Change catMap type from Map<String,Class<? extends ICategory> to Map<Integer, ICategory>.
In the static initializers create an object and put it in the map, e.g.
public static class SoftKey implements ICategory{
....
static{
catMap.put(CATEGORY, new SoftKey());
In getCategoryString use the ICategory object in the registry:
ICategory categ = catMap.get(category);
return categ.getCategoyString()
I might have misunderstood the question, but part of it are confusing:
So catMap.get(catNumber) will actually return the proper static class,
By static class I assume you mean that the interfaces are nested inside some class/interface. There is no such thing as a top-level static class in Java. get returns an Object of a static class, not a class.
but I then don't know how I can use that returned class to access these static methods.
The methods you have declared are not static, they are instance methods
I can do it with regular instances of a class, just fine, but doing it with static classes has got me puzzled.
I am puzzled too. You can call instance methods on objects of static class. Can you post a complete code sample?
Assuming you know all the codes in advance, and there aren't 1000s of function values, this would work. The non-uniqueness of the function value codes isn't a problem as long as you don't mind looking through a container to find them (as opposed to a Map).
You could do away with the static maps completely if you don't mind looping through all the enum values all the time. This could be perfectly acceptable if you don't do lookups very often.
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public enum FunctionCategory {
DISPLAY(128, "Display"),
KEYPAD(129, "KeyPad");
// more categories here...
private final int code;
private final String name;
private static Map<Integer, FunctionCategory> categoryMap = new HashMap<>();
static {
for( FunctionCategory c : FunctionCategory.values() ) {
categoryMap.put(c.getCode(), c);
}
}
// For looking up a category from its code
public static FunctionCategory fromCode( int code ) {
return categoryMap.get(code);
}
private FunctionCategory(int code, String name) {
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
public static enum FunctionValue {
// DISPLAY
DISPLAY_GRAPH(DISPLAY, 1, "Graph"),
DISPLAY_TEXT(DISPLAY, 2, "ShowText"),
//KEYPAD
KEYPAD_MENU(KEYPAD, 1, "MenuKey"),
KEYPAD_ENTER(KEYPAD, 2, "EnterKey");
// TODO, others
private static Map<FunctionCategory, Set<FunctionValue>> codeMapping = new EnumMap<>( FunctionCategory.class );
static {
for( FunctionValue fv : FunctionValue.values() ) {
Set<FunctionValue> values = codeMapping.get(fv.getCategory());
if( values == null ) {
values = EnumSet.of(fv);
}
else {
values.add(fv);
}
codeMapping.put(fv.getCategory(), values);
}
}
// First we look up the category, then we just loop over all the values
// within that category. Unless you have lots of values, or really need
// to optimize the lookups, there is no need to do something more complex
public static FunctionValue getFromCodes( int categoryCode, int valueCode ) {
FunctionCategory c = FunctionCategory.fromCode(categoryCode);
if( c != null ) {
Set<FunctionValue> valueSet = codeMapping.get(c);
if( valueSet != null ) {
// Just spin through them, there aren't that many
for( FunctionValue v : valueSet ) {
if( v.getCode() == valueCode ) {
return v;
}
}
}
}
return null;
}
private final FunctionCategory category;
private final int code;
private final String name;
private FunctionValue(FunctionCategory category, int code, String name) {
this.category = category;
this.code = code;
this.name = name;
}
public FunctionCategory getCategory() {
return category;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
}
}

java - an enum question

I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx

Categories