1

Consider the following example in Java. Where I have a method that takes an object of type Dog(which extends Animal), and need to pass it an object of type Animal. I can downcast explicitly but want to avoid this and keep type safety. Is there a way of going about this using type generics in Java? Thanks!

Edit To clarify what I'm doing: I am trying to refactor away duplicate code (I have the exact same code at the top level, but depending on what type of object is being passed will have very different behaviors in how calculations are done, and what data/methods is available etc.

Downcasting explicitly is a really simple way of doing it, but was trying to avoid that as it's frowned upon in general and I thought there might be a more proper solution using generics.

In short, at compile time, I will know which type of Animal I will have, as I create separate instances of my class for each type of animal. I thought there would be away to pass the type down as I create each instance, and have the compiler understand what type of object it is and do the casting safely for me.

public class Test {
    interface Animal {
        void speak();
    }
    class Cat implements Animal {
        @Override
        public void speak() {}
    }
    static class Dog implements Animal {
        @Override
        public void speak() {}
        public void doDogThing() {}
    }
    static void dogMethod(Dog d) {
        d.doDogThing();
    }
    public static void main(String[] args) {
        Animal a = new Dog();
        dogMethod(a);
    }
}
  • `dogMethod` needs a `Dog`. So you should not give it an `Animal a` which could not be a `Dog`, might as well be a `Cat`, who knows. So why are you saving it as `Animal` variable and not `Dog`? If you absolutely have to cast (usually this indicates a bad design in the first place), at least check with `if (a instanceof Dog)` to be able to react to that case yourself. – Zabuzard Dec 04 '19 at 09:49
  • 1
    What are you actually trying to achieve here? Your method expects a Dog but you want to be able to pass in things that are not dogs? You explicitly remove the knowledge of the `a` instance being a Dog. – luk2302 Dec 04 '19 at 09:51
  • 1
    If all you have is an `Animal` and you want to pass it to a method that takes a `Dog` you can't do it without a cast and still keep your type safety. The cast is the thing that says "I guarantee that I fail if the `Animal` is not actually a `Dog`" and thus keeps the type safety. – Joachim Sauer Dec 04 '19 at 09:51
  • I do not really see how generics can help you here. Your question is too broad to understand where and how you intend to utilizie generics here. – Zabuzard Dec 04 '19 at 09:51
  • You could use an animalMethod that takes an animal and calls Animal.doAnimalThing which can be overriden by Dog. – Ralf Renz Dec 04 '19 at 09:53
  • 1
    @Zabuza, I added an edit explaining a bit more what I'm doing. The animal example is just a destillation of the issue. – guywiththeface Dec 04 '19 at 10:32
  • 1
    Seems I will have to go with instanceof and downcasting as generics doesn't seem to be intended for what I had in mind. – guywiththeface Dec 04 '19 at 10:34

2 Answers2

1

No, you can't do that. Consider this:

You have specified method for Dog and you want to pass it generic type which is Animal. If that method would accept generic Animal type, then any animal could be passed there... going further, Your method executes doDogThing, so what if Animal would be a Cat for example. You would be forcing a cat to doDogThing which is absolutely forbidden.

Mershel
  • 542
  • 1
  • 9
  • 17
0

Java has a keyword called instanceof, which checks if an object of some class is actually an instance of a subclass. So if you want to be safe you should check ìf (a instanceof Dog). Thus, you don't need to utilize generics for this, although I am uncertain of the overhead of checking instanceof a lot, your example seems like a learning one, so it probably won't hurt.

nylanderDev
  • 531
  • 4
  • 14