Java 二级类型参数的延迟绑定
这是一个有点做作的复制案例,但请容忍我 假设您希望为能够使用以下行为向不同类型的列表添加项的类创建加法器接口:Java 二级类型参数的延迟绑定,java,generics,higher-kinded-types,Java,Generics,Higher Kinded Types,这是一个有点做作的复制案例,但请容忍我 假设您希望为能够使用以下行为向不同类型的列表添加项的类创建加法器接口: // Can add items to any type of array list. Adder<ArrayList> arrayListAdder = ...; // Ok. Right list type and item types match. arrayListAdder.add(new ArrayList<String>(), "test"); /
// Can add items to any type of array list.
Adder<ArrayList> arrayListAdder = ...;
// Ok. Right list type and item types match.
arrayListAdder.add(new ArrayList<String>(), "test");
// Ok. Right list type and item types match.
arrayListAdder.add(new ArrayList<Integer>(), 3);
// Compile error. Item types do not match.
arrayListAdder.add(new ArrayList<Integer>(), "test");
// Compile error. Wrong list type although item types match.
arrayListAdder.add(new LinkedList<String>(), "test");
//可以将项添加到任何类型的数组列表中。
加法器arrayListAdder=。。。;
//嗯。右列表类型和项目类型匹配。
add(新的ArrayList(),“test”);
//嗯。右列表类型和项目类型匹配。
add(新的ArrayList(),3);
//编译错误。项目类型不匹配。
add(新的ArrayList(),“test”);
//编译错误。虽然项目类型匹配,但列表类型错误。
add(newlinkedlist(),“test”);
换句话说,我想让界面说:
特定列表类型的加法器有一个“add”方法。此方法接受两个参数。
第一个是此特定类型的列表,其中包含类型为T的项。
第二个参数是T类型的项。该方法将该项添加到列表中
我尝试了以下不同的解决方案:
interface Adder<L extends List<?>> {
<T> void add(L<T> list, T t);
}
接口加法器
我很确定这在Java中是不可能的。我不知道这是否是你的意思,但是
public interface Adder<T, L extends List<T>> {
void add(L list, T t);
}
公共接口加法器{
无效添加(L列表,T);
}
听起来像是一个选项这将编译,但它不会强制执行您的规则
interface Adder<L extends List<?>> {
<T> void add(L list, T t);
}
接口加法器经过多次重写后,这是否符合您的要求
interface Adder<L extends Collection<S>, S> {
public S add(L c, S s);
}
class AdderImpl <L extends Collection<S>, S> implements Adder<L, S> {
public S add(L c, S s) {
c.add(s);
return s;
}
}
public void test() {
Adder<List<String>, String> listAdder = new AdderImpl<List<String>, String>();
Adder<Set<String>, String> setAdder = new AdderImpl<Set<String>, String>();
listAdder.add(new ArrayList<String>(), "Hello");
// setAdder.add(new ArrayList<String>(), "Hello"); Complier error - can't use List on SetAdder
setAdder.add(new HashSet<String>(), "Hello");
}
接口加法器{
公共服务部增补(信用证、信用证);
}
类AdderImpl实现加法器{
公共服务添加(L c,S){
c、 添加(s);
返回s;
}
}
公开无效测试(){
Adder listAdder=新的AdderImpl();
加法器setAdder=新的AdderImpl();
adder.add(newarraylist(),“Hello”);
//setAdder.add(new ArrayList(),“Hello”);编译器错误-无法在setAdder上使用列表
add(newhashset(),“Hello”);
}
为了缩短我的答案,我给出了一个使用类的示例:
class Adder<T, L extends List<T>> {
void add(L list, T t) { /* your logic */}
void test() {
new Adder<Integer, ArrayList<Integer>>().add(new ArrayList<Integer>(), new Integer(1));
}
}
类加法器{
void add(L list,T){/*您的逻辑*/}
无效测试(){
新增加法器().add(新增ArrayList(),新增整数(1));
}
}
这样行吗
import java.util.List;
import java.util.ArrayList;
interface Adder<K> {
void add(List<K> l, K k1);
};
class IntegerListAdder implements Adder<Integer> {
public void add(List<Integer> l, Integer i) {
l.add(i);
}
}
class StringListAdder implements Adder<String> {
public void add(List<String> l, String i) {
l.add(i);
}
}
public class AdderTest {
public static void main(String... argv) {
IntegerListAdder ila = new IntegerListAdder();
List<Integer> l = new ArrayList<Integer>();
ila.add(l,1);
ila.add(l,2);
System.out.println(l);
StringListAdder sla = new StringListAdder();
List<String> s = new ArrayList<String>();
sla.add(s,"One");
sla.add(s,"Two");
System.out.println(s);
}
}
import java.util.List;
导入java.util.ArrayList;
接口加法器{
无效添加(列表l、K和k1);
};
类IntegerListAdder实现加法器{
公共空添加(列表l,整数i){
l、 加(i);
}
}
类StringListAdder实现加法器{
公共无效添加(列表l,字符串i){
l、 加(i);
}
}
公共类加法器{
公共静态void main(字符串…argv){
IntegerListAdder ila=新IntegerListAdder();
列表l=新的ArrayList();
ila.添加(l,1);
ila.添加(1,2);
系统输出打印LN(l);
StringListAdder sla=新StringListAdder();
列表s=新的ArrayList();
sla.增加“一个”;
sla.增加“两个”;
系统输出打印项次;
}
}
它编译和运行良好。不幸的是,Java泛型不支持您正在寻找的功能。最接近的方法是在方法中要求列表,而不是使用类型L。例如:
interface Adder
{
<T> void add(List<T> list, T t);
}
接口加法器
{
无效添加(列表,T);
}
但这并不是您要寻找的,因此下一个最接近的方法是将列表声明移动到方法体中,但是这也是不正确的:
interface Adder
{
<T, L extends List<T>> void add(List<T> list, T t);
}
接口加法器
{
无效添加(列表,T);
}
问题是您正试图将泛型类型分配给任意类型(L),而L可能不会被泛型化,尽管强制L extends List
。在编译时或运行时强制检查列表类型没有好方法。是否考虑过向下拉集合参数?也就是说,到方法级别。这样,您就不会有带有公共接口的单独加法器,而只有一个全局加法器来处理所有情况。考虑这一点:
class Adder {
public <T, W extends Wrapped<T>> void add(ArrayList<W> list, W w) {
System.out.println("list.add " + w);
w.commonWrappedMethod();
list.add(w);
}
public <T, W extends Wrapped<T>> void add(HashSet<W> set, W w) {
System.out.println("set.add " + w);
w.commonWrappedMethod();
set.add(w);
}
// For all other collections
public <T, W extends Wrapped<T>> void add(Collection<W> col, W w) {
System.out.println("col.add " + w);
w.commonWrappedMethod();
col.add(w);
}
}
您将不再需要(或者实际上能够有意义地使用)加法器接口,您只需传递/使用单个对象。或者更好的方法是,将方法设置为静态并将该类用作实用程序类,或者将该类设置为单例并始终引用一个实例
完整示例可用。哦。。。似乎您不希望在加法器的实现程序中取消add方法generic和List参数的绑定?那么我的代码不起作用了?或者它解决了您的问题吗?我相信问题指出列表的类型参数希望在调用方法之前取消分配,这意味着它不能放入接口中。不幸的是,Java泛型没有这种功能。@Irfy:Spot-on。虽然我同意这似乎是合理的,但不幸的是,这并不能解决我的具体问题。也许有另一种解决问题的方法。你到底想解决什么问题?换句话说,为什么这种方法看起来是必要的?@Irfy:我试图定义处理包装类型的通用方法。我有几种包装类型,所以我可以有包装1和包装2。我有不同的包装和1和2打开包装。它们应该共享一个接口,以便链式包装逻辑不知道特定的包装类型。我遇到了一个问题,WrapperType1必须有一个方法,该方法将Wrapped1用于所有T并实现Wrapper。至少这是要点。与前一个重复。我相信他希望在实现Adder
时使用未绑定的集合类型进行参数化,并在调用add
时绑定集合类型。与你在那里做的相反。我想。这个并没有强制容器类型。这个接口需要为特定的容器和项目类型制作一个加法器。我想要一个用于特定容器类型的加法器,但用于所有项目类型。他想要ArrayListAdder
,SomeOtherCollectionAdder
,等等,然后能够将任何类型添加到适当的列表中,每个类有一个add
函数。我想。谢谢你直截了当的回答
interface Adder
{
<T> void add(List<T> list, T t);
}
interface Adder
{
<T, L extends List<T>> void add(List<T> list, T t);
}
class Adder {
public <T, W extends Wrapped<T>> void add(ArrayList<W> list, W w) {
System.out.println("list.add " + w);
w.commonWrappedMethod();
list.add(w);
}
public <T, W extends Wrapped<T>> void add(HashSet<W> set, W w) {
System.out.println("set.add " + w);
w.commonWrappedMethod();
set.add(w);
}
// For all other collections
public <T, W extends Wrapped<T>> void add(Collection<W> col, W w) {
System.out.println("col.add " + w);
w.commonWrappedMethod();
col.add(w);
}
}
ArrayList<Wrapped1<Integer>> w1il = new ArrayList<Wrapped1<Integer>>();
HashSet<Wrapped1<String>> w1ss = new HashSet<Wrapped1<String>>();
Vector<Wrapped2<String>> w2sv = new Vector<Wrapped2<String>>();
Adder adder = new Adder();
adder.add(w1il, new Wrapped1<Integer>(1));
adder.add(w1ss, new Wrapped1<String>("six"));
adder.add(w2sv, new Wrapped2<String>("twelve"));