英文:
Understanding generic in Java
问题
以下是翻译好的内容:
我正在构建一些通用代码,用于返回任何类型的对象集合。这是我的代码:
public class Util{
public static <T, R extends Collection> R a(Collection<T> collection) {
return (R) collection;
}
public static <T> List<T> listWith(T... items) {
return Arrays.asList(items);
}
public static <T> Set<T> setWith(T... items) {
return new HashSet<>(Arrays.asList(items));
}
}
我的想法是,通过这个Util类,我可以创建任何类型的列表或集合,就像这样:
List<String> list = a(listWith("str1", "str2"));
Set<Object> set = a(setWith(new Object(), new Object()));
我现在有两个问题:
1. 如何限制左边的Obj类型与传递给`listWith`方法的参数的Obj类型相同?因为现在我可以做类似这样的事情:`Set<String> set = a(setWith(new Object(), new Object()));` 而没有编译错误。
2. 如何限制`a`方法的返回类型仅为**扩展Collection的类**。现在我可以做类似这样的事情:`User user = a(listWith("test"));` 也没有编译错误,但然后它会引发一个转型异常。我尝试过将返回类型定义为`R extends Collection`,但没有成功。
英文:
I am building some generic codes which returning a collection of any type of object. Here is my build:
public class Util{
public static <T, R extends Collection> R a(Collection<T> collection) {
return (R) collection;
}
public static <T> List<T> listWith(T... items) {
return Arrays.asList(items);
}
public static <T> Set<T> setWith(T... items) {
return new HashSet<>(Arrays.asList(items));
}
}
My Idea is from this Util class I can create any list or set of any object type, something like:
List<String> list = a(listWith("str1", "str2"));
Set<Object> set = a(setWith(new Object(), new Object()));
I have now two questions:
- How can I restrict the type of the Obj in the left to be the same as the Obj type of the parameter passed to the
listWith
method? Because right now I can do something like :Set<String> set = a(setWith(new Object(), new Object()));
without any compile error - How can I restrict the return type of the
a
method to be only class that extends the Collection. Right now I can do something like:User user = a(listWith("test"));
also without compile error but then it will throw an casting exception. I did try above with return type asR extends Collection
but it did not success
答案1
得分: 2
-
如何限制左侧的 Obj 类型与传递给 listWith 方法的参数的 Obj 类型相同?
不要使用 Collection 的原始类型,而是将其限制为泛型类型。
public static <T, R extends Collection<T>> R a(Collection<T> collection) { return (R) collection; }
但是可以进行更好的设计(请参阅下文)。
-
如何限制 a 方法的返回类型仅为扩展 Collection 的类。目前我可以执行类似以下的操作:User user = a(listWith("test")); 即使没有编译错误,但随后会抛出转换异常。
请记住类 User 未来可能会实现 Collection,编译器在编译时不会检查此信息。
进一步的限制如下。如果 R 是 Collection
的子类型,并且需要同一集合作为输入参数,则可以要求 R collection,并且无需显式转换即可返回。 public static <T, R extends Collection<T>> R a(R collection) { return collection; }
应用答案的第二部分后:
List<String> list = a(listWith("str1", "str2")); // 编译通过
Set<Object> set = a(setWith(new Object(), new Object())); // 编译通过
Set<String> set2 = a(setWith(new Object(), new Object())); // 无法编译
User user = a(listWith("test")); // 无法编译
这种限制对于这个简单的情况是有效的,但完全没有意义。您可以在 @DmytroMitin 的 答案 中找到进一步的解释。
正如您所看到的,整个 #2 的应用最终 返回输入本身,这使我产生了一个问题:
“是否需要这种泛型包装?”:
List<String> list = listWith("str1", "str2");
Set<Object> set = setWith(new Object(), new Object());
英文:
-
> How can I restrict the type of the Obj in the left to be the same as the Obj type of the parameter passed to the listWith method?
Don't use a raw type of the
Collection
and restrict it to the generic type.public static <T, R extends Collection<T>> R a(Collection<T> collection) { return (R) collection; }
But it can be designed better (look below).
-
> How can I restrict the return type of the a method to be only class that extends the Collection. Right now I can do something like: User user = a(listWith("test")); also without compile error but then it will throw an casting exception.
Remember the class
User
might implementCollection
in the future and compiler doesn't check this information at the compile time.Further restriction will do that. If the
R
is a subtype ofCollection<T>
and the very same collection is required as an input parameter, you can ask forR collection
and return it without explicit casting.public static <T, R extends Collection<T>> R a(R collection) { return collection; }
After applying the 2nd part of the answer:
List<String> list = a(listWith("str1", "str2")); // compiles
Set<Object> set = a(setWith(new Object(), new Object())); // compiles
Set<String> set2 = a(setWith(new Object(), new Object())); // doesn't compile
User user = a(listWith("test")); // doesn't compile
This restriction is valid for this simple case but doesn't make sense at all. You can find a further explanation at @DmytroMitin's answer.
As you can see, the whole application of the #2 finally returns the input itself, which it gives me a question:
"Is such generic wrapping needed?":
List<String> list = listWith("str1", "str2");
Set<Object> set = setWith(new Object(), new Object());
答案2
得分: 2
我只会翻译你提供的代码部分,不会回答关于翻译的问题。
我会补充**@Nikolas**的答案,解释他的修复方法 #1
public static <T, R extends Collection<T>> R a(Collection<T> collection) {
return (R) collection;
}
User user = a(listWith("test")); // 仍然可以编译,即为何 `R extends Collection<T>` 没有足够限制返回类型,使其仍然可以是 `User`。
我猜问题在于方法 `a` 的类型参数 `T, R` 可以被推断为
User user = Util.<String, User & Collection<String>>a(listWith("test"));
这里 `Util.<String, User & Collection<String>>a...` 似乎不是有效的语法,但如果我们定义
class User {}
class SubUser extends User implements Collection<String> { ... }
那么
User user = Util.<String, SubUser>a(listWith("test"));
是可能的。
---
关于你的第二个问题
> 我如何限制 `a` 方法的返回类型只能是继承了 Collection 的类。
一般情况下,这似乎是不可能的,因为对于每个类 `User`,它的子类
class SubUser<T> extends User implements Collection<T> {...}
仍然是可能的。
英文:
I'll just add to @Nikolas's answer why with his fix #1
public static <T, R extends Collection<T>> R a(Collection<T> collection) {
return (R) collection;
}
User user = a(listWith("test"));
still compiles i.e. why R extends Collection<T>
doesn't restrict enough the return type so that it still can be User
.
I guess the thing is that the type parameters T, R
of the method a
can be inferred like
User user = Util.<String, User & Collection<String>>a(listWith("test"));
Here Util.<String, User & Collection<String>>a...
seems to be not valid syntax but if we define
class User {}
class SubUser extends User implements Collection<String>{ ... }
then
User user = Util.<String, SubUser>a(listWith("test"));
is possible.
Regarding your 2nd question
> How can I restrict the return type of the a
method to be only class that extends the Collection.
Generally this seems impossible because for every class User
its subclass
class SubUser<T> extends User implements Collection<T> {...}
is still possible.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论