我的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
参数并且我传递参数类型C
(data.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>
是相同的类型。
答案 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()
方法不返回泛型类型。有些东西必须改变。
你有很多工作要做,所以要重复自己 - 把它作为重构练习,一步一步地进行。
myFragment
更改为A myFragment
并声明类型参数<A extends DataTypaA
。看看在继续之前需要做些什么才能进行编译。data
移到SparseArray<B> data
。据推测,这需要SparseArray<T>
,其中T
是DataTypeB
或其子类型。这意味着您将需要B
上基于通配符的界限。像B extends SparseArray<? extends DataTypeB>
items
。您知道它是从新的泛型类型变量A extends DataTypeA
返回的,因此DataTypeA
必须是通用的,并且具有从getData
返回的泛型类型变量。假设它被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
。然后,这会更改myAdapter
和DataTypeA
上的类型参数部分。我对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有助于获取更多信息。