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
是最好的方法,因为它没有过度设计。如果你有不同的条件,那么我的答案可能是最好的