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

时间:2015-02-01 23:58:25

标签: java generics

我的Android应用中有一个适配器,我想把它变成Generic。

Basiclly适配器看起来像这样:

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%通用?

已添加:在您回答后我将其更改为支持返回通用类型:

   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>是相同的类型。

2 个答案:

答案 0 :(得分:1)

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

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

例如,通过潜入,你现在看看items = (C)myFragment.getData()。由于fragment仍为DataTypaA类型,因此可能其getData()方法不返回泛型类型。有些东西必须改变。

你有很多工作要做,所以要重复自己 - 把它作为重构练习,一步一步地进行。

  1. 获取非泛型类型进行编译。
  2. myFragment更改为A myFragment并声明类型参数<A extends DataTypaA。看看在继续之前需要做些什么才能进行编译。
  3. 现在看看将data移到SparseArray<B> data。据推测,这需要SparseArray<T>,其中TDataTypeB或其子类型。这意味着您将需要B上基于通配符的界限。像B extends SparseArray<? extends DataTypeB>
  4. 之类的东西
  5. 现在看看items。您知道它是从新的泛型类型变量A extends DataTypeA返回的,因此DataTypeA必须是通用的,并且具有从getData返回的泛型类型变量。假设它被DataTypeA<T extends DataTypeC>声明为public T getData() { ... }
  6. 现在,您的类型参数部分将更改为:

    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 {
    }
    

答案 1 :(得分:0)

当“泛化”类时,您应该用通用类替换所有通用类型的实例:DataTypaA变为A等。

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

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

Java Tutorial on generics有助于获取更多信息。