【问题标题】:Convert custom adapter to use generics in Java将自定义适配器转换为在 Java 中使用泛型
【发布时间】:2015-02-01 23:58:25
【问题描述】:

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

添加:在您回答后,我将其更改为支持返回泛型类型:

   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
            }

}

我收到编译错误... 当我运行它时,当然&lt;T&gt;&lt;C&gt; 是同一类型。

【问题讨论】:

  • 为什么要让它通用?你能提供一个用例吗?目前尚不清楚您要达到的目标(或至少对我而言;)):data 的类型为 DataTypeBSparseArray&lt;DataTypeB&gt;
  • @Matthieu dataB 类型,这是一个错误,谢谢...这个适配器有一些逻辑,我想把它的使用交给其他类,他们只是需要设置类型&lt;A,B,C&gt;,而不是复制代码和创建新的适配器。
  • Alex,你应该在发布之前确保你的代码有意义。您的非泛型代码根本无法编译,因此很难提出任何明智的建议。

标签: java generics


【解决方案1】:

第一个问题是您的非泛型代码无法编译。您有一个字段DataTypeB data;,然后将SparseArray&lt;DataTypeB&gt; 分配给该字段。另外,setData 根本无法编译。

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

例如,您现在可以深入了解items = (C)myFragment.getData()。由于fragment 仍然是DataTypaA 类型,那么它的getData() 方法可能不会返回泛型类型。有些事情将不得不改变。

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

  1. 让您的非泛型类型进行编译。
  2. myFragment 更改为A myFragment 并声明类型参数&lt;A extends DataTypaA。在继续之前,看看需要做什么才能编译它。
  3. 现在看看将data 移动为SparseArray&lt;B&gt; data。大概这需要SparseArray&lt;T&gt;,其中TDataTypeB,或其子类型。这意味着您将需要在B 上使用基于通配符的绑定。类似B extends SparseArray&lt;? extends DataTypeB&gt;
  4. 现在查看items。你知道它是从你的新泛型类型变量A extends DataTypeA 返回的,所以DataTypeA 需要是泛型的并且有一个从getData 返回的泛型类型变量。假设它被声明为DataTypeA&lt;T extends DataTypeC&gt;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&lt;B&gt; 的假设也可能不正确——但您的代码目前无法编译,所以我无法确定。最终实现可能类似于:

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

【讨论】:

  • 感谢您的回答。我用类型修复了语法错误,它实际上不编译,我写它是为了大创意。我不使用&lt;T extends...&gt; ,因为它应该适用于没有类似内容的类型。我的问题是,当我初始化一个应该返回 &lt;T&gt; 类型的参数时,就像在 public B getItem(int position) { return data.get(position); 中一样,我在覆盖时出现错误,如果我更改名称,那么它可以接受。我也对getCount() 有疑问 - 我从 Android 类扩展了它,所以我不能按照你的建议用抽象重写它}
  • @AlexOpent。对于getCount,不需要使用abstract - 我只需要伪造这些类,而不是加载到Android 库中。 extends 是可选的 - 这取决于您需要如何使用类型参数。
  • @AlexOpent。对于您关于public B getItem(int position) { return data.get(position); 的其他问题,您应该提出一个关于覆盖非泛型超类型方法的新问题。
  • 好的,我会问一个新问题,它有什么不同吗?所以基本上你说的是如果我希望下一行可以工作:items = myFragment.getItems ();(其中itemsC类型)我需要重写getItems()所以除了返回类型C之外它今天在做什么,它应该还返回该行的泛型类型?
  • @AlexOpent。这是一种选择,还有其他选择。这本身就是一个问题。
【解决方案2】:

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

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

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

Java Tutorial on generics 可获取更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多