Java Generics casts strangely
Clash Royale CLAN TAG#URR8PPP
up vote
10
down vote
favorite
I am using java 8.
I recently came across this:
public class Test
public static void main(String args)
String ss = "" + (Test.<Integer>abc(2));
System.out.println(Test.<Integer>abc(2));
public static <T> T abc(T a)
String s = "adsa";
return (T) s;
This does not throw a java.lang.ClassCastException. Why is that?
I always thought +
and System.out.println
calls toString
. But when I try to do that it throws an Exception as expected.
String sss = (Test.<Integer>abc(2)).toString();
java generics casting
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |Â
up vote
10
down vote
favorite
I am using java 8.
I recently came across this:
public class Test
public static void main(String args)
String ss = "" + (Test.<Integer>abc(2));
System.out.println(Test.<Integer>abc(2));
public static <T> T abc(T a)
String s = "adsa";
return (T) s;
This does not throw a java.lang.ClassCastException. Why is that?
I always thought +
and System.out.println
calls toString
. But when I try to do that it throws an Exception as expected.
String sss = (Test.<Integer>abc(2)).toString();
java generics casting
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
5
Enable all compiler warnings, and you will see the answer: your cast is not “safe.†Meaning, it is not doing what you think it’s doing. Specifically, generics are subject to type erasure, meaning they are only a means of enforcing safety at compile time, not runtime. At runtime, the method doesn’t knowT
isInteger
. The compiler translated(T)
to(Object)
due to the declaration of<T>
.
– VGR
30 mins ago
Possible duplicate of Why does this use of Generics not throw a runtime or compile time exception?
– Oleksandr
51 secs ago
add a comment |Â
up vote
10
down vote
favorite
up vote
10
down vote
favorite
I am using java 8.
I recently came across this:
public class Test
public static void main(String args)
String ss = "" + (Test.<Integer>abc(2));
System.out.println(Test.<Integer>abc(2));
public static <T> T abc(T a)
String s = "adsa";
return (T) s;
This does not throw a java.lang.ClassCastException. Why is that?
I always thought +
and System.out.println
calls toString
. But when I try to do that it throws an Exception as expected.
String sss = (Test.<Integer>abc(2)).toString();
java generics casting
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
I am using java 8.
I recently came across this:
public class Test
public static void main(String args)
String ss = "" + (Test.<Integer>abc(2));
System.out.println(Test.<Integer>abc(2));
public static <T> T abc(T a)
String s = "adsa";
return (T) s;
This does not throw a java.lang.ClassCastException. Why is that?
I always thought +
and System.out.println
calls toString
. But when I try to do that it throws an Exception as expected.
String sss = (Test.<Integer>abc(2)).toString();
java generics casting
java generics casting
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 35 mins ago
zzrv
633
633
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
zzrv is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
5
Enable all compiler warnings, and you will see the answer: your cast is not “safe.†Meaning, it is not doing what you think it’s doing. Specifically, generics are subject to type erasure, meaning they are only a means of enforcing safety at compile time, not runtime. At runtime, the method doesn’t knowT
isInteger
. The compiler translated(T)
to(Object)
due to the declaration of<T>
.
– VGR
30 mins ago
Possible duplicate of Why does this use of Generics not throw a runtime or compile time exception?
– Oleksandr
51 secs ago
add a comment |Â
5
Enable all compiler warnings, and you will see the answer: your cast is not “safe.†Meaning, it is not doing what you think it’s doing. Specifically, generics are subject to type erasure, meaning they are only a means of enforcing safety at compile time, not runtime. At runtime, the method doesn’t knowT
isInteger
. The compiler translated(T)
to(Object)
due to the declaration of<T>
.
– VGR
30 mins ago
Possible duplicate of Why does this use of Generics not throw a runtime or compile time exception?
– Oleksandr
51 secs ago
5
5
Enable all compiler warnings, and you will see the answer: your cast is not “safe.†Meaning, it is not doing what you think it’s doing. Specifically, generics are subject to type erasure, meaning they are only a means of enforcing safety at compile time, not runtime. At runtime, the method doesn’t know
T
is Integer
. The compiler translated (T)
to (Object)
due to the declaration of <T>
.– VGR
30 mins ago
Enable all compiler warnings, and you will see the answer: your cast is not “safe.†Meaning, it is not doing what you think it’s doing. Specifically, generics are subject to type erasure, meaning they are only a means of enforcing safety at compile time, not runtime. At runtime, the method doesn’t know
T
is Integer
. The compiler translated (T)
to (Object)
due to the declaration of <T>
.– VGR
30 mins ago
Possible duplicate of Why does this use of Generics not throw a runtime or compile time exception?
– Oleksandr
51 secs ago
Possible duplicate of Why does this use of Generics not throw a runtime or compile time exception?
– Oleksandr
51 secs ago
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
4
down vote
It doesn't throw a ClassCastException
because all generic type information is stripped from the compiled code (a process called type erasure). Basically, any type parameter is replaced by Object
. That's why the first version works. It's also why the code compiles at all. If you ask the compiler to warn about unchecked or unsafe operations with the -Xlint:unchecked
flag, you'll get a warning about an unchecked cast in the return
statement of abc()
.
With this statement:
String sss = (Test.<Integer>abc(2)).toString();
the story is a bit different. While the type parameter T
is replaced by Object
, the calling code gets translated into byte code that explicitly casts the result to Integer
. It is as if the code were written with a method with signature static Object abc(Object)
and the statement were written:
String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();
That is, not only does the cast inside abc()
go away due to type erasure, a new cast is inserted by the compiler in the calling code. This cast generates a ClassCastException
at run time because the object returned from abc()
is a String
, not an Integer
.
Note that the statement
String ss = "" + (Test.<Integer>abc(2));
doesn't require a cast because the compiler translates it into something that might have been written:
String ss = "" + String.valueOf(Test.<Integer>abc(2));
The compiler is smart enough to recognize that no cast is needed for this code.
add a comment |Â
up vote
3
down vote
Generics disappear at runtime, so a cast to T
is really just a cast to Object
(which the compiler will actually just get rid of), so there's no class cast exception.
abc
is just a method which takes an object and returns an object. StringBuilder.append(Object)
is the method which is called, as can be seen from the bytecode:
...
16: invokestatic #7 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
...
When you do
String sss = (Test.<Integer>abc(2)).toString();
Then the bytecode is
...
4: invokestatic #3 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
7: checkcast #4 // class java/lang/Integer
10: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
...
Your code fails at the checkcast
operation, which was not present before.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
It doesn't throw a ClassCastException
because all generic type information is stripped from the compiled code (a process called type erasure). Basically, any type parameter is replaced by Object
. That's why the first version works. It's also why the code compiles at all. If you ask the compiler to warn about unchecked or unsafe operations with the -Xlint:unchecked
flag, you'll get a warning about an unchecked cast in the return
statement of abc()
.
With this statement:
String sss = (Test.<Integer>abc(2)).toString();
the story is a bit different. While the type parameter T
is replaced by Object
, the calling code gets translated into byte code that explicitly casts the result to Integer
. It is as if the code were written with a method with signature static Object abc(Object)
and the statement were written:
String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();
That is, not only does the cast inside abc()
go away due to type erasure, a new cast is inserted by the compiler in the calling code. This cast generates a ClassCastException
at run time because the object returned from abc()
is a String
, not an Integer
.
Note that the statement
String ss = "" + (Test.<Integer>abc(2));
doesn't require a cast because the compiler translates it into something that might have been written:
String ss = "" + String.valueOf(Test.<Integer>abc(2));
The compiler is smart enough to recognize that no cast is needed for this code.
add a comment |Â
up vote
4
down vote
It doesn't throw a ClassCastException
because all generic type information is stripped from the compiled code (a process called type erasure). Basically, any type parameter is replaced by Object
. That's why the first version works. It's also why the code compiles at all. If you ask the compiler to warn about unchecked or unsafe operations with the -Xlint:unchecked
flag, you'll get a warning about an unchecked cast in the return
statement of abc()
.
With this statement:
String sss = (Test.<Integer>abc(2)).toString();
the story is a bit different. While the type parameter T
is replaced by Object
, the calling code gets translated into byte code that explicitly casts the result to Integer
. It is as if the code were written with a method with signature static Object abc(Object)
and the statement were written:
String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();
That is, not only does the cast inside abc()
go away due to type erasure, a new cast is inserted by the compiler in the calling code. This cast generates a ClassCastException
at run time because the object returned from abc()
is a String
, not an Integer
.
Note that the statement
String ss = "" + (Test.<Integer>abc(2));
doesn't require a cast because the compiler translates it into something that might have been written:
String ss = "" + String.valueOf(Test.<Integer>abc(2));
The compiler is smart enough to recognize that no cast is needed for this code.
add a comment |Â
up vote
4
down vote
up vote
4
down vote
It doesn't throw a ClassCastException
because all generic type information is stripped from the compiled code (a process called type erasure). Basically, any type parameter is replaced by Object
. That's why the first version works. It's also why the code compiles at all. If you ask the compiler to warn about unchecked or unsafe operations with the -Xlint:unchecked
flag, you'll get a warning about an unchecked cast in the return
statement of abc()
.
With this statement:
String sss = (Test.<Integer>abc(2)).toString();
the story is a bit different. While the type parameter T
is replaced by Object
, the calling code gets translated into byte code that explicitly casts the result to Integer
. It is as if the code were written with a method with signature static Object abc(Object)
and the statement were written:
String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();
That is, not only does the cast inside abc()
go away due to type erasure, a new cast is inserted by the compiler in the calling code. This cast generates a ClassCastException
at run time because the object returned from abc()
is a String
, not an Integer
.
Note that the statement
String ss = "" + (Test.<Integer>abc(2));
doesn't require a cast because the compiler translates it into something that might have been written:
String ss = "" + String.valueOf(Test.<Integer>abc(2));
The compiler is smart enough to recognize that no cast is needed for this code.
It doesn't throw a ClassCastException
because all generic type information is stripped from the compiled code (a process called type erasure). Basically, any type parameter is replaced by Object
. That's why the first version works. It's also why the code compiles at all. If you ask the compiler to warn about unchecked or unsafe operations with the -Xlint:unchecked
flag, you'll get a warning about an unchecked cast in the return
statement of abc()
.
With this statement:
String sss = (Test.<Integer>abc(2)).toString();
the story is a bit different. While the type parameter T
is replaced by Object
, the calling code gets translated into byte code that explicitly casts the result to Integer
. It is as if the code were written with a method with signature static Object abc(Object)
and the statement were written:
String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();
That is, not only does the cast inside abc()
go away due to type erasure, a new cast is inserted by the compiler in the calling code. This cast generates a ClassCastException
at run time because the object returned from abc()
is a String
, not an Integer
.
Note that the statement
String ss = "" + (Test.<Integer>abc(2));
doesn't require a cast because the compiler translates it into something that might have been written:
String ss = "" + String.valueOf(Test.<Integer>abc(2));
The compiler is smart enough to recognize that no cast is needed for this code.
edited 13 mins ago
answered 24 mins ago


