我正在尝试围绕其他一些都有 main 方法的类做一个命令行包装器类。
我已经声明了一个字符串到类的映射,但现在我想确保所有类都实现一个特定的接口(interface)。
我的想法是,您将类别名或“命令名称”作为第一个参数,然后我将调用该类的 main 并将 argv 数组的其余部分传递给它。
最初我有这个:
static final Map<String, Class> CLASSES = new LinkedHashMap<String,Class>() {{
put( "command1", com.foobar.package_a.ClassOne.class );
put( "command2", com.foobar.package_a.ClassTwo.class );
put( "command3", com.foobar.package_b.ClassThree.class );
...
}};
但我想让用户运行不带参数的命令并列出类及其作用。从以前的工作来看,大多数类都有描述。
我决定在一个界面中将其形式化:
public interface HasDescription {
String getDescription();
}
然后:
public class ClassOne implements HasDescription {
// I'd prefer static, but that's a different concern
public String getDescription() {
return "check files for gophers";
}
... rest of class ...
}
但我不确定如何声明它,我有很多变体。这是不起作用的一个示例:
static final Map<String, Class<T implements HasDescription>> CLASSES = new LinkedHashMap<String,Class<T implements HasDescription>>() {{
put( "command1", com.foobar.package_a.ClassOne.class );
put( "command2", com.foobar.package_a.ClassTwo.class );
put( "command3", com.foobar.package_b.ClassThree.class );
}};
变化/教训:
- 我试过尖括号内没有前导字母
- 我都试过了
implements
和extends
- 即使在 Java 7 中,您也不能只输入
new LinkedHashMap<>()
内联声明时
问题:
- 理想情况下,.getDescription() 应该是静态的。
- 我假设如果我有正确的签名,然后使用 .get() 将其从散列中拉出,我会分配给一个类似声明的变量(没有顶级 Mop< >)
- 如果拉出一个适当限定的类变量,是否有一个快捷方式或特殊版本的反射让我说类似 ( (HasDescription)clazz ).getDescription() 的东西?
- 想知道我是在重新发明轮子,还是出于某种原因这是一个非常糟糕的主意
- 指定所有类都必须实现一个特定的接口(interface)在这个使用场景中对我有什么好处吗?至少,它似乎让编译器为我做一些检查。在运行时,我想知道获得合格的类引用是否比常规反射给我带来特殊优势。
我为什么要这样做?
- 我让 Maven 生成一个完整的、独立的 .jar 文件
- 我希望人们只使用 java -jar my_jar.jar 来运行它...所以我需要选择一个特定的类;你会用
java -jar projname.jar command_name arg1 arg2 arg3
运行 - 如果你只用
java -jar projname.jar
运行你会得到一个类(class)列表和他们做什么 - 另一种方法是将每个命令运行为
java -cp projname.jar com.foobar.package_a.ClassOne arg1 arg2 arg3
但这对于人们输入来说有点难看,并且每个类名都需要 .sh 和 .bat。
最佳答案
你不会像那样使用类型参数。类型参数可以在类级别 或方法级别 声明。对于这样的字段声明,您必须使用通配符:
static final Map<String, Class<? extends HasDescription>> CLASSES = new LinkedHashMap<String,Class<? extends HasDescription>>() {{
put( "command1", com.foobar.package_a.ClassOne.class );
put( "command2", com.foobar.package_a.ClassTwo.class );
put( "command3", com.foobar.package_b.ClassThree.class );
}};
I've tried both
implements
andextends
在泛型中,您只需使用 extends
关键字来表示这两个概念。
Ideally .getDescription() would be static.
不,你不能那样做。这不会给您当前想要的多态行为。
If a pull out a properly qualified class variable, is there a shortcut or special version of reflection that just lets me say something like
( (HasDescription)clazz ).getDescription()
?
如果你想像那样调用方法,那么为什么要存储 Class
实例而不是实例本身?如果要存储 Class
实例,则必须使用 Class#newInstance()
对其进行实例化。方法,并确保所有实现类都为此提供一个 0-arg 构造函数。
Does specifying that all classes must implement a particular interface buy me anything in this usage scenario?
如果您要存储 Class
实例,那么您必须这样做。但是,如果您自己存储实例,那么只需将引用保留为 HasDescription
就可以正常工作:
static final Map<String, HasDescription> map = new LinkedHashMap<>();
map.put("command1", new com.foobar.package_a.ClassOne());
map.put("command2", new com.foobar.package_a.ClassTwo());
然后你可以做:
map.get("command1").getDescription();
关于java - 为特定类型的类声明一个字符串到类的映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22151968/