Pregunta

En Java, me gustaría tener algo como:

class Clazz<T> {
  static void doIt(T object) {
    // shake that booty
  }
}

Pero consigo

Cannot make a static reference to the non-static type T

No entiendo genéricos más allá de los usos básicos y por lo tanto no puede tener mucho sentido de ello. No sirve de nada que yo no era capaz de encontrar mucha información en Internet sobre el tema.

Podría alguien aclarar si dicha utilización es posible, por una manera similar? También, por qué no tuvo éxito mi intento original?

¿Fue útil?

Solución

No se puede utilizar parámetros de tipo genérico de una clase de métodos estáticos o campos estáticos. los parámetros de tipo de la clase son sólo en alcance por los métodos de instancia y campos de instancia. Para los campos estáticos y métodos estáticos, que son compartidos entre todas las instancias de la clase, incluso casos de diferentes parámetros de tipo, así que obviamente no pueden depender de un parámetro de tipo particular.

No parece que el problema debe requerir el uso de parámetro de tipo de la clase. Si usted describe lo que está tratando de hacer con más detalle, tal vez podamos ayudar a encontrar una mejor manera de hacerlo.

Otros consejos

Java no sabe lo que está T hasta que una instancia de un tipo.

Tal vez se puede ejecutar métodos estáticos llamando Clazz<T>.doit(something) pero parece que no puede.

La otra manera de manejar las cosas es poner el parámetro de tipo en el propio método:

static <U> void doIt(U object)

lo que no le consigue la restricción a la derecha en U, pero es mejor que nada ....

Me encontré con este mismo problema. He encontrado mi respuesta descargando el código fuente de Collections.sort en el marco de Java. La respuesta que utilicé fue poner el <T> genérico en el método, no en la definición de clase.

Así que esto funcionó:

public class QuickSortArray  {
    public static <T extends Comparable> void quickSort(T[] array, int bottom, int top){
//do it
}

}

Por supuesto, después de leer las respuestas de arriba me di cuenta de que esto sería una alternativa aceptable sin necesidad de utilizar una clase genérica:

public static void quickSort(Comparable[] array, int bottom, int top){
//do it
}

Es posible hacer lo que desee utilizando la sintaxis de los métodos genéricos al declarar su método de doIt() (nótese la adición de <T> entre static y void en la firma del método de doIt()):

class Clazz<T> {
  static <T> void doIt(T object) {
    // shake that booty
  }
}

Tengo editor de Eclipse para aceptar el código anterior sin el error Cannot make a static reference to the non-static type T y luego lo amplió para el siguiente programa de trabajo (con referencia cultural, algo apropiado para la edad):

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }

  private static class KC {
  }

  private static class SunshineBand {
  }

  public static void main(String args[]) {
    KC kc = new KC();
    SunshineBand sunshineBand = new SunshineBand();
    Clazz.doIt(kc);
    Clazz.doIt(sunshineBand);
  }
}

que imprime estas líneas a la consola cuando lo ejecuto:

  

sacudir ese botín 'com.eclipseoptions.datamanager.Clazz clase $ KC'
!!!   sacudir ese botín 'clase com.eclipseoptions.datamanager.Clazz $ SunshineBand' !!!

Creo que esta sintaxis no se ha mencionado todavía (en el caso de que quiera un método sin argumentos):

class Clazz {
  static <T> T doIt() {
    // shake that booty
  }
}

Y la llamada:

String str = Clazz.<String>doIt();

Espero que esto ayuda a alguien.

Se menciona correctamente en el error: no se puede hacer una referencia estática a tipo T. no estático La razón es la T parámetro de tipo puede ser sustituido por cualquiera del argumento de tipo, por ejemplo, Clazz<String> campos o Clazz<integer> etc. Pero estáticas / métodos son compartidos por todos los objetos no estáticos de la clase.

El siguiente extracto se toma del doc :

  

campo estático de una clase es una variable de nivel de clase compartida por todos   objetos no estáticos de la clase. Por lo tanto, los campos estáticos de tipo   No se permite parámetros. Considere la siguiente clase:

public class MobileDevice<T> {
    private static T os;

    // ...
}
     

Si se permitiera campos estáticos de parámetros de tipo, a continuación, el siguiente código se confundiría:

MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();
     

Debido a que el sistema operativo campo estático es compartida por teléfono, buscapersonas, y PC, ¿cuál es el tipo real del sistema operativo? No puede ser inteligente, buscapersonas, y   Tablet PC al mismo tiempo. No se puede, por lo tanto, crear campos estáticos   de parámetros de tipo.

