I have a question. First, I declared a map:
Map<TwoIntClass, Set<Integer>> m = new HashMap<TwoIntClass, Set<开发者_运维百科;Integer>>();
Now, I want to put stuff inside this map, something like
int num = 7;
m.put(new TwoIntClass(5, 3), ?? how to put num inside Set ??);
My question is, how do I put variable num inside Set. Thanks.
Like Jack and others have suggested, you need to instantiate a concrete instance of the Set
interface (like HashSet
), add your int
values in the Set
and then put the Set
into your Map
. However, if you are using a custom class for your Map
's key, I would suggest you implement the equals()
and hashCode()
method of your TwoIntClass
class to be sure that you are not creating duplicate entries inside your Map
. For example, consider this class :
public class TwoIntClass {
private int i1;
private int i2;
public TwoIntClass(int i1, int i2) {
this.i1 = i1;
this.i2 = i2;
}
static public void main(String...args) {
Map<TwoIntClass, Set<Integer>> map = new HashMap<TwoIntClass, Set<Integer>>();
Set<Integer> dataset = new HashSet<Integer>();
dataset.add(1);
dataset.add(2);
TwoIntClass i1 = new TwoIntClass(5, 3);
TwoIntClass i2 = new TwoIntClass(5, 3);
map.put(i1, dataset);
map.put(i2, dataset);
System.out.println( i1.hashCode() + " = " + i2.hashCode() + " == " + i2.equals(i2) + " > map count = " + map.size() );
TwoIntClass i3 = new TwoIntClass(5, 3);
System.out.println("Looking for TwoIntClass(5,3)... " + map.containsKey(i3) );
}
}
The output for executing it is :
1476323068 = 535746438 == false > map count = 2
Looking for TwoIntClass(5,3)... false
As you see, they both are "equal" (i.e. they both are constructed with the same integers), but they are distinct objects with different hash codes, therefore create two entries in the map. This could lead into possible data corruption in your application. Moreover, executing this line : map.get(new TwoIntClass(5,3)).add(3);
will generate a NullPointerException
because the key (it's hash) does not exist in the map. So, you need to implement the equals()
and hashCode()
methods to fix this, so any TwoIntClass
constructed with the same integers will be considered equal. Something like :
@Override
public boolean equals(Object obj) {
if (!(obj instanceof TwoIntClass)) {
return false;
}
TwoIntClass other = (TwoIntClass) obj;
return (other.i1 == this.i1) && (other.i2 == this.i2);
}
@Override
public int hashCode() {
//return TwoIntClass.class.hashCode() | i1 | (i2 << 16);
// better implementation based on the String class
int hash = TwoIntClass.class.hashCode();
hash = (hash * 31) + i1;
hash = (hash * 31) + i2;
return hash;
}
yields a more expected result of
1476323071 = 1476323071 == true > map count = 1
Looking for TwoIntClass(5,3)... true
Of course, this hashCode()
method is over simplistic and you may need to find a yet better construct, but the bottom line is that implementing them is what I would recommend.
Set set = new HashSet();
set.add(2);
set.add(4);
...
m.put(new TwoIntClass(5, 3), set);
Slightly better (from here):
m.put(new TwoIntClass(5, 3), new HashSet(Arrays.asList(1, 2)));
You can modify the set like this:
m.get(new TwoIntClass(5, 3)).add(6);
I'd recommend using a SetMultimap from Guava instead. This saves you from having to think about creating the sets yourself.
SetMultimap<TwoIntClass, Integer> multimap = HashMultimap.create();
TwoIntClass twoInts = new TwoIntClass(5, 3);
int num = 7;
multimap.put(twoInts, num);
Set<Integer> set = multimap.get(twoInts); // set contains 7
multimap.put(twoInts, 8);
multimap.put(twoInts, 9); // set now contains 7, 8 and 9
You have to be sure that the related Set
is instantiated and inserted into the Map
before doing anything. You could use something like
public void safeInsert(TwoIntClass tic, Integer element)
{
if (!map.contains(tic))
map.put(tic, new HashSet<Integer>());
map.get(tic).add(element);
}
Mind that you can't use directly Set
since it's an interface, so choose an actual implementation (eg. HashSet
)
With Java8 every thing become easier:
map.computeIfAbsent(tic, k -> new HashSet<>()).add(element);
You will have to create the set first, add the item, and then put the set in the map. There is no good way to initialize a set inline in Java. (This may change when java 7 comes out.)
int num = 7;
Set<Integer> set = new HashSet<Integer>();
set.add(num);
m.put(new TwoIntClass(5, 3), set);
Each time you want to put something in the set, you need to check if the set already exists, and create the set if it does not. ie:
int num = 7;
TwoIntClass twoInt = new TwoIntClass(5, 3);
Set<Integer> intSet = m.get(twoInt);
if(num == null) {
intSet = new HashSet<Integer>();
intSet.put(twoInt, intSet);
}
intSet.add(num);
There's a perfect abstraction over this in google's guava libraries called SetMultimap that you should consider using, especially if this is a repeated pattern in your code.
int num = 7;
TwoIntClass twoInts = new TwoIntClass(5, 3);
m.put(twoInts, new HashSet<Integer>());
m.get(twoInts).add(num);
精彩评论