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

Java泛型-使用未知类的成员方法,java,generics,Java,Generics,所以我有一个接口MyInterface,它有一个方法stringsave(tobj) 实现类具有以下定义Animal implements MyInterface。我的主要功能如下所示: MyInterface<Cow> animal = new Animal<Cow>(); Cow cow = new Cow(); cow.setName("Rose"); animal.save(cow); MyInterface<Object> animal = new

所以我有一个接口
MyInterface
,它有一个方法
stringsave(tobj)
实现类具有以下定义
Animal implements MyInterface
。我的主要功能如下所示:

MyInterface<Cow> animal = new Animal<Cow>();
Cow cow = new Cow();
cow.setName("Rose");
animal.save(cow);
MyInterface<Object> animal = new Animal<Object>();
tobj
到Cow对象的合适方式是什么,这样我就可以使用member方法
getName()

我的想法是:

@Override
public void save(T obj)
{
        Object unknown = obj.getClass().newInstance();
        if (unknown instanceof Cow)
        {
            String name = ((Cow) unknown).getName();
        }
}
这是“ok”java吗?我想我可以使用反射并搜索与
未知对象相关的所有方法

更新 只要我定义
MyInterface animal=new animal()像这样我是安全的,但问题出现在这样的情况下:

MyInterface<Cow> animal = new Animal<Cow>();
Cow cow = new Cow();
cow.setName("Rose");
animal.save(cow);
MyInterface<Object> animal = new Animal<Object>();
MyInterface animal=新动物();
然后就没有
getName()
方法了

不,这是“不好”的Java。首先是因为你想避免被贬低,但主要是因为你的想法是这样使用反射

<如果>代码> GETNAME()/代码>功能实际上是模型的一个重要部分,那么考虑把它放置在它自己的接口中。p> 意思:如果有的话,你应该做类似的事情

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

如果假设所有动物都有一个名称,那么创建一个接口

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();
    }
}
class周年纪念{
无效保存(T obj){
...
字符串名称=obj.getName();
}
}

即使使用
instanceof
有效,就像在你的帖子中一样,这也是一种要避免的做法,因为如果有一天你想实现一种新的动物类型,比如说
,你必须修改save方法的实现以添加
if(未知的马的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
        }
    }
}
接口可保存
{
布尔canSave();
}
公共类Cow实现了可保存的
{
//...
@凌驾
布尔值canSave()
{
返回getName()!=null&!getName().isEmpty();
}
}
公共类动物实现MyInterface
{
@凌驾
公共作废保存(T obj)
{
if(obj.canSave())
{
//随便
}
}
}

所有答案都很好,可以毫无疑问地使用。但我还是有一些建议。虽然其他人大部分时间都在谈论一个新接口,然后调用一个方法,比如
getName()
canSave
(它确实像一个符咒一样工作),但我更喜欢使用自定义测试工具,比如
谓词

我假设您的
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
         }
     }
}

使用
instanceof
检查对象的类型通常意味着您的代码有气味。对接口进行编码的全部意义在于,您可以对任何匹配的通用对象调用
getName()
,而不用担心该对象具有
getName()
方法。您的Cow类是动物的子类吗?它是“ok”,但很难维护。假设您现在实现了一个
,您可能需要检查它的
goodBoiScore()
。对于
Cat
,您可能需要检查它的
meow()
,。。。对于每个新类,您必须创建一个新的
if(…instanceof…
)。这对我来说似乎是一个挑战。你能解释一下你实际上想用的是什么吗?例如,
cow
的名字?我的问题是,你是否特别希望这种情况只发生在cow对象上,或者发生在实现这个接口的所有类上?你不能在MyInterface或Animal的接口中编写一个(虚拟)getName()方法,这样你就可以调用这个方法而不用担心对象必须是一头奶牛吗?如果你使用
object
作为泛型参数,你几乎放弃了几乎所有的类型security=)来避免这种情况,我们可以使用
extends
super
来限制泛型类型。你可能想看一下演员阵容。我想我不需要演员阵容。。。甚至不可能将object()的对象传递给save方法。只要我在尖括号中定义我使用的类型。刚刚看到:)“不好”-非常主观。向下投射时有发生。例如,有时你会被不属于你的代码所困扰,无法更改。我主要关心的是使用反射-相应地更新了我的答案。我没有想到这一点,真的很好!我会试试你的方法。不知道类可以在其泛型类型上“扩展”接口!好办法。太糟糕了,我不能接受一个以上的答案。我觉得
新接口是最方便的解决方案,但这很酷。@BakedInhalf它实际上取决于您的用例。因为当你只需要检查是否为每只动物设置了名称时,
newinterface
是最好的方法,因为它没有过度设计。如果你有不同的条件,那么我的答案可能是最好的