2012-09-26 7 views
8

Esta es una pregunta general de JAVA. En androide, existe una interfaz Parcelable:Clase genérica con problema de acceso de restricción

Este es un ejemplo en el interior del official documentation:

public class MyParcelable implements Parcelable { 
    private int mData; 

    public int describeContents() { 
     return 0; 
    } 

    public void writeToParcel(Parcel out, int flags) { 
     out.writeInt(mData); 
    } 

    public static final Parcelable.Creator<MyParcelable> CREATOR 
      = new Parcelable.Creator<MyParcelable>() { 
     public MyParcelable createFromParcel(Parcel in) { 
      return new MyParcelable(in); 
     } 

     public MyParcelable[] newArray(int size) { 
      return new MyParcelable[size]; 
     } 
    }; 

    private MyParcelable(Parcel in) { 
     mData = in.readInt(); 
    } 
} 

Estamos obligados a poner en práctica las 2 funciones describeContents() y writeToParcel.

(problema) Además de ellos, también se requieren para implementar la interfaz Parcelable.Creator<T> como un campo estático llamado CREADOR.

Todo es realmente sencillo. Ahora quiero crear una clase genérica que tiene un tipo de clase parcelable:

public class ShushContainer<T extends Parcelable> implements Parcelable 

soy capaz de poner en práctica parcelable. Puedo llamar a la T 's writeToParcel función. Sin embargo, no puedo acceder al campo CREATOR estático.

public class ShushContainer<T extends Parcelable> implements Parcelable { 
    Vector<T> items; 
    String someField; 

    @Override 
    public int describeContents() { 
     return 0; 
    } 

    @Override 
    public void writeToParcel(Parcel dest, int flags) { 
     dest.writeString(someField); 
     dest.writeInt(items.size()); 
     for(int i=0;i<items.size();i++) 
      items.get(i).writeToParcel(dest, flags); 
    } 

    public ShushContainer(Parcel in) { 
     someField = in.readString(); 
     int size = in.readInt(); 
     for(int i=0;i<size;i++) 
      //this does not work 
      items.add(T.CREATOR.createFromParcel(in)); 
    } 

    public static final Parcelable.Creator<ShushContainer> CREATOR = new Parcelable.Creator<ShushContainer>() { 
     public ShushContainer createFromParcel(Parcel in) { 
      return new ShushContainer(in); 
     } 

     public ShushContainer[] newArray(int size) { 
      return new ShushContainer[size]; 
     } 
    }; 
} 

Respuesta

1

En lugar de <T extends Parcelable> necesita <T extends ShushContainer<T> & Parcelable> esta manera se especifica que es TShushContainer para que pueda acceder es métodos y variables.

public class ShushContainer<T extends ShushContainer<T> & Parcelable> 
implements Parcelable 

Aquí está el ejemplo usando Serializable

class Sample<T extends Sample<T> & Serializable> implements Serializable { 

    public static int CONST = 0; 

    public void foo() 
    { 
    T.CONST = 5; 
    } 
} 

actualización

Si he entendido bien threre es otra clase que implementa Parcelable que tiene CREATOR Usted está tratando polimorfismo dinámico para las variables estáticas que no es posible

ejemplo de muestra para mostrar cómo se produce un error

public class Base { 
    public static int count = 10; 
} 

public class Child extends Base { 
    public static int count = 20; 
} 


class Sample<T extends Base> { 
    T t = null; 
    public void printCount() { 
     System.out.println(T.count); 
    } 
    public Sample(T t) { 
     this.t = t; 
    } 

    public static void main(String[] args) { 
     Sample<Child> sample = new Sample<Child>(new Child()); 
     Sample<Base> sample1 = new Sample<Base>(new Base()); 
     sample.printCount();//Child value printed as 10 
     sample1.printCount();//Same for parent value printed as 10 
    } 

} 

Este programa falla porque los campos estáticos están obligados a clase en lugar de ejemplo, por lo que hay dos separados count uno para Base y uno para Child si accede valor de Base entonces siempre será 10.

Puede usar el reflejo para verificar si el campo CREATOR está presente y acceder a él. Lo que no será posible sin objeto o objeto de clase.

O puede hacer algo como a continuación utilizando TypeToken

class Sample<T extends Serializable> implements Serializable { 

    public int abc = 0; 
    public void foo() { 
    } 
    public static void main(String[] args) throws SecurityException, NoSuchFieldException { 
     TypeToken<Sample<Integer>> token = new TypeToken<Sample<Integer>>() { 
     }; 
     Class<?> t = token.getRawType(); 
     Field field = t.getDeclaredField("abc"); 
     field.setAccessible(true); 
     System.out.println(field.getName()); 

    } 
} 
+0

T es otra clase que implementa parcelable. –

+0

Entonces, ¿cómo puede esa clase tener 'CREATOR' porque está definida en ShushContainer. Esta variable pertenece solo a esta clase. Simplemente úselo, ¿por qué necesita T.CREATOR? Simplemente use CREATOR –

+0

Nopes ShushContainer implementa Parcelable y tiene su propio CREATOR. T también implementa Parcelable y tiene su propio CREADOR. Es este CREADOR al que no puedo acceder. –

0

esto no responde a su pregunta sobre cómo acceder a la propiedad CREADOR estática, sin embargo no es necesario acceder a esta propiedad implementar parcelable. Consulte a continuación, por ejemplo:

public class TestModel<T extends Parcelable> implements Parcelable { 

private List<T> items; 
private String someField; 

public List<T> items() { 
    return items; 
} 

public void setItems(List<T> newValue) { 
    items = newValue; 
} 

public String someField() { 
    return someField; 
} 

public void setSomeField(String newValue) { 
    someField = newValue; 
} 

//region: Parcelable implementation 

public TestModel(Parcel in) { 
    someField = in.readString(); 

    int size = in.readInt(); 
    if (size == 0) { 
     items = null; 
    } 

    else { 

     Class<?> type = (Class<?>) in.readSerializable(); 

     items = new ArrayList<>(size); 
     in.readList(items, type.getClassLoader()); 
    } 
} 

@Override 
public int describeContents() { 
    return 0; 
} 

@Override 
public void writeToParcel(Parcel dest, int flags) { 
    dest.writeString(someField); 

    if (items == null || items.size() == 0) 
     dest.writeInt(0); 

    else { 
     dest.writeInt(items.size()); 

     final Class<?> objectsType = items.get(0).getClass(); 
     dest.writeSerializable(objectsType); 

     dest.writeList(items); 
    } 

    dest.writeInt(items.size()); 
    for(int i=0;i<items.size();i++) 
     items.get(i).writeToParcel(dest, flags); 
} 

public static final Parcelable.Creator<TestModel> CREATOR = new Parcelable.Creator<TestModel>() { 
    public TestModel createFromParcel(Parcel in) { 
     return new TestModel(in); 
    } 

    public TestModel[] newArray(int size) { 
     return new TestModel[size]; 
    } 
}; 

//endregion 
} 
Cuestiones relacionadas