Ted Hopp
197k40307416
197k40307416
add a comment |Â
add a comment |Â
up vote
3
down vote
Generics disappear at runtime, so a cast to T
is really just a cast to Object
(which the compiler will actually just get rid of), so there's no class cast exception.
abc
is just a method which takes an object and returns an object. StringBuilder.append(Object)
is the method which is called, as can be seen from the bytecode:
...
16: invokestatic #7 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
...
When you do
String sss = (Test.<Integer>abc(2)).toString();
Then the bytecode is
...
4: invokestatic #3 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
7: checkcast #4 // class java/lang/Integer
10: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
...
Your code fails at the checkcast
operation, which was not present before.
add a comment |Â
up vote
3
down vote
Generics disappear at runtime, so a cast to T
is really just a cast to Object
(which the compiler will actually just get rid of), so there's no class cast exception.
abc
is just a method which takes an object and returns an object. StringBuilder.append(Object)
is the method which is called, as can be seen from the bytecode:
...
16: invokestatic #7 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
...
When you do
String sss = (Test.<Integer>abc(2)).toString();
Then the bytecode is
...
4: invokestatic #3 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
7: checkcast #4 // class java/lang/Integer
10: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
...
Your code fails at the checkcast
operation, which was not present before.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Generics disappear at runtime, so a cast to T
is really just a cast to Object
(which the compiler will actually just get rid of), so there's no class cast exception.
abc
is just a method which takes an object and returns an object. StringBuilder.append(Object)
is the method which is called, as can be seen from the bytecode:
...
16: invokestatic #7 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
...
When you do
String sss = (Test.<Integer>abc(2)).toString();
Then the bytecode is
...
4: invokestatic #3 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
7: checkcast #4 // class java/lang/Integer
10: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
...
Your code fails at the checkcast
operation, which was not present before.
Generics disappear at runtime, so a cast to T
is really just a cast to Object
(which the compiler will actually just get rid of), so there's no class cast exception.
abc
is just a method which takes an object and returns an object. StringBuilder.append(Object)
is the method which is called, as can be seen from the bytecode:
...
16: invokestatic #7 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
...
When you do
String sss = (Test.<Integer>abc(2)).toString();
Then the bytecode is
...
4: invokestatic #3 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
7: checkcast #4 // class java/lang/Integer
10: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
...
Your code fails at the checkcast
operation, which was not present before.
edited 4 mins ago
answered 21 mins ago
Michael
17.4k73066
17.4k73066
add a comment |Â
add a comment |Â
zzrv is a new contributor. Be nice, and check out our Code of Conduct.
zzrv is a new contributor. Be nice, and check out our Code of Conduct.
zzrv is a new contributor. Be nice, and check out our Code of Conduct.
zzrv is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53175130%2fjava-generics-casts-strangely%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
5
Enable all compiler warnings, and you will see the answer: your cast is not “safe.†Meaning, it is not doing what you think it’s doing. Specifically, generics are subject to type erasure, meaning they are only a means of enforcing safety at compile time, not runtime. At runtime, the method doesn’t know
T
isInteger
. The compiler translated(T)
to(Object)
due to the declaration of<T>
.– VGR
30 mins ago
Possible duplicate of Why does this use of Generics not throw a runtime or compile time exception?
– Oleksandr
51 secs ago