用文字解释很难,但是Java Generics给了我一个意想不到的结果。我希望如果我说列表的类型为? extends Object
,我可以在那里存储任何内容。因此,如果类型Wrapper<? extends Object>
的列表,我可以在那里存储任何类型的包装器。等等。这对我来说很有意义。但是我们假设我们有:
private static class Wrapper<T> {
public Wrapper(T t) { /**/ }
}
我想要的是:
private static final List<Wrapper<Wrapper<? extends Object>>> ls1 = new ArrayList<>();
请注意,这会给我一个错误:
public static <T> doit(T t) {
Wrapper<Wrapper<T>> l1 = new Wrapper<>(new Wrapper<>(t));
ls1.add(l1); // nok
// add (Wrapper<Wrapper<? extends java.lang.Object>>) in List
// cannot be applied to (Wrapper<Wrapper<T>>
}
但是如果我将Wrapper包装在辅助包装器(rs)中,那么:
private static class C<T> extends Wrapper<Wrapper<T>> {
public C(T t) {
super(new Wrapper<>(t));
}
}
private static final List<C<? extends Object>> ls2 = new ArrayList<>();
public static <T> doit(T t) {
ls2.add(new C<>(t)); // ok
}
请注意,它是一回事;这对我没有意义。
PS。在我的例子中,我没有制作包装器包装器,而是创建泛型类的ThreadLocal。
答案 0 :(得分:2)
我认为
private static void AssignValueToProperty(ObjectAccessor accessor, object value, string propertyLambdaString)
{
var index = propertyLambdaString.IndexOf('.');
if (index == -1)
{
accessor[propertyLambdaString] = value;
// problem above: throws Exception if assigning value to Nullable<T>
}
else
{
var property = propertyLambdaString.Substring(0, index);
accessor = ObjectAccessor.Create(accessor[property]);
AssignValueToProperty(accessor, value, propertyLambdaString.Substring(index + 1));
}
}
你可以这样做
public class A
{
public double? SomeValue {get; set;}
}
...
var a = new A();
var accessor = ObjectAccessor.Create(a);
accessor["SomeValue"] = 100; // throws Exception, when assigning 100.0 it works???
答案 1 :(得分:0)
说实话,我必须更详细地研究它为什么不起作用。它最有可能与泛型类型擦除有关。 我有一个解决方法,我知道这个解决方案失去了l1对象的典型。如果你可以接受它。
Wrapper<Wrapper<? extends Object>> l1 = new Wrapper<>(new Wrapper<>(t));
ls1.add(l1);
答案 2 :(得分:0)
基本上你需要决定什么更重要,对于你想要把放入包装器的内容,通过什么 out out 包装(你不能两者都安全)。决定之后,您需要在extends
和super
之间进行选择。
如果只是想要存储指针,那么List<Wrapper<Wrapper>>
就足够了,但之后你需要做一些演员。
当您使用 extends
时,? extends Foo
表示结构返回的任何数据类型将是{{1}类型的子类型}(或Foo
本身)。
例如,如果您有Foo
,则可以传递void doIt1( List< ? extends Mammal> l ){}
,List<Human>
,List<Primate>
或List<Simian>
。
然而,当使用List<Mammal>
时,你不知道什么是安全的。
考虑一下:
? extends
这显然不安全!我本可以void addElephant( List< ? extends Mammal> l ){
l.add( new Elephant() ); //wrong!
}
传递List<Human>
,现在我的l
列表中有一个Human
!
另一方面,您有 Elephant
,其中super
表示容器可以使用? super Foo
。
对于Foo
,您可以传入void doIt2( List< ? extends Human> l ){}
,List<Human>
,List<Primate>
,List<Simian>
或List<Mammal>
。
List<Object>
这很好,但你不能保证你将从容器中取出什么。
void ( List< ? super Human> l ){
l.add( new Human() );
}
这是因为如果void ( List< ? super Human> l ){
Human h = l.get(0); //wrong!
}
真的是l
,它可能混合了List<Primate>
和Human
,并且无法保证第一个元素将是Gorilla
。
为此,您将获得首字母缩写Human
=&#34; [a] P roducer ** E xtends,[但a] C onsumer S upers&#34;。
如果你的容器正在将对象返回给某个方法(例如P.E.C.S
),那么你就是&#34;生成&#34; (所以使用get
),否则如果你接受一个容器的元素(例如extends
),容器就会消耗掉#34;对象如此使用&#34; super&#34;。 ( Nb:要记住PECS的棘手部分是它来自容器的观点,而不是调用代码!)。
如果你想 生成和消费你,你需要有一个具体的类型列表add
,你可以在其中添加List<Primate>
并检索{{1 }}第
另见: