英文:
How to give hint in Java that two type parameters are actually the same type?
问题
<!-- language-all: lang-java -->
我正在使用AOSP的[`CaptureRequest`][1]及其相关的[`CaptureRequest.Builder`][2]类,尽管情况非常不同寻常,但我需要将现有的`CaptureRequest`实例的设置键值复制到新的`CaptureRequest.Builder`<sup>1</sup>实例中。
我想要运行的基本代码如下:
for(CaptureRequest.Key<?> key : request.getKeys()) {
builder.set(key, request.get(key));
}
...其中`CaptureRequest.Builder.set()`函数定义为`<T> void set(Key<T> key, T value)`,而`CaptureRequest.get()`定义为`<T> T get(Key<T> key)`。
但这会导致编译器报错,错误信息如下:
Source.java:2: error: method set in class Builder cannot be applied to given types;
builder.set(key, request.get(key));
^
required: Key<T>,T
found: Key<CAP#1>,CAP#2
reason: inferred type does not conform to lower bound(s)
inferred: CAP#1
lower bound(s): Object
where T is a type-variable:
T extends Object declared in method <T>set(Key<T>,T)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ?
CAP#2 extends Object from capture of ?
如果我正确解释了错误信息,它试图表达的是无法将两个函数的`<T>`关联为相同的`T`。为了给它一个提示,表明它是相同的`T`,我创建了一些辅助函数,应该可以明确它是相同的`T`,因此我有了这个:
private static <T> T getKeyValue(CaptureRequest request, CaptureRequest.Key<T> key) {
return (T)request.<T>get(key);
}
private static <T> void setKeyValue(CaptureRequest.Builder builder, CaptureRequest.Key<T> key) {
builder.<T>set(key, (T)MyClass.<T>getKeyValue(key));
}
.....
for(CaptureRequest.Key<?> key : request.getKeys()) {
setKeyValue(builder, key);
}
这无法使Java编译器满意,它会输出与先前错误非常相似的错误:
Source.java:6: error: method getKeyValue in class MyClass cannot be applied to given types;
builder.<T>set(key, (T)MyClass.<T>getKeyValue(key));
^
required: CaptureRequest,Key<T#1>
found: Key<T#2>
reason: actual and formal argument lists differ in length
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>getKeyValue(CaptureRequest,Key<T#1>)
T#2 extends Object declared in method <T#2>setKeyValue(Builder,Key<T#2>)
如何以合理的方式执行这个[本应该简单的]键值复制?
----------
<sup>1</sup> 是的,我知道这很奇怪,与通常的API使用有些不同,因此“不寻常”。背景是已构建的请求(超出库的范围)正在通过需要使用自己的阴影请求对请求进行处理,大部分情况下模仿原始请求,但稍作修改,而且该库无法访问原始构建器以构建阴影同级请求。是的,这很奇怪,超出了这个问题的范围。这个问题实际上是关于Java的模板方法和明显的编译错误。
[1]: https://developer.android.com/reference/android/hardware/camera2/CaptureRequest
[2]: https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.Builder
英文:
<!-- language-all: lang-java -->
I'm working with AOSP's CaptureRequest
and its associated CaptureRequest.Builder
classes, and have (albeit very unusual case of) a need to copy settings key-values from an existing instance of CaptureRequest
to a new instance of CaptureRequest.Builder
<sup>1</sup>.
The basic code here that I want to run is the following:
for(CaptureRequest.Key<?> key : request.getKeys()) {
builder.set(key, request.get(key));
}
... where CaptureRequest.Builder.set()
function is defined as <T> void set(Key<T> key, T value)
, and CaptureRequest.get()
is defined as <T> T get(Key<T> key)
.
But that makes compiler barf with the following error:
Source.java:2: error: method set in class Builder cannot be applied to given types;
builder.set(key, request.get(key));
^
required: Key<T>,T
found: Key<CAP#1>,CAP#2
reason: inferred type does not conform to lower bound(s)
inferred: CAP#1
lower bound(s): Object
where T is a type-variable:
T extends Object declared in method <T>set(Key<T>,T)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ?
CAP#2 extends Object from capture of ?
If I'm interpreting the error correctly, it's trying to say that it cannot relate <T>
s of two functions as being the same one T
. So to give it a hint that it's the same T
, I created some helper functions that should make it obvious that it's the same T
, and so I have this:
private static <T> T getKeyValue(CaptureRequest request, CaptureRequest.Key<T> key) {
return (T)request.<T>get(key);
}
private static <T> void setKeyValue(CaptureRequest.Builder builder, CaptureRequest.Key<T> key) {
builder.<T>set(key, (T)MyClass.<T>getKeyValue(key));
}
.....
for(CaptureRequest.Key<?> key : request.getKeys()) {
setKeyValue(builder, key);
}
This fails to pacify the Java compiler and it spits out very similar error to the previous one:
Source.java:6: error: method getKeyValue in class MyClass cannot be applied to given types;
builder.<T>set(key, (T)MyClass.<T>getKeyValue(key));
^
required: CaptureRequest,Key<T#1>
found: Key<T#2>
reason: actual and formal argument lists differ in length
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>getKeyValue(CaptureRequest,Key<T#1>)
T#2 extends Object declared in method <T#2>setKeyValue(Builder,Key<T#2>)
How can I perform this [what should be simple] copy of key-values in a sane way?
<sup>1</sup> Yes, I know that's weird and a bit backwards from typical use of API, hence "unusual". Context is that already built request (beyond library's scope) is percolating through a library that needs to shadow request with its own, mostly mimicking the original, but slightly amended, and said library doesn't have access to original builder to build the shadow sibling request. Yes, it's weird and is beyond the scope of this question. This question is really about Java's template methods and apparent compilation error.
答案1
得分: 1
为什么不只是:
builder.set((CaptureRequest.Key<Object>)key, request.get(key));
我很确定它应该可以工作。
英文:
Why not just:
builder.set((CaptureRequest.Key<Object>)key, request.get(key));
Pretty sure it should work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论