How can I make this java generic cast ?
我该如何制作这个java通用演员?
public interface IField {
}
class Field implements IField { // package private class
}
public class Form {
private List<Field> fields;
public List<IField> getFields() {
return this.fields;
}
}
The return statement throws a compiler error (I know the reason - I read the generics tutorial) but it would be very handy to write such code.
return语句抛出一个编译器错误(我知道原因 - 我阅读了泛型教程),但编写这样的代码会非常方便。
If I declared "fields" as List I would need to use a lot of casts to Field in other methods of a Form class .
如果我将“fields”声明为List,则需要在Form类的其他方法中使用很多强制转换为Field。
Can I force that damn compiler to bend it's rules and compile that return statement ?
我可以强制该死的编译器弯曲它的规则并编译返回语句吗?
Thanks in advance.
提前致谢。
5 个解决方案
#1
17
A better solution, IMO, is to change the signature of your method to use a bounded wildcard:
IMO更好的解决方案是更改方法的签名以使用有界通配符:
public List<? extends IField> getFields()
This will let the caller treat anything coming "out" of the list as an IField, but it won't let the caller add anything into the list (without casting or warnings), as they don't know what the "real" type of the list is.
这将让调用者将列表中的任何内容视为IField,但它不会让调用者在列表中添加任何内容(没有强制转换或警告),因为他们不知道“真实”类型是什么列表是。
#2
12
As it happens, you can, because Java generics are just grafted on, not part of the type system.
碰巧,你可以,因为Java泛型只是嫁接,而不是类型系统的一部分。
You can do
你可以做
return (List<IField>)(Object)this.fields;
because all List<T>
objects are the same underlying type.
因为所有List
Bear in mind that this allows anyone to put any type implementing IField
in your list, so if your collection is not read-only, you may run into difficulties.
请记住,这允许任何人在您的列表中放置任何实现IField的类型,因此如果您的集合不是只读的,则可能会遇到困难。
#3
5
Don't do it.
不要这样做。
A List<Field>
is not a List<IField>
. You can try to force the compiler into accepting (I thought it was not possible, I wish it was not possible), but that will get you into trouble. The compiler will allow a user to introduce AnotherField deriving from IField into the given List breaking your invariants, and breaking into the type safety that generics provide. Later use of the List<Field>
will break as extraction of the strange element will fail the implicit cast to Field where you will not expect it to happen.
List
If you do need to return a List<IField>
instead of List<Field>
, then I will recommend generating a new list filled with the same elements. If you can modify your interface go for Jon Skeets solution.
如果确实需要返回List
#4
2
If the caller does not need to be able to modify the list:
如果调用者不需要能够修改列表:
return Collections.<IField>unmodifiableList(this.fields);
#5
0
Sunlight is right, you can just cast it.
阳光是对的,你可以投它。
Another fix is to double-check that you really need a List<Field>
, or whether you can change your internal fields
variable to List<IField>
.
另一个解决方法是仔细检查您是否确实需要List
As long as you only ever use methods on the contents of the list that are on the IField
interface, you should be able to do a strightforward swap.
只要您只使用IField接口上列表内容的方法,您就应该能够进行直接的交换。
#1
17
A better solution, IMO, is to change the signature of your method to use a bounded wildcard:
IMO更好的解决方案是更改方法的签名以使用有界通配符:
public List<? extends IField> getFields()
This will let the caller treat anything coming "out" of the list as an IField, but it won't let the caller add anything into the list (without casting or warnings), as they don't know what the "real" type of the list is.
这将让调用者将列表中的任何内容视为IField,但它不会让调用者在列表中添加任何内容(没有强制转换或警告),因为他们不知道“真实”类型是什么列表是。
#2
12
As it happens, you can, because Java generics are just grafted on, not part of the type system.
碰巧,你可以,因为Java泛型只是嫁接,而不是类型系统的一部分。
You can do
你可以做
return (List<IField>)(Object)this.fields;
because all List<T>
objects are the same underlying type.
因为所有List
Bear in mind that this allows anyone to put any type implementing IField
in your list, so if your collection is not read-only, you may run into difficulties.
请记住,这允许任何人在您的列表中放置任何实现IField的类型,因此如果您的集合不是只读的,则可能会遇到困难。
#3
5
Don't do it.
不要这样做。
A List<Field>
is not a List<IField>
. You can try to force the compiler into accepting (I thought it was not possible, I wish it was not possible), but that will get you into trouble. The compiler will allow a user to introduce AnotherField deriving from IField into the given List breaking your invariants, and breaking into the type safety that generics provide. Later use of the List<Field>
will break as extraction of the strange element will fail the implicit cast to Field where you will not expect it to happen.
List
If you do need to return a List<IField>
instead of List<Field>
, then I will recommend generating a new list filled with the same elements. If you can modify your interface go for Jon Skeets solution.
如果确实需要返回List
#4
2
If the caller does not need to be able to modify the list:
如果调用者不需要能够修改列表:
return Collections.<IField>unmodifiableList(this.fields);
#5
0
Sunlight is right, you can just cast it.
阳光是对的,你可以投它。
Another fix is to double-check that you really need a List<Field>
, or whether you can change your internal fields
variable to List<IField>
.
另一个解决方法是仔细检查您是否确实需要List
As long as you only ever use methods on the contents of the list that are on the IField
interface, you should be able to do a strightforward swap.
只要您只使用IField接口上列表内容的方法,您就应该能够进行直接的交换。