Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics - use member method of unknown class

Tags:

java

generics

So I have an Interface MyInterface<T> which has a method String save(T obj) The implementing class has this definition Animal<T> implements MyInterface<T>. My Main function looks like this:

MyInterface<Cow> animal = new Animal<Cow>();
Cow cow = new Cow();
cow.setName("Rose");
animal.save(cow);

So far so good, animal.save() can only save Cows which is type-safe.

Now the problem. In my Animal class I have the save method, but before I save I want to know that my Cow has a name. The Cow class has a getName() method.

Save method:

@Override
public void save(T obj)

What would be an apropriate way to go from T obj to a Cow-object so I can use the member method getName()?

My idea is:

@Override
public void save(T obj)
{
        Object unknown = obj.getClass().newInstance();
        if (unknown instanceof Cow)
        {
            String name = ((Cow) unknown).getName();
        }
}

Is this "ok" java? I guess I could use reflection and search for all methods related to the unknown object as well..

Update As long as I define MyInterface<Cow> animal = new Animal<Cow>(); Like this I'm safe, but the problem apperas when it looks like this:

MyInterface<Object> animal = new Animal<Object>();

Then there is no getName() method....

like image 964
Baked Inhalf Avatar asked Nov 27 '25 05:11

Baked Inhalf


2 Answers

If you assume that all animals have a name then create an interface.

static interface HasName {
    String getName();
}

All objects having a name should then implements the interface

class Cow implements HasName{
    String name;

    Cow(String name){
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}

Then modifying Annimal to allow all objects implementing the interface you will be able to get their names:

class Annimal<T extends HasName> {
    void save(T obj) {
        ...
        String name =  obj.getName();
    }
}

Even if the use of instanceof works, like in your post, it's a practice to avoid, because if one day you want to implement a new type of animal, let's say Horse, you will have to modify the implementation of your save method to add the if (unknown instanceof Horse) condition.

like image 139
Guillaume Barré Avatar answered Nov 28 '25 19:11

Guillaume Barré


instanceof should be avoided wherever possible, and so should reflection.

I would add a separate interface which indicates whether something is in a saveable state. Your Animal class would then need to change it's generic type parameter to only allow saveable items.

interface Saveable
{
    boolean canSave();
}

public class Cow implements Saveable
{
    //...

    @Override
    boolean canSave()
    {
        return getName() != null && !getName().isEmpty();
    }
}

public class Animal<T extends Saveable> implements MyInterface<T>
{
    @Override
    public void save(T obj)
    {
        if (obj.canSave())
        {
            //whatever
        }
    }
}
like image 44
Michael Avatar answered Nov 28 '25 19:11

Michael



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!