一种查找 Java 对象初始化为什么而不是声明类型的方法?
我不知道我是否在这里遗漏了一些东西,但我在将对象转换为其实际的初始化类型时遇到了问题。基本上,如果我使用“SuperClass sc = new SubClass()”创建一个对象,那么我在 sc 上调用一个方法,我希望该方法能够调用方法(子类)而不是方法(超类)。示例如下:
public class Example
{
public static void act(SuperClass a) {
System.out.println("SuperClass");
}
public static void act(SubClass a) {
System.out.println("SubClass");
}
public static void main(String[] args) {
SuperClass sc = new SubClass();
// want to find a way to call act(SubClass) instead of act(SuperClass)
act(sc);
}
}
class SuperClass {}
class SubClass extends SuperClass {}
我现在正在使用访问者模式,但我想知道是否还有其他方法可以做到这一点,也许通过 Java Reflection API?
预先非常感谢!
==编辑==
我知道,一般来说,对于OO来说,最好将功能放回超类/子类本身,但对于我的特定用例,我有一堆子类,它们是不可变的模型类,它们应该传递给不同的类型执行引擎(想想不同的“示例”类)。子类/模型类应该只保存不可变的信息,仅此而已,实际的功能在于执行引擎(示例类)。这就是为什么我想知道访客模式的替代方案。有没有人有办法恢复Java中实际的“初始化”信息?如果是的话,非常感谢。
由于问题的性质,我不能使用直接铸造...... 想象一下,如果我有一个 SuperClass 的数组列表,其中每个元素可能是 SubClass1、SubClass2、SubClass3,全部从 SuperClass 扩展。
现在,当您从 Arraylist 中取出内容时,您会得到一个 SuperClass 对象,即使它们实际上可能是 SubClass1、SubClass2、SubClass3 等。
接下来,我想调用 act(SubClass1),并能够调用正确的 act当前类型的 () 方法。所以我想最终调用 act(SubClass1)、act(SubClass2)、act(SubClass3),而不是 act(SuperClass)。
==再次编辑==
我想出了一种通过Java Reflection API来做到这一点的方法,通过使用Class.forName(classname)查找子类的实际底层类型,然后使用正确的方法签名动态调用该方法。我已将其以答案形式写在本页下方的某个位置,供那些对此问题感兴趣的人使用。请注意,这不是完成我在这里尝试做的事情的非常有效的方法,如果您遇到我的情况,那么使用访问者模式或 if-else 语句可能会更好。
因此,尼古拉·穆萨蒂给出的答案最接近回答我的问题,尽管他也指出,随着子类数量的增长,if-else 语句列表会变得非常长。我会选择他的答案作为接受答案,因为我没有在问题中明确说明我希望避免 if-else 检查。
无论如何,今天我尝试了一下 Java Reflection API,并得出了这样的结论:
SuperClass sc = new SubClass();
// Get the actual class of sc. actualClass now is SubClass.
Class actualClass = Class.forName(sc.getClass().getCanonicalName());
// Basically invoking act(SubClass sc) instead of act(SuperClass sc)
Class parameters[] = {actualClass};
Method method = Example.class.getMethod("act", parameters);
Object arguments[] = {sc};
method.invoke(null, arguments);
这肯定不是一个好方法,特别是因为 Java Reflection API 造成的性能损失。这可能比访问者模式或 if-else 检查是否有一百万个子类更好,因为它可能需要管理更少的代码,但是我现在会坚持使用访问者模式,因为我没有一百万个子类要管理。
无论如何,我只是想将其发布在这里以表明它可以完成,仅供那些好奇的人使用。
I don't know if I'm missing something here, but I am having trouble casting an object to its actual, initialized type. Basically, if I create an object with "SuperClass sc = new SubClass()," then I call a method on sc, I want the method to be able to call method(Subclass) instead of method(Superclass). Example shown below:
public class Example
{
public static void act(SuperClass a) {
System.out.println("SuperClass");
}
public static void act(SubClass a) {
System.out.println("SubClass");
}
public static void main(String[] args) {
SuperClass sc = new SubClass();
// want to find a way to call act(SubClass) instead of act(SuperClass)
act(sc);
}
}
class SuperClass {}
class SubClass extends SuperClass {}
I am using the visitor pattern right now, but I'm wondering if there are other ways to do this, maybe via the Java Reflection API?
Thanks alot in advance!
== edit ==
I know that generally with OO it's better to stick the functionality back to the superclass/subclasses themselves, but for my specific use cases I have a bunch of subclasses that are immutable model classes, which should be passed to different kinds of execution engines (think different "Example" classes). The subclasses/model classes should only hold immutable information, nothing more, and the actual real functionality lies with the execution engine (Example class). That's why I am wondering about alternatives to the visitor's pattern. Does anyone have a way to recover the actual "initialized" information in Java? If so, thank you so much.
And because of the nature of the problem, I can't use direct casting...
Imagine if I have an arraylist of SuperClass, where each element may be SubClass1, SubClass2, SubClass3, all extending from SuperClass.
Now, when you pull things out of the Arraylist, you get a SuperClass object, even though they may really be SubClass1, SubClass2, SubClass3, etc.
Next, I want to call act(SubClass1), and be able to invoke the correct act() method on the current type. So I want to end up calling act(SubClass1), act(SubClass2), act(SubClass3), instead of act(SuperClass).
== edit again ==
I've came up with a way of doing this via the Java Reflection API, by finding the actual underlying type of the SubClass using Class.forName(classname), then dynamically invoking the method with the correct method signature. I have written this up in answer form somewhere down this page for those who are interested about this problem. Note that this isn't a very efficient way of accomplishing what I'm trying to do here, and you're probably better off with visitor pattern or if-else statements if you're stuck with my situation.
So the answer that Nicola Musatti gave is the closest to answering my question, though as he has also pointed out, as the number of SubClasses grow the if-else statements list gets very long. I will choose his answer as the accept answer since I hadn't stated clearly in my question that I was hoping to avoid the if-else checks.
Anyways, so I've played around a bit with the Java Reflection API today and came up with this:
SuperClass sc = new SubClass();
// Get the actual class of sc. actualClass now is SubClass.
Class actualClass = Class.forName(sc.getClass().getCanonicalName());
// Basically invoking act(SubClass sc) instead of act(SuperClass sc)
Class parameters[] = {actualClass};
Method method = Example.class.getMethod("act", parameters);
Object arguments[] = {sc};
method.invoke(null, arguments);
This is surely not a great way to do things, especially because of the performance penalty impose by the Java Reflection API. This might be better than visitor pattern or the if-else checks if you have a million subclasses, since it's probably less code to manage, however I'll stick with the visitor pattern for now since I don't have a million subclasses to manage.
Regardless, just thought I would post this here to show that it can be done, just for those who are curious.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
难道你不应该在
SuperClass
和SubClass
中定义act()
吗?这样,无论对象引用的类型如何,都会调用正确的方法。编辑:如果我没记错的话,访问者模式在要访问的元素上定义了类似
accept()
方法的内容,该方法允许访问者以多态方式访问所访问元素中它感兴趣的任何内容。Shouldn't you define
act()
inSuperClass
andSubClass
? That way the correct method will be called regardless of the type of the reference to the object.Edit: If I remember correctly the visitor pattern defines something like an
accept()
method on the elements to be visited which allows the visitor to polymorphically access whatever it's interested in in the visited elements.一般的解决方案是访客模式。如果您遇到特定的情况,您知道 sc 的实际类型,那么您确实可以使用强制转换,正如已经建议的那样,可能在类型检查之前进行类型检查,如
然而发明了访问者模式,因为当您需要处理的类数量会增加。
最后但并非最不重要的一点是,有时最简单的方法就是保留实际类型的变量:
The general solution is the Visitor pattern. If you have a specific situation where you know the actual type of sc you can indeed use a cast, as was already suggested, possibly preceded by a type check as in
However the Visitor pattern was invented because this approach doesn't scale up when the number of classes you need to handle grows.
Last but not least, sometimes the simplest approach is just to keep around a variable of the actual type:
又怎样
??
What about
??
也许您应该将方法
act
设为 SupperClass 类的成员,然后在 SubClass 类中重写它。Maybe you should make the method
act
member of the SupperClass class, and then override it in SubClass class.