Como se hizo notar justamente por Chris en su contesta es necesario utilizar el parámetro de tipo con el método y no con la clase en este caso. Se puede escribir como:

static <E> void doIt(E object) 

Otros han respondido a su pregunta ya, pero además me pueden recomendar a fondo el O'Reilly de Java genéricos libro. Es un tema complejo y sutil a veces, y aunque a menudo parece no tener restricciones sin sentido, pero el libro hace un buen trabajo de explicar por qué los genéricos de Java son como son.

Algo parecido a lo siguiente sería llegar más cerca

class Clazz
{
   public static <U extends Clazz> void doIt(U thing)
   {
   }
}

EDIT: Actualización ejemplo con más detalle

public abstract class Thingo 
{

    public static <U extends Thingo> void doIt(U p_thingo)
    {
        p_thingo.thing();
    }

    protected abstract void thing();

}

class SubThingoOne extends Thingo
{
    @Override
    protected void thing() 
    {
        System.out.println("SubThingoOne");
    }
}

class SubThingoTwo extends Thingo
{

    @Override
    protected void thing() 
    {
        System.out.println("SuThingoTwo");
    }

}

public class ThingoTest 
{

    @Test
    public void test() 
    {
        Thingo t1 = new SubThingoOne();
        Thingo t2 = new SubThingoTwo();

        Thingo.doIt(t1);
        Thingo.doIt(t2);

        // compile error -->  Thingo.doIt(new Object());
    }
}

Cuando se especifica un tipo genérico para su clase, JVM saber sobre él sólo tener una instancia de su clase, no definición. Cada definición sólo se ha parametrizado tipo.

Los genéricos funcionan como plantillas en C ++, por lo que primero debe crear una instancia de la clase, a continuación, utilizar la función con el tipo que se ha especificado.

También para ponerlo en términos simples, esto ocurre debido a la propiedad "borrado" de la generics.Which significa que aunque definimos ArrayList<Integer> y ArrayList<String>, en el momento de la compilación se queda como dos tipos diferentes de hormigón, pero en el tiempo de ejecución del JVM borra tipos genéricos y crea una sola clase ArrayList en lugar de dos clases. Así que cuando se define un método de tipo estático o cualquier cosa por un genérico, que es compartida por todas las instancias de ese genérico, en mi ejemplo es compartida por ambos ArrayList<Integer> y ArrayList<String> .Es por eso que obtener el tipo error.A genérico de parámetros de una Clase no está permitido en un contexto estático!

@BD en Rivenhill: Dado que esta vieja cuestión ha conseguido una atención renovada el año pasado, vamos a ir en un poco, sólo por el bien de la discusión. El cuerpo de su método doIt no hace nada T específica en absoluto. Aquí está:

public class Clazz<T> {
  static <T> void doIt(T object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

Así se puede soltar por completo todas las variables de tipo y código sólo

public class Clazz {
  static void doIt(Object object) {
    System.out.println("shake that booty '" + object.getClass().toString()
                       + "' !!!");
  }
// ...
}

Ok. Pero volvamos más cerca del problema original. La primera variable de tipo en la declaración de clase es redundante. Sólo se necesita la segunda en el método. Aquí vamos de nuevo, pero no es la respuesta final, sin embargo:

public class Clazz  {
  static <T extends Saying> void doIt(T object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}
// Output:
// KC
// Sunshine

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

Sin embargo, todo es demasiado alboroto por nada, ya que la siguiente versión funciona de la misma manera. Todo lo que necesita es el tipo de interfaz en el parámetro del método. No hay variables de tipo a la vista en cualquier lugar. ¿Era realmente el problema original?

public class Clazz  {
  static void doIt(Saying object) {
    System.out.println("shake that booty "+ object.say());
  }

  public static void main(String args[]) {
    Clazz.doIt(new KC());
    Clazz.doIt(new SunshineBand());
  }
}

interface Saying {
      public String say();
}

class KC implements Saying {
      public String say() {
          return "KC";
      }
}

class SunshineBand implements Saying {
      public String say() {
          return "Sunshine";
      }
}

Dado que las variables estáticas son compartidos por todas las instancias de la clase. Por ejemplo, si usted está teniendo siguiente código

class Class<T> {
  static void doIt(T object) {
    // using T here 
  }
}

T está disponible sólo después de que se crea una instancia. Sin embargo, los métodos estáticos se pueden utilizar incluso antes de casos están disponibles. Por lo tanto, los parámetros de tipo genérico no pueden ser referenciados dentro de los métodos estáticos y variables

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