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

问题描述 投票:2回答:4

所以我有一个接口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-object的合适方式,所以我可以使用成员方法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()方法....

java generics
4个回答
3
投票

应尽可能避免使用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
        }
    }
}

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,就像在你的帖子中一样,这是一种避免的做法,因为如果有一天你想要实现一种新型动物,让我们说Horse,你将不得不修改你的保存方法的实现来添加if (unknown instanceof Horse)条件。


2
投票

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

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

意思是:如果有的话,你应该做的事情

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

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
© www.soinside.com 2019 - 2024. All rights reserved.