可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Using Java Generics, I tried to implement a generic console input method.
public static <T> T readFromInput(String message, Class<?> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return (T) Integer.valueOf(scanner.nextInt());
if(c == String.class)
return (T) scanner.nextLine();
if(c == Double.class)
return (T) Double.valueOf(scanner.nextDouble());
if(c == Float.class)
return (T) Float.valueOf(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
I'm having a warning "Type safety: Unchecked cast from Integer to T". Aside from @SuppressWarnings, is it possible to avoid this warning?
Are there better ways to implement my method? Thanks in advance
回答1:
You can use the Class#cast
method instead, but should leave some comments, because even though cast
does not create a warning, it can throw a ClassCastException at runtime if the cast is not possible.
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
// the next cast to Integer is safe
return c.cast(Integer.valueOf(scanner.nextInt()));
if(c == String.class)
// the next cast to String is safe
return c.cast(scanner.nextLine());
if(c == Double.class)
// the next cast to Double is safe
return c.cast(Double.valueOf(scanner.nextDouble()));
if(c == Float.class)
// the next cast to Float is safe
return c.cast(Float.valueOf(scanner.nextFloat()));
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
Note that I've changed the method signature slightly - it should be Class<T>
and not Class<?>
to guarantee, that the Class
instance is consistent with the type parameter.
回答2:
Others have shown how you can do it with Class.cast
, but how should you do it?
I suggest readInt
, readString
, readFloat
and readDouble
methods. Also, I suspect Scanner
may buffer, which could lead you into trouble.
回答3:
I think you might be trying to over abstract the problem. What's wrong with just doing this?
Scanner scanner = new Scanner(System.in);
System.out.println("Give me a boolean:");
boolean bool = scanner.nextBoolean();
System.out.println("Give me an integer:");
int integer = scanner.nextInt();
No cast required and you still have to handle the exception either way........
Remember KISS, "Keep It Simple Stupid"...
回答4:
Do it like this:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return c.cast(scanner.nextInt());
if(c == String.class)
return c.cast(scanner.nextLine());
if(c == Double.class)
return c.cast(scanner.nextDouble());
if(c == Float.class)
return c.cast(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
回答5:
Reading from this post,
Java generic function: how to return Generic type
I got rid of my warning:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return c.cast(scanner.nextInt());
if(c == String.class)
return c.cast(scanner.nextLine());
if(c == Double.class)
return c.cast(scanner.nextDouble());
if(c == Float.class)
return c.cast(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
回答6:
There's no general way to avoid "Unchecked cast" warning other than using @SuppressWarnings (unchecked)
annotation.
In particular case you get this warning because there's no warranty that parameter Class<?> c
may be cast to T since Java's generics are checked only in compilation and no checks may be done in runtime.
回答7:
You can do the following:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
System.out.println(message);
Scanner scanner = new Scanner(System.in);
try {
if(c == Integer.class)
return c.cast(scanner.nextInt());
if(c == String.class)
return c.cast(scanner.nextLine());
if(c == Double.class)
return c.cast(scanner.nextDouble());
if(c == Float.class)
return c.cast(scanner.nextFloat());
} catch (InputMismatchException e) {
throw new Exception(e);
}
return null;
}
However, I strongly recommend not throwing Exception. Throw a more specific exception (either the original runtime exception or some appropriate checked exception).
回答8:
You can get rid of the warning by using the concrete class you pass in to cast the object:
public static <T> T readFromInput(String message, Class<T> c) throws Exception{
..
return c.cast(Integer.valueOf(scanner.nextInt()));
..
}
I would tempted in this case to implement multiple readFromInput methods overridden with your desired types, e.g.
public static Float readFromInput(String message, Class c)
public static Integer readFromInput(String message, Class c)
etc.