why does Java let you cast to a collection?

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











up vote
10
down vote

favorite
1












I have a simple foo class and I am casting to a collection interface (either Map or List). No compiler error.



public class Foo 

public List<String> getCollectionCast()
return (List<String>) this; //no compiler error


public Map<String, String> getCollection2Cast()
return (Map<String, String>) this; //no compiler error


public Other getCast()
return (Other)this; //incompatible types, Cannot cast Foo to Other


public static class Other
// Just for casting demo





My question is: Why does the Java compiler not return incompatible types error when I try to cast the Foo class to a collection?



Foo does not implement Collection.
I would expect an incompatible types error, because given the current Foo class signature, this cannot be a Collection.










share|improve this question



















  • 6




    You could write a subclass of Foo that implements List or Map.
    – khelwood
    2 hours ago











  • Yes I know. My question is why java compiler does not show me incompatibles types error, as it shows when I try to cast Foo to Other (as expected)
    – istovatis
    2 hours ago







  • 2




    @istovatis because Other is a class, and a subclass of Foo cannot also extend Other.
    – Andy Turner
    2 hours ago











  • Possible duplicate of Java casting in interfaces (or at least closely related)
    – Hulk
    40 mins ago











  • In the question above there are two classes that implement two interfaces. Here the foo class does not implement any interface. In addition, in the question you provided, compiler complains in an interface cast, but not complaints in the other. Hence, we have to do with two different examples
    – istovatis
    21 mins ago














up vote
10
down vote

favorite
1












I have a simple foo class and I am casting to a collection interface (either Map or List). No compiler error.



public class Foo 

public List<String> getCollectionCast()
return (List<String>) this; //no compiler error


public Map<String, String> getCollection2Cast()
return (Map<String, String>) this; //no compiler error


public Other getCast()
return (Other)this; //incompatible types, Cannot cast Foo to Other


public static class Other
// Just for casting demo





My question is: Why does the Java compiler not return incompatible types error when I try to cast the Foo class to a collection?



Foo does not implement Collection.
I would expect an incompatible types error, because given the current Foo class signature, this cannot be a Collection.










share|improve this question



















  • 6




    You could write a subclass of Foo that implements List or Map.
    – khelwood
    2 hours ago











  • Yes I know. My question is why java compiler does not show me incompatibles types error, as it shows when I try to cast Foo to Other (as expected)
    – istovatis
    2 hours ago







  • 2




    @istovatis because Other is a class, and a subclass of Foo cannot also extend Other.
    – Andy Turner
    2 hours ago











  • Possible duplicate of Java casting in interfaces (or at least closely related)
    – Hulk
    40 mins ago











  • In the question above there are two classes that implement two interfaces. Here the foo class does not implement any interface. In addition, in the question you provided, compiler complains in an interface cast, but not complaints in the other. Hence, we have to do with two different examples
    – istovatis
    21 mins ago












up vote
10
down vote

favorite
1









up vote
10
down vote

favorite
1






1





I have a simple foo class and I am casting to a collection interface (either Map or List). No compiler error.



public class Foo 

public List<String> getCollectionCast()
return (List<String>) this; //no compiler error


public Map<String, String> getCollection2Cast()
return (Map<String, String>) this; //no compiler error


public Other getCast()
return (Other)this; //incompatible types, Cannot cast Foo to Other


public static class Other
// Just for casting demo





My question is: Why does the Java compiler not return incompatible types error when I try to cast the Foo class to a collection?



Foo does not implement Collection.
I would expect an incompatible types error, because given the current Foo class signature, this cannot be a Collection.










share|improve this question















I have a simple foo class and I am casting to a collection interface (either Map or List). No compiler error.



public class Foo 

public List<String> getCollectionCast()
return (List<String>) this; //no compiler error


public Map<String, String> getCollection2Cast()
return (Map<String, String>) this; //no compiler error


public Other getCast()
return (Other)this; //incompatible types, Cannot cast Foo to Other


public static class Other
// Just for casting demo





My question is: Why does the Java compiler not return incompatible types error when I try to cast the Foo class to a collection?



Foo does not implement Collection.
I would expect an incompatible types error, because given the current Foo class signature, this cannot be a Collection.







java collections casting






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 10 mins ago

























asked 3 hours ago









istovatis

804924




804924







  • 6




    You could write a subclass of Foo that implements List or Map.
    – khelwood
    2 hours ago











  • Yes I know. My question is why java compiler does not show me incompatibles types error, as it shows when I try to cast Foo to Other (as expected)
    – istovatis
    2 hours ago







  • 2




    @istovatis because Other is a class, and a subclass of Foo cannot also extend Other.
    – Andy Turner
    2 hours ago











  • Possible duplicate of Java casting in interfaces (or at least closely related)
    – Hulk
    40 mins ago











  • In the question above there are two classes that implement two interfaces. Here the foo class does not implement any interface. In addition, in the question you provided, compiler complains in an interface cast, but not complaints in the other. Hence, we have to do with two different examples
    – istovatis
    21 mins ago












  • 6




    You could write a subclass of Foo that implements List or Map.
    – khelwood
    2 hours ago











  • Yes I know. My question is why java compiler does not show me incompatibles types error, as it shows when I try to cast Foo to Other (as expected)
    – istovatis
    2 hours ago







  • 2




    @istovatis because Other is a class, and a subclass of Foo cannot also extend Other.
    – Andy Turner
    2 hours ago











  • Possible duplicate of Java casting in interfaces (or at least closely related)
    – Hulk
    40 mins ago











  • In the question above there are two classes that implement two interfaces. Here the foo class does not implement any interface. In addition, in the question you provided, compiler complains in an interface cast, but not complaints in the other. Hence, we have to do with two different examples
    – istovatis
    21 mins ago







