Why does this use of Generics not throw a runtime or compile time exception?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
15
down vote

favorite
3












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.










share|improve this question



























    up vote
    15
    down vote

    favorite
    3












    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.










    share|improve this question

























      up vote
      15
      down vote

      favorite
      3









      up vote
      15
      down vote

      favorite
      3






      3





      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.










      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Sep 22 at 17:15

























      asked Sep 22 at 16:35









      Ray

      26k959104




      26k959104






















          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.






          share|improve this answer






















          • 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

















          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.






          share|improve this answer



























            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).






            share|improve this answer






















              Your Answer





              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "1"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              convertImagesToLinks: true,
              noModals: false,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













               

              draft saved


              draft discarded


















              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






























              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.






              share|improve this answer






















              • 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














              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.






              share|improve this answer






















              • 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












              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.






              share|improve this answer














              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.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Sep 22 at 17:00

























              answered Sep 22 at 16:47









              Sweeper

              56.8k964126




              56.8k964126











              • 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
















              • 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















              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












              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.






              share|improve this answer
























                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.






                share|improve this answer






















                  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.






                  share|improve this answer












                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Sep 22 at 16:46









                  ernest_k

                  14.7k41429




                  14.7k41429




















                      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).






                      share|improve this answer


























                        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).






                        share|improve this answer
























                          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).






                          share|improve this answer














                          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).







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Sep 30 at 0:02

























                          answered Sep 22 at 21:03









                          Oleksandr

                          7,10533366




                          7,10533366



























                               

                              draft saved


                              draft discarded















































                               


                              draft saved


                              draft discarded














                              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













































































                              Popular posts from this blog

                              How to check contact read email or not when send email to Individual?

                              Displaying single band from multi-band raster using QGIS

                              How many registers does an x86_64 CPU actually have?