• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Tim Cooke
  • Jeanne Boyarsky
  • Paul Clapham
Sheriffs:
  • Devaka Cooray
  • Ron McLeod
  • paul wheaton
Saloon Keepers:
  • Tim Moores
  • Piet Souris
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Al Hobbs
  • Frits Walraven
  • Scott Selikoff

Tough generic problem: factory method that returns a list

 
Ranch Hand
Posts: 96
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello all,

Suppose that I have a super class Animal.java and sub-classes Dog.java and Cat.java
How can I write a "factory" method that return a list of Dog or Cat based on the parameter without explicit type case.

For example:


And I think of the factoryMethod signature like that:


However, this code doesn't work.

If I use explicit type cast then it work but that's what I want to avoid:

Can anyone help me?

Thanks a lot.
 
author & internet detective
Posts: 41381
853
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This works. It doesn't use the enum, but keeps it to preserve your method signature:

 
Swerrgy Smith
Ranch Hand
Posts: 96
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Jeanne, it works better than my first version but it seems that I still have to to some kind of type cast in the method if I really want to use the list and add some element. Is there anyway to avoid completely the type cast?



Jeanne Boyarsky wrote:This works. It doesn't use the enum, but keeps it to preserve your method signature:

 
Ranch Hand
Posts: 239
12
Scala IntelliJ IDE Eclipse IDE Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Swerrgy Smith wrote:Thanks Jeanne, it works better than my first version but it seems that I still have to to some kind of type cast in the method if I really want to use the list and add some element. Is there anyway to avoid completely the type cast?



Jeanne Boyarsky wrote:This works. It doesn't use the enum, but keeps it to preserve your method signature:



One way is to leave it without a type parameter...but it compiles with warning: "Note: FactoryMethod1.java uses unchecked or unsafe operations."



 
Marshal
Posts: 76802
366
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Not convinced, I am afraid.
Those if‑elses about type don't look properly object‑oriented to me. Also returning a raw type looks dubious.
 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You can do it with raw types as Scott shows, but this is a bad idea. Raw types only exist for backward compatibility with very old Java versions, where there were no generics. Don't use raw types in new code.

The problem is that type checking is done at compile time but your code wants to decide at runtime what type it's going to return (based on what value is being passed in when the method is called). So the compiler can't check the types, since it's not known at compile time what the method is going to return.

You either have to resort to a cast, or use reflection.
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Swerrgy Smith wrote:Thanks Jeanne, it works better than my first version but it seems that I still have to to some kind of type cast in the method if I really want to use the list and add some element. Is there anyway to avoid completely the type cast?


Simple answer: No - because the statement 'new ArrayList<T>()' is not allowed; so whatever actual type you do create has to be cast to a List<T> in order to satisfy the return type.

Winston

PS: Since you're using an enum, you could put that if...else stuff into a switch statement.
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:Simple answer: No - because the statement 'new ArrayList<T>()' is not allowed...


My apologies. That appears to be wrong (you learn something new every day ).

Indeed, the following code:appears to compile (and run) just fine; so maybe that's an alternative for you.

HIH

Winston
 
Scott Shipp
Ranch Hand
Posts: 239
12
Scala IntelliJ IDE Eclipse IDE Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jesper de Jong wrote:
The problem is that type checking is done at compile time but your code wants to decide at runtime what type it's going to return (based on what value is being passed in when the method is called). So the compiler can't check the types, since it's not known at compile time what the method is going to return.



Expanding the explanation. Hope it helps.

I think the problem might be understood as being that Java does not have covariant generics. Java considers List<Animal> and List<Cat> to be different, unrelated types, even though Animal and Cat themselves have a super-subtype relationship. So you can't expect to do anything with a List<Cat> (or List<Dog>) when a List<Animal> is expected. Can't pass a List<Dog> as a method parameter when a List<Animal> is expected, can't return a List<Cat> from a method with a List<Animal> return type.

And thus you can't do:



nor can you do:



Anyway I don't see how not having to cast to an explicit type would be buying you anything? I think the compiler is forcing this because otherwise you lose type safety. Ultimately this question is asking how to get rid of type safety. For example, what is going to happen when you accidentally do this with the code that has now resulted:

 
Why am I so drawn to cherry pie? I can't seem to stop. Save me tiny ad!
the value of filler advertising in 2021
https://coderanch.com/t/730886/filler-advertising
reply
    Bookmark Topic Watch Topic
  • New Topic