Pregunta

¿Es posible parametrizar genéricamente un método que acepte ClassA o InterfaceB?

No se compila debido a | Pseudocódigo

public <T extends Number | CharSequence> void orDoer(T someData){ // ... }

es decir, en lugar de escribir firmas de métodos múltiples, me gustaría que este método acepte un número o caracteres como argumento

Debe pasar con un número o argumento de Charsequence

orDoer(new Integer(6));
int somePrimitive = 4;
orDoer(somePrimitive);
orDoer("a string of chars");
¿Fue útil?

Solución

Si usted De Verdad Quiere hacer eso, necesitará envolver las clases aceptadas dentro de una clase personalizada propia. En su caso de ejemplo, probablemente algo como:

public class OrDoerElement {
    private final Number numberValue;
    private final CharSequence charSequenceValue;

    private OrDoerElement(Number number, CharSequence charSequence) {
        this.numberValue = number;
        this.charSequenceValue = charSequence;
    }

    public static OrDoerElement fromCharSequence(CharSequence value) {
        return new OrDoerElement(null, value);
    }

    public static OrDoerElement fromNumber(Number value) {
        return new OrDoerElement(value, null);
    }
}

Y tu orDoer El método se convierte en:

public void orDoer(OrDoerElement someData) { .... }

Luego puede construir uno de esos y usar en su método utilizando:

orDoer(OrDoerElement.fromCharSequence("a string of chars"));
orDoer(OrDoerElement.fromNumber(new Integer(6)));

Pero honestamente, eso suena un poco demasiado complejo y demasiado trabajo solo para poder llamar a un método con diferentes tipos de parámetros. ¿Estás seguro de que no puedes lograr lo mismo usando dos métodos y un tercer método para la lógica común?

Otros consejos

¿Usar una clase abstracta anónima es una opción para usted? Cuando necesito tipos de parámetros seguros o tipos de devolución, uso alguna variante del código a continuación. Dicho esto, estoy de acuerdo con los otros comentarios aquí, y tengo curiosidad por saber qué beneficio realmente deriva cuando está haciendo cumplir un tipo de seguridad para un grupo de objetos que no tienen tanto en común.

public abstract class Doer<T> {

  public void do(T obj) {
    // do some stuff. 
  }

}

// calling method

new Doer<Number>(){}.do(new Integer(5));

Para la pregunta original:

public void orDoer(Object someData){
    assert someData instanceof Number || someData instanceof CharSequence;

    // ...
}

En su caso más específico, el assert La declaración debe usar la introspección para aclarar si el objeto tiene los detalles que desea, es decir, verifique un constructor de String, sondee para crear una nueva instancia del objeto desde el toString() resultado del objeto entrante y compare ambos para la igualdad:

public void orDoer(Object someData) {
    assert isUniconstructable(someData);
}

public static boolean isUniconstructable(Object object) {
    try {
        return object.equals(object.getClass().getConstructor(String.class)
            .newInstance(object.toString()));
    } catch (InstantiationException | IllegalAccessException | InvocationTargetException
            | NoSuchMethodException| RuntimeException e) {
        return false;
    }
}

(Debido a las excepciones que se pueden lanzar, necesitamos envolver la prueba de afirmación en su propia función).

Tenga en cuenta que la introspección mayo Romper debido a la compresión del código Proguard de Android que reescribe los nombres de clases y en lugar de YourClass Solo una clase, es decir Q, se almacena en la base de datos, y cuando desea restaurarlo con una versión posterior de su aplicación que tiene más clases, clase Q es algo diferente entonces. Consulte el sitio web de Proguard para obtener más información sobre esto; Solo quería notificar que debas estar al tanto de esto al usar la introspección en Android.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top