Android code - the SharedPreferences class exports different methods for persisting/retrieving different preferences :
@SuppressWarnings(\"unchecked\")
public st
Short answer: no, you can't get rid of the warnings. They're there for a reason.
Longer answer: As you may know, generics in Java are just syntactic sugar plus compile-time checks; pretty much nothing survives to runtime (a process known as "erasure"). This means that the cast to (T) within your method is actually a no-op. It'll turn into a cast to the most specific type that it can be, which in this case is Object. So this:
(T) (Boolean) prefs.whatever()
really turns into this:
(Object) (Boolean) prefs.whatever()
which is of course the same as just:
(Boolean) prefs.whatever()
This can get you into a dangerous situation, which is what the warnings are trying to tell you. Basically, you're losing type safety, and it can end up biting you far away from where the bug actually is (and thus be hard to track down). Imagine the following:
// wherever you see "T" here, think "Object" due to erasure
public void prefsToMap(String key, T defaultValue, Map map) {
T val = retrieve(this.context, key, defaultValue);
map.put(key, val);
}
Map map = new HashMap<>();
prefsToMap("foo", 123, map);
// ... later
Integer val = map.get("foo");
So far so good, and in your case it'll work, because if "foo" is in the prefs, you'll call getInt to get it. But imagine if you had a bug in your retrieve function, such that if( defaultValue instanceof Integer) accidentally returned getDouble() instead of getInt() (with the casting and all that). The compiler won't catch it, since your cast to T is really just a cast to Object, which is always allowed! You won't find out until Integer val = map.get("foo");, which becomes:
Integer val = (Integer) map.get("foo"); // cast automatically inserted by the compiler
This cast could be very far away from where the error really happened -- the getObject call -- making it hard to track down. Javac is trying to protect you from that.
Here's an example of it all put together. In this example, I'll be using a Number instead of a prefs object, just to keep things simple. You can copy-paste this example and try it out as is.
import java.util.*;
public class Test {
@SuppressWarnings("unchecked")
public static T getNumber(Number num, T defaultVal) {
if (num == null)
return defaultVal;
if (defaultVal instanceof Integer)
return (T) (Integer) num.intValue();
if (defaultVal instanceof String)
return (T) num.toString();
if (defaultVal instanceof Long)
return (T) (Double) num.doubleValue(); // oops!
throw new AssertionError(defaultVal.getClass());
}
public static void getInt() {
int val = getNumber(null, 1);
}
public static void getLong() {
long val = getNumber(123, 456L); // This would cause a ClassCastException
}
public static void prefsToMap(Number num, String key, T defaultValue, Map map) {
T val = getNumber(num, defaultValue);
map.put(key, val);
}
public static void main(String[] args) {
Map map = new HashMap();
Long oneTwoThree = 123L;
Long fourFixSix = 456L;
prefsToMap(oneTwoThree, "foo", fourFixSix, map);
System.out.println(map);
Long fromMap = map.get("foo"); // Boom! ClassCastException
System.out.println(fromMap);
}
}
A few things to note:
main). The error happened in prefsToMap, but main paid the cost. If the map were an instance variable, it could be very hard to track where that error was introduced.getNumber is pretty much the same as your retrieve functiondefaultVal is a Long, I get (and cast to T) a double instead of a long. But the type system has no way of catching this bug, which is exactly what the unchecked cast is trying to warn me about (it's warning me that it can't catch any bugs, not that there necessarily are bugs).defaultValue is an int or String, everything will be fine. But if it's a Long, and the num is null, then I'll be returning a Double such when the call site expects a Long.prefsToMap class only casts to T -- which, as mentioned above, is a no-op cast -- it won't cause any cast exceptions. I don't get an exception until the second-to-last line, Long fromMap = map.get("foo").Using javap -c, we can see how some of these look in bytecode. First, let's look at getNumber. Note that the casts to T don't show up as anything:
public static java.lang.Object getNumber(java.lang.Number, java.lang.Object);
Code:
0: aload_0
1: ifnonnull 6
4: aload_1
5: areturn
6: aload_1
7: instanceof #2; //class java/lang/Integer
10: ifeq 21
13: aload_0
14: invokevirtual #3; //Method java/lang/Number.intValue:()I
17: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
20: areturn
21: aload_1
22: instanceof #5; //class java/lang/String
25: ifeq 33
28: aload_0
29: invokevirtual #6; //Method java/lang/Object.toString:()Ljava/lang/String;
32: areturn
33: aload_1
34: instanceof #7; //class java/lang/Long
37: ifeq 48
40: aload_0
41: invokevirtual #8; //Method java/lang/Number.doubleValue:()D
44: invokestatic #9; //Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
47: areturn
48: new #10; //class java/lang/AssertionError
51: dup
52: aload_1
53: invokevirtual #11; //Method java/lang/Object.getClass:()Ljava/lang/Class;
56: invokespecial #12; //Method java/lang/AssertionError."":(Ljava/lang/Object;)V
59: athrow
Next, take a look at getLong. Notice that it casts the result of getNumber to a Long:
public static void getLong();
Code:
0: bipush 123
2: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: ldc2_w #15; //long 456l
8: invokestatic #17; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
11: invokestatic #13; //Method getNumber:(Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
14: checkcast #7; //class java/lang/Long
17: invokevirtual #18; //Method java/lang/Long.longValue:()J
20: lstore_0
21: return
And finally, here's prefsToMap. Notice that since it only deals with the generic T type -- aka Object -- it doesn't do any casting at all.
public static void prefsToMap(java.lang.Number, java.lang.String, java.lang.Object, java.util.Map);
Code:
0: aload_0
1: aload_2
2: invokestatic #13; //Method getNumber:(Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object;
5: astore 4
7: aload_3
8: aload_1
9: aload 4
11: invokeinterface #19, 3; //InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
16: pop
17: return