6




6




You could write a subclass of Foo that implements List or Map.
– khelwood
2 hours ago





You could write a subclass of Foo that implements List or Map.
– khelwood
2 hours ago













Yes I know. My question is why java compiler does not show me incompatibles types error, as it shows when I try to cast Foo to Other (as expected)
– istovatis
2 hours ago





Yes I know. My question is why java compiler does not show me incompatibles types error, as it shows when I try to cast Foo to Other (as expected)
– istovatis
2 hours ago





2




2




@istovatis because Other is a class, and a subclass of Foo cannot also extend Other.
– Andy Turner
2 hours ago





@istovatis because Other is a class, and a subclass of Foo cannot also extend Other.
– Andy Turner
2 hours ago













Possible duplicate of Java casting in interfaces (or at least closely related)
– Hulk
40 mins ago





Possible duplicate of Java casting in interfaces (or at least closely related)
– Hulk
40 mins ago













In the question above there are two classes that implement two interfaces. Here the foo class does not implement any interface. In addition, in the question you provided, compiler complains in an interface cast, but not complaints in the other. Hence, we have to do with two different examples
– istovatis
21 mins ago




In the question above there are two classes that implement two interfaces. Here the foo class does not implement any interface. In addition, in the question you provided, compiler complains in an interface cast, but not complaints in the other. Hence, we have to do with two different examples
– istovatis
21 mins ago












2 Answers
2






active

oldest

votes

















up vote
15
down vote













It's not because they're collection classes, it's because they're interfaces. Foo doesn't implement them, but subclasses of it could. So it's not a compile-time error, since those methods may be valid for subclasses. At runtime, if this isn't of a class that implements those interfaces, naturally it's a runtime error.



