Java泛型 - 使用未知类的成员方法

时间:2017-12-21 10:28:39

标签: java generics

所以我有一个接口MyInterface<T>,它有一个方法String save(T obj) 实现类具有此定义Animal<T> implements MyInterface<T>。我的主要功能如下所示:

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

到目前为止,animal.save()只能保存类型安全的奶牛。

现在问题。在我的Animal类中,我有save方法,但在我保存之前我想知道我的Cow有一个名字。 Cow类有一个getName()方法。

保存方法:

@Override
public void save(T obj)

T obj到Cow对象的适当方式是什么,所以我可以使用成员方法getName()

我的想法是:

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

这是“好”的java吗?我想我可以使用反射并搜索与unknown对象相关的所有方法。

更新 只要我定义MyInterface<Cow> animal = new Animal<Cow>();这样我就安全了,但问题出现的时候看起来像这样:

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

然后没有getName()方法....

4 个答案:

答案 0 :(得分:4)

如果您认为所有动物都有一个名字,那么就创建一个界面。

static interface HasName {
    String getName();
}

所有具有名称的对象应该实现接口

class Cow implements HasName{
    String name;

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

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

然后修改Annimal以允许实现界面的所有对象,您将能够获得他们的名字:

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

即使instanceof的使用有效,也就像在你的帖子中一样,这是一种避免的做法,因为如果有一天你想要实施一种新型的动物,那就让我们说{ {1}},您必须修改save方法的实现以添加Horse条件。

答案 1 :(得分:3)

应尽可能避免{p> instanceof,反思也应如此。

我会添加一个单独的界面,指示某些东西是否处于可保存状态。然后,您的Animal类需要将其通用类型参数更改为仅允许可保存的项目。

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
        }
    }
}

答案 2 :(得分:2)

不,这是&#34;不行&#34; Java的。首先是因为你想要避免向下倾斜,但主要是因为你想要使用这样的反射。

如果getName()功能确实是模型的重要组成部分,那么请考虑将其置于自己的界面中。

含义:如果有的话,你应该做类似

的事情
@Override
public void save(T obj) {
  if (obj instanceof NamedThingy) { 
    then cast ...

答案 3 :(得分:1)

所有答案都很棒,可以毫无疑问地使用。但我仍有一些建议。虽然其他人大部分时间都在谈论一个新的界面,然后调用像getName()canSave这样的方法(它确实像魅力一样),我更喜欢使用自定义测试器,如Predicate<T>

我假设你的MyInterface就像一个将实体保存到数据库或类似数据结构的服务。然后,您可以调整您的课程Animal,如下所示:

public class Animal<T> implements MyInterface<T>{
     private final Predicate<T> canSave;

     public Animal(Predicate<T> canSave){
         this.canSave = canSave;
     }

     @Override
     public void save(T obj){
         if(canSave.test(obj)){
              // your save logic
         }
     }
}

这样,您可以在保存该实体时为每个Animal实例定义一个行为:

Animal<Cow> animal = new Animal<>(c -> c.getName() != null); // save only when name not null
Cow cow = new Cow();

animal.save(cow); // doesn't save because name is null

cow.setName("Rose");
animal.save(cow); // saves because name is set

animal = new Animal<>(c -> true); // save always

cow.setName(null);
animal.save(cow); // saves because it can always