Reputation: 331
I have a singleton class like below :
public enum SingletonClassA {
INSTANCE;
private final Map<Character, Character> characters;
// private constructor
SingletonClassA() {
Map<Character, Character> aCharMap = new HashMap();
aCharMap.put('a', 'e');
aCharMap.put('o', 'u');
// in order to keep short I erased other puts.
characters = aCharMap;
}
public char getInstance(final char letter) {
return characters.get(letter);
}
public boolean containsKey(char letter) {
return characters.containsKey(letter);
}
}
And in order to test that I've create only one single object, even though I call more than once, I created a test case with JUnit :
public class SingletonTest {
@Test
public void TestSingletonObject(){
SingletonClassA instance1 = SingletonClassA.INSTANCE;
SingletonClassA instance2 = SingletonClassA.INSTANCE;
//Passes
Assert.assertSame("2 objects are same", instance1, instance2);
}
@Test
public void TestgetInstance(){
SingletonClassA instance1 = SingletonClassA.INSTANCE;
SingletonClassA instance2 = SingletonClassA.INSTANCE;
// Does not pass
Assert.assertSame(instance1.getInstance('o'), instance2.getInstance('o'));
}
}
The test passes from TestSingletonObject() which says that those 2 objects are exactly the same. But from the second one, TestgetInstance(), it does not pass.
My question is: why? Why it does not pass from the second test. I am thinking that even I call the instance methods it should return true because they belong to the exact same object. Am I missing a point?
Upvotes: 4
Views: 6267
Reputation: 424993
Your code passes all tests. And it should.
Even through assertSame()
causes auto-boxing, the same object is returned for char
values 0-127
(inclusive), because those values are cached.
Here's the source code of Character.valueOf(char c)
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
whose behaviour is confirmed in its javadoc (excerpt):
... This method will always cache values in the range '\u0000' to '\u007F', inclusive ...
which has remained unchanged since its introduction (in version 1.5).
However, if your code and returns values outside the range of 0-127, eg:
aCharMap.put('c', '¢'); // the "cent" char is decimal 155
then a test using it will fail:
Assert.assertSame(instance1.getInstance('c'), instance2.getInstance('c')); // fails
Upvotes: 2
Reputation: 657
This is similar to this question. Your getInstance()
method returns a primitive, but JUnit's Assert.assertSame(Object, Object)
requires 2 objects and will check that their references point to the same object.
Java will use auto-boxing in this case, essentially calling Character.valueOf(char)
in order to provide the correct arguments to the assert method. However, since this will make a separate Character
object for each argument, the assertion will fail.
Try using Assert.assertEquals(Object, Object)
instead. This will use the equals(Object)
method.
Upvotes: 3