简体   繁体   English

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

[英]Convert custom adapter to use generics in Java

I have a Adapter in my Android app and I want to make it Generic. 我的Android应用程序中有一个适配器,我想使其通用。

Basiclly the Adapter looks like that: 适配器基本上是这样的:

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

I changed it to generic 我将其更改为通用

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

but I'm getting different errors, when methods should get DataTypeC parameter and I passing it parameter type C ( data.setTheData (items) ) that is actually type DataTypeC the compiler suggest to cast C to type DataTypeC . 但是我遇到了不同的错误,当方法应该获取DataTypeC参数并向其传递参数类型Cdata.setTheData (items) ),而该参数类型实际上是DataTypeC ,编译器建议将C转换为DataTypeC and in getCount() I have also error suggesting to convert items to DataTypeC . getCount()我也有错误建议将items转换为DataTypeC

for example when I try to override getItem I getting mistakes, but when I create the same method with other name it compiles. 例如,当我尝试覆盖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);
    }

Any ideas how to fix it so it will be 100% generic? 任何想法如何解决它,使其成为100%通用的?

ADDED : After your answer I changes it to support return of generic type : 添加 :在您回答之后,我将其更改为支持通用类型的返回:

   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
            }

}

I'm getting compile error... when I run it of course <T> and <C> are the same type. 我遇到了编译错误……当我运行它时, <T><C>当然是同一类型。

The first problem is that your non-generic code doesn't compile. 第一个问题是您的非通用代码无法编译。 You have a field DataTypeB data; 您有一个字段DataTypeB data; which you then assign a SparseArray<DataTypeB> to. 然后将其分配给SparseArray<DataTypeB> Also, setData doesn't compile at all. 另外, setData根本不编译。

Ignoring this... you have declared type parameters A, B, C and changed your instance field types, but you still try and assign DataTypaA to A myFragment in your constructor, and a SparseArray<DataTypeB> to B data . 忽略此...您已经声明了类型参数A, B, C并更改了实例字段类型,但是您仍然尝试将DataTypaA分配给DataTypaA中的A myFragment ,并将SparseArray<DataTypeB>分配给B data When you migrate code to generics you need to approach it like you would refactoring - one step at a time. 当您将代码迁移到泛型时,您需要像重构那样进行处理-一次仅一步。

For instance, by diving in as you have now take a look at items = (C)myFragment.getData() . 例如,通过现在进入,可以查看items = (C)myFragment.getData() As fragment is still of type DataTypaA then presumably its getData() method doesn't return a generic type. 由于fragment仍然是DataTypaA类型, DataTypaA大概它的getData()方法不会返回泛型类型。 Something is going to have to change. 某些事情将不得不改变。

You have a lot of work to do, so to repeat myself - treat this as a refactoring exercise and go step by step. 您有很多工作要做,所以重复我自己-将此视为重构练习,然后逐步进行。

  1. Get your non-generic type to compile. 获取您的非泛型类型进行编译。
  2. Change myFragment to be a A myFragment and declare a type parameter <A extends DataTypaA . myFragment更改为A myFragment并声明类型参数<A extends DataTypaA See what needs to be done to get this to compile before moving on. 在继续之前,请查看需要做什么才能使其编译。
  3. Now look at moving data to be SparseArray<B> data . 现在将移动data视为SparseArray<B> data Presumably this needs to a SparseArray<T> where T is a DataTypeB , or subtype thereof. 大概这需要SparseArray<T> ,其中TDataTypeB或其子类型。 That means you are going to need a wildcard-based bound on B . 这意味着您将需要在B上基于通配符的绑定。 Something like B extends SparseArray<? extends DataTypeB> B extends SparseArray<? extends DataTypeB>这样的东西B extends SparseArray<? extends DataTypeB> B extends SparseArray<? extends DataTypeB>
  4. Now look at items . 现在看一下items You know that it is returned from your new generic type variable A extends DataTypeA , so DataTypeA needs to be generic and have a generic type variable returned from getData . 您知道它是从新的通用类型变量A extends DataTypeA ,因此DataTypeA需要是通用的,并且具有从getData返回的通用类型变量。 Let's say it is declared as DataTypeA<T extends DataTypeC> with public T getData() { ... } . 假设它是使用public T getData() { ... }声明为DataTypeA<T extends DataTypeC>

So now your type parameter sections change to: 因此,现在您的类型参数部分更改为:

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;
...

It's hard to go too far with this given the code you have posted - not all the classes and information is there, but this is the process you will have to follow. 鉴于您已发布的代码,对此很难走得太远-并非所有的类和信息都在那儿,但这是您必须遵循的过程。

For instance: you may not need to restrict C to DataTypeC . 例如:您可能不需要将C限制为DataTypeC This then changes the type parameter sections on myAdapter and DataTypeA . 然后,这将更改myAdapterDataTypeA上的类型参数部分。 My assumption about SparseArray<B> may also be incorrect - but your code doesn't compile at the moment so I can't tell. 我对SparseArray<B>假设也可能不正确-但您的代码目前无法编译,因此我无法告知。 A final implementation may go something like: 最终的实现可能类似于:

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);
    }
}

For this I used the fake classes: 为此,我使用了伪类:

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

When "genericizing" classes, you should replace all instances of genericized types by their generic: DataTypaA becomes A , etc. 当“泛化”类时,应将泛化类型的所有实例替换为其泛型: DataTypaA变为ADataTypaA

You also need to make sure return types from methods you call on other objects (like fragment.getData() ) are compatible with the generic. 您还需要确保您在其他对象(例如fragment.getData() )上调用的方法的返回类型与泛型兼容。 For that you can indicate the generic type extends a known class: 为此,您可以指示泛型扩展了一个已知的类:

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

The Java Tutorial on generics is good for more information. 有关泛型Java教程可提供更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM