Why does this use of Generics not throw a runtime or compile time exception?
Clash Royale CLAN TAG#URR8PPP
up vote
15
down vote
favorite
I've got a method in a class that has a return type specified by use of a generic.
public class SomeMain
public static void main(String args)
Foo<Integer> foo = new Foo<Integer>();
System.out.println(foo.getFoo()); // Works, prints out "Foo"
public static class Foo<E>
public E getFoo()
return (E) "Foo";
With the generic return type, I assumed the return in the above example would evaluate to:
return (Integer) "Foo"; // Inconvertible types !!!
Instead a String
is returned and printed correctly.
I get a compilation error if I change the call to be:
String fooString = foo.getFoo(); // Compile error, incompatible types found
System.out.println(fooString);
What am I missing to help me understand what's going on here and why the original version didn't result in a compilation error.
java generics
add a comment |Â
up vote
15
down vote
favorite
I've got a method in a class that has a return type specified by use of a generic.
public class SomeMain
public static void main(String args)
Foo<Integer> foo = new Foo<Integer>();
System.out.println(foo.getFoo()); // Works, prints out "Foo"
public static class Foo<E>
public E getFoo()
return (E) "Foo";
With the generic return type, I assumed the return in the above example would evaluate to:
return (Integer) "Foo"; // Inconvertible types !!!
Instead a String
is returned and printed correctly.
I get a compilation error if I change the call to be:
String fooString = foo.getFoo(); // Compile error, incompatible types found
System.out.println(fooString);
What am I missing to help me understand what's going on here and why the original version didn't result in a compilation error.
java generics
add a comment |Â
up vote
15
down vote
favorite
up vote
15
down vote
favorite
I've got a method in a class that has a return type specified by use of a generic.
public class SomeMain
public static void main(String args)
Foo<Integer> foo = new Foo<Integer>();
System.out.println(foo.getFoo()); // Works, prints out "Foo"
public static class Foo<E>
public E getFoo()
return (E) "Foo";
With the generic return type, I assumed the return in the above example would evaluate to:
return (Integer) "Foo"; // Inconvertible types !!!
Instead a String
is returned and printed correctly.
I get a compilation error if I change the call to be:
String fooString = foo.getFoo(); // Compile error, incompatible types found
System.out.println(fooString);
What am I missing to help me understand what's going on here and why the original version didn't result in a compilation error.
java generics
I've got a method in a class that has a return type specified by use of a generic.
public class SomeMain
public static void main(String args)
Foo<Integer> foo = new Foo<Integer>();
System.out.println(foo.getFoo()); // Works, prints out "Foo"
public static class Foo<E>
public E getFoo()
return (E) "Foo";
With the generic return type, I assumed the return in the above example would evaluate to:
return (Integer) "Foo"; // Inconvertible types !!!
Instead a String
is returned and printed correctly.
I get a compilation error if I change the call to be:
String fooString = foo.getFoo(); // Compile error, incompatible types found
System.out.println(fooString);
What am I missing to help me understand what's going on here and why the original version didn't result in a compilation error.
java generics
java generics
edited Sep 22 at 17:15
asked Sep 22 at 16:35
Ray
26k959104
26k959104
add a comment |Â
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
18
down vote
accepted
This is because overload resolution resolved your println
call to println(Object)
, since there is no println(Integer)
.
Keep in mind that Java's generics are erased at runtime. And casts like (E) "Foo"
are removed, and are moved to call site. Sometimes this is not necessary, so things are casted to the right type only when needed.
In other words, no casts are performed inside getFoo
. The language spec supports this:
Section 5.5.2 Checked Casts and Unchecked Casts
The cast is a completely unchecked cast.
No run-time action is performed for such a cast.
After erasure, getFoo
returns Object
. And that gets passed into println(Object)
, which is perfectly fine.
If I call this method and pass foo.getFoo
, I will get an error:
static void f(Integer i)
System.out.println(i);
// ...
f(foo.getFoo()); // ClassCastException
because this time it needs to be casted.
Think that new rule should be introduced inlint
that highlights generics usage with compile-time constants
â Maxim
Sep 22 at 17:01
Interesting. So, theE
in the method declarationpublic E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.
â Ray
Sep 22 at 17:12
add a comment |Â
up vote
2
down vote
System.out.println
does not have an overload that takes Integer
. So this statement:
System.out.println(foo.getFoo());
Is calling System.out.println(Object);
.
To verify that it would otherwise fail, try:
Foo<Integer> foo = new Foo<Integer>();
Integer fooInt = foo.getFoo(); //class cast exception
The following will fail in the same way:
public static void main(String args) throws Exception
Foo<Integer> foo = new Foo<Integer>();
print(foo.getFoo()); //Would also fail with a class cast exception
static void print(Integer in)
System.out.println(in);
And this is failing compilation for obvious reasons:
String fooString = foo.getFoo(); //can't work
foo
is Foo<Integer>
, and foo.getFoo()
returns an Integer
and the compiler can pick this up.
add a comment |Â
up vote
1
down vote
I'd like to add that during the type erasure process, the Java compiler replaces the unbounded type parameter E
with Object
, therefore the Foo
class is actually compiled into:
public static class Foo
public Object getFoo()
return "Foo";
That's why the following code is valid (cast is not needed):
Object obj = foo.getFoo();
System.out.println(obj);
At the same time, the next code snippet produces a compile-time error, as expected:
Foo<Integer> foo = new Foo<Integer>();
String fooString = foo.getFoo(); // you're trying to trick the compiler (unsuccessfully)
^
incompatible types: Integer can not be converted to String
And that's the main responsibility of generics - compile-time checks.
Yet there is another side of the story - execution-time casts. For example, if you write:
Integer value = foo.getFoo();
you get a ClassCastException
thrown at runtime (the Java compiler inserts a checkcast
instruction that examines whether the result of the foo.getFoo()
can be cast to Integer
).
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
18
down vote
accepted
This is because overload resolution resolved your println
call to println(Object)
, since there is no println(Integer)
.
Keep in mind that Java's generics are erased at runtime. And casts like (E) "Foo"
are removed, and are moved to call site. Sometimes this is not necessary, so things are casted to the right type only when needed.
In other words, no casts are performed inside getFoo
. The language spec supports this:
Section 5.5.2 Checked Casts and Unchecked Casts
The cast is a completely unchecked cast.
No run-time action is performed for such a cast.
After erasure, getFoo
returns Object
. And that gets passed into println(Object)
, which is perfectly fine.
If I call this method and pass foo.getFoo
, I will get an error:
static void f(Integer i)
System.out.println(i);
// ...
f(foo.getFoo()); // ClassCastException
because this time it needs to be casted.
Think that new rule should be introduced inlint
that highlights generics usage with compile-time constants
â Maxim
Sep 22 at 17:01
Interesting. So, theE
in the method declarationpublic E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.
â Ray
Sep 22 at 17:12
add a comment |Â
up vote
18
down vote
accepted
This is because overload resolution resolved your println
call to println(Object)
, since there is no println(Integer)
.
Keep in mind that Java's generics are erased at runtime. And casts like (E) "Foo"
are removed, and are moved to call site. Sometimes this is not necessary, so things are casted to the right type only when needed.
In other words, no casts are performed inside getFoo
. The language spec supports this:
Section 5.5.2 Checked Casts and Unchecked Casts
The cast is a completely unchecked cast.
No run-time action is performed for such a cast.
After erasure, getFoo
returns Object
. And that gets passed into println(Object)
, which is perfectly fine.
If I call this method and pass foo.getFoo
, I will get an error:
static void f(Integer i)
System.out.println(i);
// ...
f(foo.getFoo()); // ClassCastException
because this time it needs to be casted.
Think that new rule should be introduced inlint
that highlights generics usage with compile-time constants
â Maxim
Sep 22 at 17:01
Interesting. So, theE
in the method declarationpublic E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.
â Ray
Sep 22 at 17:12
add a comment |Â
up vote
18
down vote
accepted
up vote
18
down vote
accepted
This is because overload resolution resolved your println
call to println(Object)
, since there is no println(Integer)
.
Keep in mind that Java's generics are erased at runtime. And casts like (E) "Foo"
are removed, and are moved to call site. Sometimes this is not necessary, so things are casted to the right type only when needed.
In other words, no casts are performed inside getFoo
. The language spec supports this:
Section 5.5.2 Checked Casts and Unchecked Casts
The cast is a completely unchecked cast.
No run-time action is performed for such a cast.
After erasure, getFoo
returns Object
. And that gets passed into println(Object)
, which is perfectly fine.
If I call this method and pass foo.getFoo
, I will get an error:
static void f(Integer i)
System.out.println(i);
// ...
f(foo.getFoo()); // ClassCastException
because this time it needs to be casted.
This is because overload resolution resolved your println
call to println(Object)
, since there is no println(Integer)
.
Keep in mind that Java's generics are erased at runtime. And casts like (E) "Foo"
are removed, and are moved to call site. Sometimes this is not necessary, so things are casted to the right type only when needed.
In other words, no casts are performed inside getFoo
. The language spec supports this:
Section 5.5.2 Checked Casts and Unchecked Casts
The cast is a completely unchecked cast.
No run-time action is performed for such a cast.
After erasure, getFoo
returns Object
. And that gets passed into println(Object)
, which is perfectly fine.
If I call this method and pass foo.getFoo
, I will get an error:
static void f(Integer i)
System.out.println(i);
// ...
f(foo.getFoo()); // ClassCastException
because this time it needs to be casted.
edited Sep 22 at 17:00
answered Sep 22 at 16:47
Sweeper
56.8k964126
56.8k964126
Think that new rule should be introduced inlint
that highlights generics usage with compile-time constants
â Maxim
Sep 22 at 17:01
Interesting. So, theE
in the method declarationpublic E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.
â Ray
Sep 22 at 17:12
add a comment |Â
Think that new rule should be introduced inlint
that highlights generics usage with compile-time constants
â Maxim
Sep 22 at 17:01
Interesting. So, theE
in the method declarationpublic E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.
â Ray
Sep 22 at 17:12
Think that new rule should be introduced in
lint
that highlights generics usage with compile-time constantsâ Maxim
Sep 22 at 17:01
Think that new rule should be introduced in
lint
that highlights generics usage with compile-time constantsâ Maxim
Sep 22 at 17:01
Interesting. So, the
E
in the method declaration public E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.â Ray
Sep 22 at 17:12
Interesting. So, the
E
in the method declaration public E getFoo()
does nothing at run-time, only acts a compile time checking on uses of the signature, not what's going in inside the method.â Ray
Sep 22 at 17:12
add a comment |Â
up vote
2
down vote
System.out.println
does not have an overload that takes Integer
. So this statement:
System.out.println(foo.getFoo());
Is calling System.out.println(Object);
.
To verify that it would otherwise fail, try:
Foo<Integer> foo = new Foo<Integer>();
Integer fooInt = foo.getFoo(); //class cast exception
The following will fail in the same way:
public static void main(String args) throws Exception
Foo<Integer> foo = new Foo<Integer>();
print(foo.getFoo()); //Would also fail with a class cast exception
static void print(Integer in)
System.out.println(in);
And this is failing compilation for obvious reasons:
String fooString = foo.getFoo(); //can't work
foo
is Foo<Integer>
, and foo.getFoo()
returns an Integer
and the compiler can pick this up.
add a comment |Â
up vote
2
down vote
System.out.println
does not have an overload that takes Integer
. So this statement:
System.out.println(foo.getFoo());
Is calling System.out.println(Object);
.
To verify that it would otherwise fail, try:
Foo<Integer> foo = new Foo<Integer>();
Integer fooInt = foo.getFoo(); //class cast exception
The following will fail in the same way:
public static void main(String args) throws Exception
Foo<Integer> foo = new Foo<Integer>();
print(foo.getFoo()); //Would also fail with a class cast exception
static void print(Integer in)
System.out.println(in);
And this is failing compilation for obvious reasons:
String fooString = foo.getFoo(); //can't work
foo
is Foo<Integer>
, and foo.getFoo()
returns an Integer
and the compiler can pick this up.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
System.out.println
does not have an overload that takes Integer
. So this statement:
System.out.println(foo.getFoo());
Is calling System.out.println(Object);
.
To verify that it would otherwise fail, try:
Foo<Integer> foo = new Foo<Integer>();
Integer fooInt = foo.getFoo(); //class cast exception
The following will fail in the same way:
public static void main(String args) throws Exception
Foo<Integer> foo = new Foo<Integer>();
print(foo.getFoo()); //Would also fail with a class cast exception
static void print(Integer in)
System.out.println(in);
And this is failing compilation for obvious reasons:
String fooString = foo.getFoo(); //can't work
foo
is Foo<Integer>
, and foo.getFoo()
returns an Integer
and the compiler can pick this up.
System.out.println
does not have an overload that takes Integer
. So this statement:
System.out.println(foo.getFoo());
Is calling System.out.println(Object);
.
To verify that it would otherwise fail, try:
Foo<Integer> foo = new Foo<Integer>();
Integer fooInt = foo.getFoo(); //class cast exception
The following will fail in the same way:
public static void main(String args) throws Exception
Foo<Integer> foo = new Foo<Integer>();
print(foo.getFoo()); //Would also fail with a class cast exception
static void print(Integer in)
System.out.println(in);
And this is failing compilation for obvious reasons:
String fooString = foo.getFoo(); //can't work
foo
is Foo<Integer>
, and foo.getFoo()
returns an Integer
and the compiler can pick this up.
answered Sep 22 at 16:46
ernest_k
14.7k41429
14.7k41429
add a comment |Â
add a comment |Â
up vote
1
down vote
I'd like to add that during the type erasure process, the Java compiler replaces the unbounded type parameter E
with Object
, therefore the Foo
class is actually compiled into:
public static class Foo
public Object getFoo()
return "Foo";
That's why the following code is valid (cast is not needed):
Object obj = foo.getFoo();
System.out.println(obj);
At the same time, the next code snippet produces a compile-time error, as expected:
Foo<Integer> foo = new Foo<Integer>();
String fooString = foo.getFoo(); // you're trying to trick the compiler (unsuccessfully)
^
incompatible types: Integer can not be converted to String
And that's the main responsibility of generics - compile-time checks.
Yet there is another side of the story - execution-time casts. For example, if you write:
Integer value = foo.getFoo();
you get a ClassCastException
thrown at runtime (the Java compiler inserts a checkcast
instruction that examines whether the result of the foo.getFoo()
can be cast to Integer
).
add a comment |Â
up vote
1
down vote
I'd like to add that during the type erasure process, the Java compiler replaces the unbounded type parameter E
with Object
, therefore the Foo
class is actually compiled into:
public static class Foo
public Object getFoo()
return "Foo";
That's why the following code is valid (cast is not needed):
Object obj = foo.getFoo();
System.out.println(obj);
At the same time, the next code snippet produces a compile-time error, as expected:
Foo<Integer> foo = new Foo<Integer>();
String fooString = foo.getFoo(); // you're trying to trick the compiler (unsuccessfully)
^
incompatible types: Integer can not be converted to String
And that's the main responsibility of generics - compile-time checks.
Yet there is another side of the story - execution-time casts. For example, if you write:
Integer value = foo.getFoo();
you get a ClassCastException
thrown at runtime (the Java compiler inserts a checkcast
instruction that examines whether the result of the foo.getFoo()
can be cast to Integer
).
add a comment |Â
up vote
1
down vote
up vote
1
down vote
I'd like to add that during the type erasure process, the Java compiler replaces the unbounded type parameter E
with Object
, therefore the Foo
class is actually compiled into:
public static class Foo
public Object getFoo()
return "Foo";
That's why the following code is valid (cast is not needed):
Object obj = foo.getFoo();
System.out.println(obj);
At the same time, the next code snippet produces a compile-time error, as expected:
Foo<Integer> foo = new Foo<Integer>();
String fooString = foo.getFoo(); // you're trying to trick the compiler (unsuccessfully)
^
incompatible types: Integer can not be converted to String
And that's the main responsibility of generics - compile-time checks.
Yet there is another side of the story - execution-time casts. For example, if you write:
Integer value = foo.getFoo();
you get a ClassCastException
thrown at runtime (the Java compiler inserts a checkcast
instruction that examines whether the result of the foo.getFoo()
can be cast to Integer
).
I'd like to add that during the type erasure process, the Java compiler replaces the unbounded type parameter E
with Object
, therefore the Foo
class is actually compiled into:
public static class Foo
public Object getFoo()
return "Foo";
That's why the following code is valid (cast is not needed):
Object obj = foo.getFoo();
System.out.println(obj);
At the same time, the next code snippet produces a compile-time error, as expected:
Foo<Integer> foo = new Foo<Integer>();
String fooString = foo.getFoo(); // you're trying to trick the compiler (unsuccessfully)
^
incompatible types: Integer can not be converted to String
And that's the main responsibility of generics - compile-time checks.
Yet there is another side of the story - execution-time casts. For example, if you write:
Integer value = foo.getFoo();
you get a ClassCastException
thrown at runtime (the Java compiler inserts a checkcast
instruction that examines whether the result of the foo.getFoo()
can be cast to Integer
).
edited Sep 30 at 0:02
answered Sep 22 at 21:03
Oleksandr
7,10533366
7,10533366
add a comment |Â
add a comment |Â
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%2f52458668%2fwhy-does-this-use-of-generics-not-throw-a-runtime-or-compile-time-exception%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