java - 为特定类型的类声明一个字符串到类的映射

标签 java generics reflection collections jar

我正在尝试围绕其他一些都有 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 );
}};

变化/教训:

  • 我试过尖括号内没有前导字母
  • 我都试过了implementsextends
  • 即使在 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 and extends

在泛型中,您只需使用 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/

相关文章:

java - 我可以将类放在通用类声明中吗?

java - 在 JUnit 中引用私有(private)类

java - 序列化 Weka 过滤器

java - 扩展集合泛型类的泛型类

generics - 当类型参数在声明站点协变时,强制类型参数在使用站点保持不变

c# - 获取 StringLength 值的扩展方法

c# - 查询 Entity Framework 以获取动态类型列表

java - 用于嵌套一系列 for 循环的大 O

java - 如何从本地主机访问本地文件

java - map 中的 3 亿个项目