2008-12-11 23 views
8

me gustaría definir un tipo genérico, cuyo tipo de parámetro real sólo puede serJava Tipo de parámetro formal definición (Genéricos)

  1. Una de las clases numéricos primitivos envoltura (Long, Integer, Float, Double)
  2. String

puedo cumplir con el primer requisito, con una definición como esta

public final class MyClass<T extends Number> { 
    // Implementation omitted 
} 

Pero no puedo encontrar la forma de conocerlos a los dos. Sospecho que esto no es realmente posible, porque que yo sepa no hay forma de especificar "o" semántica cuando se define un parámetro de tipo formal, aunque se puede especificar "y" semántica utilizando una definición como

public final class MyClass<T extends Runnable & Serializable > { 
    // Implementation omitted 
} 

Cheers, Don

+0

El borrado de tipo lo pondría nuevamente en el objeto si existiera. – Loki

Respuesta

0

Interesante pregunta, me asombró un poco. Sin embargo, aparentemente esto es imposible. Probé varios hacks diferentes, ninguno realmente funciona.

11

Los genéricos de Java no son compatibles con los tipos de unión (este parámetro puede ser A o B).

En una nota relacionada que puede ser de interés para algunos, admite varios límites, si desea aplicar varias restricciones. He aquí un ejemplo de la JDK de Java se menciona en el generics tutorial:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 
+1

¿No es ese un mal ejemplo (veo que es de SUN, no del tuyo)? > es lo mismo que >, ¿no? no significa nada. – Markus

+0

@Markus no, no es un mal ejemplo. No es lo mismo. Sin el tipo de firma 'extends Object', el tipo de firma es Comparable (que no hereda de un objeto) en lugar del Object que se desea. – McTrafik

2

Mientras que los genéricos no funcionarán aquí, un tipo de base con tipos derivados de Number y String voluntad. Dado que un tipo genérico se habría borrado a Object de todos modos, cualquier funcionalidad que haya puesto allí puede ir en una clase base abstracta. Es probable que solo necesite un descriptor de acceso específico del tipo en la subclase para obtener el valor.

Además, tenga cuidado con la clase Number. No se limita al boxeo de los tipos primitivos, ya que cualquiera puede ampliarlo —, por ejemplo, BigInteger.

4

Puede utilizar los métodos de fábrica para todos los tipos admitidos y hacer que el constructor sea privado/protegido. Usted tiene que fijar el tipo genérico en el constructor de todos modos por lo que tiene sentido, por lo que probablemente podría codificar de esta manera:

public final class MyClass<T> { 
    public static MyClass<Integer> newInstance(int i) { 
     return new MyClass<Integer>(i); 
    } 
    public static MyClass<String> newInstance(String s) { 
     return new MyClass<String>(s); 
    } 
    //More factory methods... 

    protected MyClass(T obj) { 
     //... 
    } 
} 

O si no desea que el parámetro constructor, algo como esto: public final clase MyClass { public static MyClass newIntegerInstance() { return new MyClass(); } // ...}

Como se dijo Erickson, la puesta en práctica común puede confiar sólo en objetos de todos modos, por lo que la única restricción es que se pueden crear otras implementaciones de otros tipos, además de la primitiva y de cadena.

0

Tal vez usted podría hacer lo siguiente:

  1. Hacer MyClass<T> una clase de paquete predeterminado, invisible para otros componentes, o al menos con sólo unos ctors paquete predeterminado, de modo que no puede extenderse o una instancia fuera del paquete.
  2. Cree dos clases públicas en el paquete de MyClass<T>:
MyNumericClass<T extends Number> extends MyClass<T> 
MyStringClass extends MyClass<String> 

De esta manera todas las subclases de MiClase se limitarán a los parametrizada con una subclase número o una cadena.

Cuestiones relacionadas