If you change List<String> to ArrayList<String>, you'll get a compiler-time error for that, too, since a Foo subclass could implement List, but can't extend ArrayList (since Foo doesn't). Similarly, if you make Foo final, the compiler will give you an error for your interface casts because it knows they can never be true (since Foo can't have subclasses, and doesn't implement those interfaces).






share|improve this answer





























    up vote
    8
    down vote













    The compiler doesn't prevent code from casting a type to an interface, unless it can establish for sure that the relationship is impossible.



    If the target type is an interface, then it makes sense because a class extending Foo can implement Map<String, String>. However, note that this only works as Foo is not final. If you declared your class with final class Foo, that cast would not work.



    If the target type is a class, then in this case it would simply fail (try (HashMap<String, String>) this), because the compiler knows for certain that the relationship between Foo and HashMap is impossible.



    As a reference this rules are described in JLS-5.5.1 (T = target type - Map<String, String>, S = source type - Foo)




    If T [target type] is an interface type:



    • If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

      Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).


    • If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.




    Note the bold-italic comment in the quoted text.






    share|improve this answer


















    • 1




      Indeed, cast is not permitted even though for interfaces when the class is turned into final
      – istovatis
      2 hours ago










    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%2f52698154%2fwhy-does-java-let-you-cast-to-a-collection%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    15
    down vote













    It's not because they're collection classes, it's because they're interfaces. Foo doesn't implement them, but subclasses of it could. So it's not a compile-time error, since those methods may be valid for subclasses. At runtime, if this isn't of a class that implements those interfaces, naturally it's a runtime error.



    If you change List<String> to ArrayList<String>, you'll get a compiler-time error for that, too, since a Foo subclass could implement List, but can't extend ArrayList (since Foo doesn't). Similarly, if you make Foo final, the compiler will give you an error for your interface casts because it knows they can never be true (since Foo can't have subclasses, and doesn't implement those interfaces).






    share|improve this answer


























      up vote
      15
      down vote













      It's not because they're collection classes, it's because they're interfaces. Foo doesn't implement them, but subclasses of it could. So it's not a compile-time error, since those methods may be valid for subclasses. At runtime, if this isn't of a class that implements those interfaces, naturally it's a runtime error.



      If you change List<String> to ArrayList<String>, you'll get a compiler-time error for that, too, since a Foo subclass could implement List, but can't extend ArrayList (since Foo doesn't). Similarly, if you make Foo final, the compiler will give you an error for your interface casts because it knows they can never be true (since Foo can't have subclasses, and doesn't implement those interfaces).






      share|improve this answer
























        up vote
        15
        down vote










        up vote
        15
        down vote









        It's not because they're collection classes, it's because they're interfaces. Foo doesn't implement them, but subclasses of it could. So it's not a compile-time error, since those methods may be valid for subclasses. At runtime, if this isn't of a class that implements those interfaces, naturally it's a runtime error.



        If you change List<String> to ArrayList<String>, you'll get a compiler-time error for that, too, since a Foo subclass could implement List, but can't extend ArrayList (since Foo doesn't). Similarly, if you make Foo final, the compiler will give you an error for your interface casts because it knows they can never be true (since Foo can't have subclasses, and doesn't implement those interfaces).






        share|improve this answer














        It's not because they're collection classes, it's because they're interfaces. Foo doesn't implement them, but subclasses of it could. So it's not a compile-time error, since those methods may be valid for subclasses. At runtime, if this isn't of a class that implements those interfaces, naturally it's a runtime error.



        If you change List<String> to ArrayList<String>, you'll get a compiler-time error for that, too, since a Foo subclass could implement List, but can't extend ArrayList (since Foo doesn't). Similarly, if you make Foo final, the compiler will give you an error for your interface casts because it knows they can never be true (since Foo can't have subclasses, and doesn't implement those interfaces).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 2 hours ago

























        answered 2 hours ago









        T.J. Crowder

        658k11311591259




        658k11311591259






















            up vote
            8
            down vote













            The compiler doesn't prevent code from casting a type to an interface, unless it can establish for sure that the relationship is impossible.



            If the target type is an interface, then it makes sense because a class extending Foo can implement Map<String, String>. However, note that this only works as Foo is not final. If you declared your class with final class Foo, that cast would not work.



            If the target type is a class, then in this case it would simply fail (try (HashMap<String, String>) this), because the compiler knows for certain that the relationship between Foo and HashMap is impossible.



            As a reference this rules are described in JLS-5.5.1 (T = target type - Map<String, String>, S = source type - Foo)




            If T [target type] is an interface type:



            • If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

              Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).


            • If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.




            Note the bold-italic comment in the quoted text.






            share|improve this answer


















            • 1




              Indeed, cast is not permitted even though for interfaces when the class is turned into final
              – istovatis
              2 hours ago














            up vote
            8
            down vote













            The compiler doesn't prevent code from casting a type to an interface, unless it can establish for sure that the relationship is impossible.



            If the target type is an interface, then it makes sense because a class extending Foo can implement Map<String, String>. However, note that this only works as Foo is not final. If you declared your class with final class Foo, that cast would not work.



            If the target type is a class, then in this case it would simply fail (try (HashMap<String, String>) this), because the compiler knows for certain that the relationship between Foo and HashMap is impossible.



            As a reference this rules are described in JLS-5.5.1 (T = target type - Map<String, String>, S = source type - Foo)




            If T [target type] is an interface type:



            • If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

              Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).


            • If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.




            Note the bold-italic comment in the quoted text.






            share|improve this answer


















            • 1




              Indeed, cast is not permitted even though for interfaces when the class is turned into final
              – istovatis
              2 hours ago












            up vote
            8
            down vote










            up vote
            8
            down vote









            The compiler doesn't prevent code from casting a type to an interface, unless it can establish for sure that the relationship is impossible.



            If the target type is an interface, then it makes sense because a class extending Foo can implement Map<String, String>. However, note that this only works as Foo is not final. If you declared your class with final class Foo, that cast would not work.



            If the target type is a class, then in this case it would simply fail (try (HashMap<String, String>) this), because the compiler knows for certain that the relationship between Foo and HashMap is impossible.



            As a reference this rules are described in JLS-5.5.1 (T = target type - Map<String, String>, S = source type - Foo)




            If T [target type] is an interface type:



            • If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

              Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).


            • If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.




            Note the bold-italic comment in the quoted text.






            share|improve this answer














            The compiler doesn't prevent code from casting a type to an interface, unless it can establish for sure that the relationship is impossible.



            If the target type is an interface, then it makes sense because a class extending Foo can implement Map<String, String>. However, note that this only works as Foo is not final. If you declared your class with final class Foo, that cast would not work.



            If the target type is a class, then in this case it would simply fail (try (HashMap<String, String>) this), because the compiler knows for certain that the relationship between Foo and HashMap is impossible.



            As a reference this rules are described in JLS-5.5.1 (T = target type - Map<String, String>, S = source type - Foo)




            If T [target type] is an interface type:



            • If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

              Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).


            • If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.




            Note the bold-italic comment in the quoted text.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 2 hours ago

























            answered 2 hours ago









            ernest_k

            15.1k41430




            15.1k41430







            • 1




              Indeed, cast is not permitted even though for interfaces when the class is turned into final
              – istovatis
              2 hours ago












            • 1




              Indeed, cast is not permitted even though for interfaces when the class is turned into final
              – istovatis
              2 hours ago







            1




            1




            Indeed, cast is not permitted even though for interfaces when the class is turned into final
            – istovatis
            2 hours ago




            Indeed, cast is not permitted even though for interfaces when the class is turned into final
            – istovatis
            2 hours ago

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52698154%2fwhy-does-java-let-you-cast-to-a-collection%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            What does second last employer means? [closed]

            List of Gilmore Girls characters

            Confectionery