(要清除问题,'T'指的是在Class中声明的类型参数)
举个例子,请查看以下应用程序:
public class TestClass {
interface InterfaceA{}
interface InterfaceB{}
interface InterfaceC{}
class ClassA implements InterfaceA, InterfaceB, InterfaceC{}
public static void main(String[] args){
Class<? super ClassA> superClass1 = ClassA.class;
Class<? super ClassA> superclass2 = InterfaceA.class;
Class<? super ClassA> superclass3 = InterfaceB.class;
Class<? super ClassA> superclass4 = InterfaceC.class;
for(Class<?> clazz : ClassA.class.getInterfaces()){
System.out.println(clazz.getName());
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出是人们所期望的:
TestClass$InterfaceA
TestClass$InterfaceB
TestClass$InterfaceC
Run Code Online (Sandbox Code Playgroud)
因此,基于上面的这个例子,我们可以看到编译器认识到InterfaceA 确实符合通配符的边界,所有其他接口也是如此.
直观地说,我希望以下是安全的,但它不是:
Class<? super ClassA>[] interfaces = ClassA.class.getInterfaces();
Run Code Online (Sandbox Code Playgroud)
编译器发出警告,因为签名表示它返回Class; 但是,Class的javadoc声明如下:
如果此对象表示类,则返回值是一个数组,其中包含表示该类实现的所有接口的对象.
'这个对象'在我们的例子中指的是ClassA.基于此声明,如果我们致电:
ClassA.class.getInterfaces()
Run Code Online (Sandbox Code Playgroud)
然后我们从逻辑上知道Class<?>返回数组中的每一个都将包含对超类型的引用ClassA …
我知道Stream.concat存在(doc)来连接两个流.但是,我遇到了需要在现有流中添加"更多"项目,然后继续处理它的情况.在这种情况下,我本来希望能够将以下方法联系在一起:
getStream(someArg)
.map(Arg::getFoo)
.concat(someOtherStreamOfFoos) // Or append, or...
.map(...)
Run Code Online (Sandbox Code Playgroud)
但是,不存在这种实例级可链接append/concat方法.
这不是一个问题,要求解决这个问题,或更优雅的方法(虽然我当然会感激任何其他观点!).相反,我问的是导致这一决定的设计因素.我相信,Stream界面是由一些非常聪明的人设计的,他们都知道最小惊讶原则 - 所以,我必须假设他们决定省略这个(对我来说)直观明显的方法,这意味着该方法是一个反模式,或由于某些技术限制而无法实现.我很想知道原因.
该toArray方法(可以接在执行java.util.ArrayList)如下:
class ArrayList<E> ....{
public <T> T[] toArray(T[] a){
if(a.length < size)
return (T[]) Arrays.copyof(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if(a.length > size)
a[size] = null;
return a;
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道我们可以使用<E>而不是<T>在这种情况下吗?喜欢
public E[] toArray(E[] a){
if(a.length < size)
return (E[]) Arrays.copyof(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if(a.length > size)
a[size] = null;
return a;
}
Run Code Online (Sandbox Code Playgroud)
由于ArrayList类iteself已经是通用的<E>,所以我们可以使用它而不是新的泛型类型<T>吗?
我将尝试在以下简化示例中说明我的问题:
public class DataHolder<T> {
private final T myValue;
public DataHolder(T value) {
myValue = value;
}
public T get() {
return myValue;
}
// Won't compile
public <R> DataHolder<R super T> firstNotNull(DataHolder<? extends R> other) {
return new DataHolder<R>(myValue != null ? myValue : other.myValue); }
public static <R> DataHolder<R> selectFirstNotNull(DataHolder<? extends R> first,
DataHolder<? extends R> second) {
return new DataHolder<R>(first.myValue != null ? first.myValue : second.myValue);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我想写泛型方法firstNotNull返回DataHolder的类型参数的共同参数化父T的this和 …
正如Bounding泛型中使用'super'关键字所讨论的那样,当涉及到方法泛型的下限时,Java类型系统被破坏/不完整.由于Optional现在是JDK的一部分,我开始更多地使用它,并且Guava遇到的问题与他的可选性开始变得困难.我提出了一个体面的工作,但我不确定它是否安全.首先,让我设置一个例子:
public class A {}
public class B extends A {}
Run Code Online (Sandbox Code Playgroud)
我希望能够声明一个方法,如:
public class Cache {
private final Map<String, B> cache;
public <T super B> Optional<T> find(String s) {
return Optional<T>.ofNullable(cache.get(s));
}
}
Run Code Online (Sandbox Code Playgroud)
以下两项工作:
A a = cache.find("A").orElse(new A())
B b = cache.find("B").orElse(new B())
Run Code Online (Sandbox Code Playgroud)
作为一种解决方法,我有一个静态实用方法如下:
public static <S, T extends S> Optional<S> convertOptional(Optional<T> optional) {
return (Optional<S>)optional;
}
Run Code Online (Sandbox Code Playgroud)
所以我的最后一个问题是,这是上述"理想"代码的类型安全吗?
A a = OptionalUtil.<A,B>convertOptional(cache.find("A")).orElse(new A());
Run Code Online (Sandbox Code Playgroud) 我对以下两个方法声明感到困惑:
private <U, T extends U> T funWorks(T child, U parent) {
// No compilation errors
}
private <T, U super T> T funNotWorks(T child, U parent) {
// compilation errors
}
Run Code Online (Sandbox Code Playgroud)
以上两者都不应该有效吗?比喻 如果U是T的父,那么T是U的子.那为什么第二个会出现编译错误?
编辑::我认为,T extends T和T super T都是有效的.对 ?
得到一个Map<String, ? extends Map<String, Integer>> mapOfMaps变量。
Map<String, Integer> result = mapOfMaps.get("aaa");
Run Code Online (Sandbox Code Playgroud)
有效,但是
Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",Collections.emptyMap());
Run Code Online (Sandbox Code Playgroud)
说
类型 Map<String,capture#1-of ? 中的方法 getOrDefault(Object, capture#1-of ? extends Map<String,Integer>) extends Map<String,Integer>> 不适用于参数 (String, Map<String,Integer>)
同样适用于
Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",Collections.<String,Integer>emptyMap());
Run Code Online (Sandbox Code Playgroud)
或者
Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",(Map<String,Integer>)Collections.EMPTY_MAP);
Run Code Online (Sandbox Code Playgroud)
甚至
Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",new HashMap<String, Integer>());
Run Code Online (Sandbox Code Playgroud)
有没有办法像这样使用 getOrDefault 或者我必须使用笨重的方式?
Map<String, Integer> result = mapOfMaps.get("aaa");
if( result == null ) {
result = Collections.emptyMap();
}
Run Code Online (Sandbox Code Playgroud) 因此,我正在阅读泛型,以便重新熟悉这些概念,特别是在涉及通配符的情况下,因为我几乎没有使用它们或碰到它们.从我所做的阅读中我无法理解为什么他们使用通配符.我不断遇到的一个例子如下.
void printCollection( Collection<?> c ) {
for (Object o : c){
System.out.println(o);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么你不写这个:
<T> void printCollection( Collection<T> c ) {
for(T o : c) {
System.out.println(o);
}
}
Run Code Online (Sandbox Code Playgroud)
来自oracle网站的另一个例子:
public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
Run Code Online (Sandbox Code Playgroud)
为什么这不是写的
public static <T extends Number> double sumOfList(List<T> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
} …Run Code Online (Sandbox Code Playgroud) 我有类似的东西:
interface Foo<T> {
//... lines [0,45]...
/*line 46*/ <R, X super T&R> List<X> weave(R value);
//...
}
Run Code Online (Sandbox Code Playgroud)
但是IntelliJ正在报道:
有什么问题?我不允许将名字绑定到下限吗?或者我只允许R&X在上限中使用表达式?
把它改成
interface Foo<T> {
//... lines [0,45]...
/*line 46*/ <R> List<? super T&R> weave(R value);
//...
}
Run Code Online (Sandbox Code Playgroud)
产量
我正在玩Java中的泛型,我发现了一些奇怪的东西:
以下编译:
public static <A, B extends A> B reduce(Function2<A, A, B> func)
{
//code doesn't matter
}
Run Code Online (Sandbox Code Playgroud)
但以下不是:
public static <A, B super A> B reduce(Function2<A, A, B> func)
{
//code doesn't matter
}
Run Code Online (Sandbox Code Playgroud)
在我看来上面是完全有效的(毕竟,这几乎是Scala集合中reduce方法的签名).
为什么Java不允许逆变返回类型,特别是在这种情况下,因为将推断返回(通过Function2的第三个参数)?
我在项目中遇到了一个奇怪的问题.现在我简化了问题并在这里写了一个小例子来说明我的困惑:
public class Question {
class Q1 {}
class Q2 extends Q1 {}
interface In<T> {
void f(T t);
}
List<Q2> list;
void f(In<? super List<? super Q2>> in) {
in.f(list);
}
static void g() {
Question question = new Question();
In<Collection<Q1>> in1 = new In<Collection<Q1>>() {
@Override
public void f(Collection<Q1> o) {}
};
In<List<Q2>> in2 = new In<List<Q2>>() {
@Override
public void f(List<Q2> o) {}
};
question.f(in1); //Error!
question.f(in2); //Error!
}
}
Run Code Online (Sandbox Code Playgroud)
我的目标是使该方法f(In<? super List<? super Q2>>)更灵活.我可以通过 …
java ×11
generics ×9
arraylist ×1
collections ×1
interface ×1
java-8 ×1
java-stream ×1
super ×1
syntax-error ×1