java:统一处理子类
假设我有这样的:
abstract class Command {
static void run (String[]argv) {}
}
class Slice extends Command {
static void run (String[]argv) {/* slicing code */}
}
class Dice extends Command {
static void run (String[]argv) {/* dicing code */}
}
我希望能够迭代命令,所以我写道:
Class<Command>[] commands = {Slice.class,Dice.class}; /* compile error */
for (Class<Command> c : commands) {
if (some_string.equals(c.getName()) {
c.getDeclaredMethod("run",String[].class).invoke(argv);
return;
}
}
但是,似乎 Slice.class
和 Dice.class
不能放入与 Class
相同的容器。
如果我在所有地方用 Class
替换 Class
,则代码编译时会出现一个警告:
[unchecked] unchecked call to getDeclaredMethod(java.lang.String,java.lang.Class<?>...) as a member of the raw type java.lang.Class
c.getDeclaredMethod("run",String[].class).invoke(argv);
当然,可以抑制该警告,但是,我想知道是否还有更多警告优雅的解决方案?
(当然,在 C 中,这可以通过具有两个元素的结构数组来完成:一个字符串和一个指向函数的指针)。
Suppose I have this:
abstract class Command {
static void run (String[]argv) {}
}
class Slice extends Command {
static void run (String[]argv) {/* slicing code */}
}
class Dice extends Command {
static void run (String[]argv) {/* dicing code */}
}
I want to be able to iterate over the commands, so I wrote:
Class<Command>[] commands = {Slice.class,Dice.class}; /* compile error */
for (Class<Command> c : commands) {
if (some_string.equals(c.getName()) {
c.getDeclaredMethod("run",String[].class).invoke(argv);
return;
}
}
however, it appears that Slice.class
and Dice.class
cannot be placed into the same container as Class<Command>
.
If I replace Class<Command>
with Class
everywhere, the code compiles with one warning:
[unchecked] unchecked call to getDeclaredMethod(java.lang.String,java.lang.Class<?>...) as a member of the raw type java.lang.Class
c.getDeclaredMethod("run",String[].class).invoke(argv);
which can, of course, be suppressed, but, I wonder, is there a more elegant solution?
(Of course, in C, this could have been done with an array of structs with two elements: a string and a pointer to a function).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
只有
Command.class
属于Class
类型。它的所有子类型都是Class
。如果将数组和迭代器类型更改为 Class,其余代码应该可以工作。除非您需要反射,否则简单地拥有一个 Command 对象数组会更简单(这需要删除
run
方法上的 static 关键字):Only
Command.class
is of the typeClass<Command>
. All of its subtypes are of the typeClass<? extends Command>
. If you change the array and iterator type toClass<? extends Command>
, the rest of the code should work.Unless you need the reflection, it would be simpler to simply have an array of Command objects (which requires the removal of the static keyword on the
run
method):我强烈建议你放弃反射并创建你的类实例(这样方法就不再是静态的),一切都会变得更加清晰和更明智,并且你稍后会发现这种设计允许将来改进你的类——如果你继续沿着这条路走下去,你就会陷入一个充满伤害的世界(嗯,至少是一个充满伤害的小城市)
我喜欢反射在 Java 中的重要性,正是因为这个原因,它让人们有点沮丧,让他们重新思考他们的想法。方法。
请注意,您还将一些数据直接绑定到类名(代码构造)。我并不是说这是错误的,我已经做过很多次了,而且非常诱人和优雅——但最终我总是在某种程度上感到后悔。一些现实世界的担忧与您的类命名约定/规则不匹配...
我只想使用这样的模式:Command.wants(some_string),或者有一个字符串到类实例地图删除了整个循环,代码变成
I highly recommend you just drop the reflection and make your classes instances (So that the methods are no longer static), everything will be much clearer and more sensible, and you will later find that this design allows for future improvement of your classes--if you keep down this road you are in for a world of hurt (Well, at least a small city of hurt)
I love that Reflection is non-trivial in Java for just this reason, it discourages people a little and makes them rethink their approach.
Note that you are also binding some data directly to a class name (code construct). I'm not saying it's wrong, I've done it many times and it's Extremely Tempting and elegant--but eventually I've always regretted it to some degree or another. Some real-world concern creeps in that doesn't match your class naming conventions/rules...
I would just use a pattern like this instead: Command.wants(some_string), either that or have a string-to-class-instance map which removes your entire loop and the code becomes
尝试将命令数组声明为
Class
另外,按照这里显示的方式,Command 应该是一个接口,而不是一个抽象类(除非您计划稍后向其添加更多行为)。
Try declaring your command array as
Class<? extends Command>
also, the way things are shown here, Command should be an interface, not an abstract class (unless you plan to add more behavior to it later).
无论如何,你的设计是实现这种模式的糟糕方法。在 Java 中,如果您使用实例,即使您实际上并不需要实例状态,您也会获得更清晰的代码:
命令
使用
(我也可能将命令从命令名称到实现存储在
HashMap
中而不是搜索数组。)Your design is a bad way to implement this pattern anyway. In Java, you'll get clearer code if you use instances even when you don't really need instance state:
Commands
Use
(I'd also probably store the commands in a
HashMap
from command name to implementation instead of searching the array.)您无法在 Java 中创建通用数组。
因此,如果您需要通用集合,则必须使用集合框架中的某些类。
例如
You cannot create a generic array in Java.
So, you have to use some class from the Collection framework if you need generic collection.
e.g.