为特定类型的类声明String到Class的Map(Declaring a Map of String to Class, for classes of a specific type)

编程入门 行业动态 更新时间:2024-10-27 17:14:33
为特定类型的类声明String到Class的Map(Declaring a Map of String to Class, for classes of a specific type)

我正在尝试围绕其他所有具有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 ); ... }};

但是我想让用户在没有args的情况下运行命令并列出类和它们的作用。 从以前的工作中,大多数课程都有描述。

我决定在界面中将其形式化:

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()? 想知道我是要重新发明轮子,还是有一些原因这是一个非常糟糕的主意 指定所有类必须实现特定接口是否在此使用场景中为我买了什么? 至少,它似乎让编译器为我做了一些检查。 在运行时,我想知道获得合格的类引用是否比常规反射具有特殊的优势。

为什么我这样做?

我正在让Maven生成一个完整的,自包含的.jar文件 我希望大家只用java -jar my_jar.jar运行它...所以我需要选择一个特定的类; 你将使用java -jar projname.jar command_name arg1 arg2 arg3 如果你只运行java -jar projname.jar你会得到一个类列表以及它们的作用 另一种方法是将每个命令作为java -cp projname.jar com.foobar.package_a.ClassOne arg1 arg2 arg3但这对于输入的人来说有点难看,并且每个类名都需要.sh和.bat。

I'm trying to do a command line wrapper class around some other other classes that all have a main method.

I've declared a map of Strings to classes, but now I'd like to insure that all the classes implement a particular interface.

The idea is that you'd give the a class alias or "command name" as the first argument, then I'd call the main of that class and pass the rest of the argv array to it.

Initially I had this:

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 ); ... }};

But I wanted to let users run the command with no args and list the classes and what they do. And from previous work, most of the classes did have a description.

I decided to formalize this in an interface:

public interface HasDescription { String getDescription(); }

And then:

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 ... }

But I'm not sure how to declare it, I've had many variations. Here's one example of what doesn't work:

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 ); }};

Variations / Lessons:

I've tried with an without a leading letter inside the angle brackets I've tried both implements and extends Even in Java 7 you can't just put new LinkedHashMap<>() when declaring it inline

Questions:

Ideally .getDescription() would be static. I assume that if I had the correct signature, then pulling it out of the hash with .get() I'd assign to a similarly declared variable (sans the top level Mop< >) 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() ? Wondering if I'm either reinventing the wheel, or that there's some reason this is a horribly bad idea Does specifying that all classes must implement a particular interface buy me anything in this usage scenario? At a minimum, seems like it lets the compiler do some checking for me. At runtime, I'm wondering if getting a qualified class reference gives me an special advantage over regular reflection.

Why an I doing this?

I'm having Maven produce a full, self contained .jar file I'd like folks to run it with just java -jar my_jar.jar ... so I need to choose one specific class; you'd run with java -jar projname.jar command_name arg1 arg2 arg3 If you run with just java -jar projname.jar you get a list of classes and what they do The alternative is to run each command as java -cp projname.jar com.foobar.package_a.ClassOne arg1 arg2 arg3 but this is a bit ugly for folks to type in, and would require .sh and .bat for each class name.

最满意答案

你不要使用那样的类型参数。 类型参数可以在类级别方法级别声明 。 使用这样的字段声明,您必须使用通配符:

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 ); }};

我已经尝试了两种implements并进行了extends

在泛型中,您只需使用extends关键字来表示这两个概念。

理想情况下.getDescription()将是静态的。

不,你不能那样做。 这不会给你当前想要的多态行为。

如果拉出一个合格的类变量,是否有一个快捷方式或特殊版本的反射,只是让我说一些像( (HasDescription)clazz ).getDescription() ?

如果要调用这样的方法,那么为什么要存储Class实例而不是实例本身? 如果要存储Class实例,则必须使用Class#newInstance()方法对其进行实例化,并确保所有实现类都为此提供0-arg构造函数。

指定所有类必须实现特定接口是否在此使用场景中为我买了什么?

如果您要存储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();

You don't use type parameters like that. The type parameters can either be declared at Class level or method level. With field declaration like that, you have to use wildcards:

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

In generics, you just use extends keyword to represent both the concepts.

Ideally .getDescription() would be static.

No you can't do that. That would not give you polymorphic behaviour that you want currently.

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() ?

If you want to invoke the method like that, then why are you storing the Class instance instead of the instance itself? If you are storing the Class instance, you would have to instantiate it using Class#newInstance() method, and ensure that all the implementating classes provide a 0-arg constructor for that.

Does specifying that all classes must implement a particular interface buy me anything in this usage scenario?

If you're storing the Class instance, then you have to do that. But if you store the instances themselves, then just keeping the reference as HasDescription would work fine:

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());

and then you can do:

map.get("command1").getDescription();

更多推荐

本文发布于:2023-07-26 03:44:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1270675.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:声明   类型   Class   String   Map

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!