在 Java 中转换自定义适配器以使用泛型

Convert custom adapter to use generics in Java

我的 Android 应用程序中有一个适配器,我想将其设为通用。

适配器基本上是这样的:

public class myAdapter extends FragmentStatePagerAdapter {

DataTypaA myFragment;
DataTypeB data;
DataTypeC items;

public myAdapter(FragmentManager fm, DataTypaA fragment) {
        data = new SparseArray<DataTypeB>();
        myFragment = fragment;
        items = myFragment.getData();
    }

    public DataTypeB getItem(int position) {
        return data.get(position);
    }

    @Override
    public int getCount() {
        return items.getList().size();
    }


public void setData () {

items = myFragment.getItems ()  //getItems return DataTypeC
data.setTheData (items) 
}
}

我将其更改为通用

public class myAdapter <A,B,C> extends FragmentStatePagerAdapter {

A myFragment;
B data;
C items;

public myAdapter(FragmentManager fm, A fragment) {
        data = new SparseArray<B>();
        myFragment = fragment;
        items =  (C) myFragment.getData();
    }

    public B getItem(int position) {
        return data.get(position);
    }

    @Override
    public int getCount() {
        return items.getList().size();
    }


public void setData () {

items = myFragment.getItems ()  //getItems return DataTypeC
data.setTheData (items) 
}
}

但是我得到了不同的错误,当方法应该得到 DataTypeC 参数并且我传递给它的参数类型 Cdata.setTheData (items) )实际上是类型 DataTypeC编译器建议将 C 转换为类型 DataTypeC。在 getCount() 中,我也有错误建议将 items 转换为 DataTypeC

例如,当我尝试重写 getItem 时出现错误,但是当我用其他名称创建相同的方法时它会编译。

//Error - "The return type is incompatible with FragmentStatePagerAdapter.getItem(int)"
@Override
    public B getItem(int position) {
        return (B) data.get(position);
    }

//compiles
    public B getItemTest(int position) {
        return data.get(position);
    }

关于如何修复它以使其 100% 通用的任何想法?

ADDED:在你回答后我将其更改为支持通用类型的 return:

   public class TypeA <T> {
    private T mData;

        public T getData() { return mData;; }
    }



    public class myAdapter <A,B,C> extends FragmentStatePagerAdapter {

        A myFragment;
        B data;
        C items;

        public myAdapter(FragmentManager fm, A fragment) {
                data = new SparseArray<B>();
                myFragment = fragment;
                items = myFragment.getData(); //Error - The method getData() is undefined for the type T
            }

}

我遇到编译错误... 当我 运行 它当然 <T><C> 是同一类型。

当 "genericizing" class 时,您应该将泛型类型的所有实例替换为它们的泛型:DataTypaA 变为 A,等等

您还需要确保您在其他对象(如 fragment.getData())上调用的方法中的 return 类型与泛型兼容。为此,您可以指示泛型类型扩展了一个已知的 class:

public class MyAdapter<A extends MyData,B extends MyData,...>

Java Tutorial on generics 可以提供更多信息。

第一个问题是您的非通用代码无法编译。您有一个字段 DataTypeB data;,然后您将 SparseArray<DataTypeB> 分配给该字段。此外,setData 根本无法编译。

忽略这个...您已经声明了类型参数 A, B, C 并更改了您的实例字段类型,但您仍然尝试在构造函数中将 DataTypaA 分配给 A myFragment,并且SparseArray<DataTypeB>B data。当您将代码迁移到泛型时,您需要像重构一样处理它 - 一次一个步骤。

例如,像现在这样深入研究 items = (C)myFragment.getData()。由于 fragment 仍然是 DataTypaA 类型,因此可以推测它的 getData() 方法不是 return 泛型类型。有些事情将不得不改变。

你有很多工作要做,所以重复一遍 - 将此视为重构练习并逐步进行。

  1. 获取要编译的非泛型类型。
  2. myFragment 更改为 A myFragment 并声明类型参数 <A extends DataTypaA。在继续之前看看需要做什么才能编译它。
  3. 现在看看移动 data 成为 SparseArray<B> data。据推测,这需要一个 SparseArray<T>,其中 T 是一个 DataTypeB,或其子类型。这意味着您将需要在 B 上进行基于通配符的绑定。像 B extends SparseArray<? extends DataTypeB>
  4. 现在看items。您知道它是从您的新泛型类型变量 A extends DataTypeA 中 return 编辑的,因此 DataTypeA 需要是泛型的并且具有从 getData 中编辑的泛型类型变量 return ].假设它被声明为 DataTypeA<T extends DataTypeC>public T getData() { ... }

所以现在您的类型参数部分更改为:

class DataTypaA<T extends DataTypeC>
...
class myAdapter <A extends DataTypaA<C>, 
                 B extends SparseArray<? extends DataTypeB>, 
                 C extends DataTypeC> 
    extends FragmentStatePagerAdapter { 
    A myFragment;
    SparseArray<B> data;
    C items;
...

鉴于您发布的代码,很难对此做得太过分 - 并非所有 类 和信息都在那里,但这是您必须遵循的过程。

例如:您可能不需要将 C 限制为 DataTypeC。然后,这会更改 myAdapterDataTypeA 上的类型参数部分。我对 SparseArray<B> 的假设也可能不正确 - 但您的代码目前无法编译,所以我无法判断。最终实现 可能 是这样的:

class myAdapter <A extends DataTypaA<C>, 
                 B extends SparseArray<? extends DataTypeB, 
                                       ? extends DataTypeC>, 
                 C extends DataTypeC> 
    extends FragmentStatePagerAdapter {

    A myFragment;
    SparseArray<B, C> data;
    C items;

    public myAdapter(FragmentManager fm, A fragment) {
        data = new SparseArray<B, C>();
        myFragment = fragment;
        items =  myFragment.getData();
    }

    public B getItem(int position) {
        return data.get(position);
    }

    @Override
    public int getCount() {
        return items.getList().size();
    }   

    public void setData () {
        items = myFragment.getItems ();  //getItems return DataTypeC
        data.setTheData(items);
    }
}

为此我使用了假的 类:

class DataTypaA<T extends DataTypeC> {
    public T getData() { return null; }
    public T getItems() { return null; }
}
class SparseArray<T, S> {
    public T get(int foo) { return null; }
    public void setTheData(S items){}
}
class DataTypeB {
}
class DataTypeC {
    // do NOT use the raw type List - just done to get your code to compile
    public List getList() { return null; }
}
abstract class FragmentStatePagerAdapter {
    public abstract int getCount();
}
class FragmentManager {
}