Differences between <T> and <?>

Asked

Viewed 4,521 times

34

What is the difference among the ratings <T> and <?> in Java? What motivation in the use of these resources and where each one is fundamental?

  • <T> when we have a certain data type for Generics, <?> when you don’t know what kind of data((List<?> elements)) that list will accept any kind of data in the case.

1 answer

30


The T in <T> is a placeholder of the type it will represent for a certain variable within a class. It is used in class declaration and its methods. Example:

class MeuGenerico<T> {  //T abreviacao de tipo
    private T var;
    public MeuGenerico() { }
    public MeuGenerico(T var) { this.var = var; }
    public T getVar() { return var; }
    public void setVar(T var) { this.var = var; }
}

public class Teste {
    public static void main(String[] args) {
        MeuGenerico<Integer> mg = new MeuGenerico<>(42);
        System.out.println(mg.getVar());
    }
}

Exit:

42

It is used when creating a class where its variables are of a type that is not defined at the time it is written, but rather at the time it is used, leaving it to the discretion of the user of that class what will be the type of the variable instead of the T.

Besides T which is an abbreviation for the "type", there are other convention-standardized acronyms among Java developers:

E - Element
K - Key
N - Number
T - Type
V - Valor

Example: Interface Map<K,V>

However, these acronyms are not special characters reserved by the compiler, you can use other characters you prefer, such as f, J, Z, or even whole words, for example meuTipo or _$$_. The rule that governs what can go within the <> is the same that defines how variable names can be, so your word cannot start with numbers and in no way can it be a ?, just as it cannot be a @ not even a #, among several other special characters which are also not allowed.

Although I have the freedom to write whatever I want to be placeholder, always try to follow the convention as it facilitates communication between developers.

More details on: Generic Tag Wiki '' and also in Oracle tutorial on Generics


Already the ?, in the context of generics, basically serves as a wildcard, because it represents "any kind". Its function is to allow the use of polymorphism along with generics.

When followed by the word reserved super, for example <? super Number> it accepts that any object whose supertype is Number is read or written to a variable, as it is safe to treat any subtype of it as Number. For example:

import java.math.BigInteger;

class MeuGenerico<T> {  //T abreviacao de tipo
    private T var;
    public MeuGenerico() { }
    public T getVar() { return var; }
    public void setVar(T var) { this.var = var; }
}

public class Teste {
    public static void main(String[] args) {
        MeuGenerico<? super Number> mg = new MeuGenerico<>();
        //escrevendo em uma variável
        mg.setVar(new Integer(1));                      //válido
        mg.setVar(new Float(2.0f));                     //válido
        mg.setVar(new BigInteger("99999999999999"));    //válido
        //mg.setVar(new String("999999999"));           //inválido!!
    }
}

It is worth remembering the hierarchy:

  • java.lang.Object
    • java.lang.Number
      • java.util.Concurrent.atomic.Atomicinteger
      • java.util.Concurrent.atomic.Atomiclong
      • java.math.Bigdecimal
      • java.math.Biginteger
      • java.lang.Byte
      • java.lang.
      • java.lang.Float
      • java.lang.
      • java.lang.Long
      • java.lang.Short

Therefore, only the objects of the Number classes and their subtypes can be associated with the variable of our generic class.

When followed by the word reserved extends, for example <? extends Number>, again it will only accept objects that are subtypes of Number, however this time it will not allow writing to variables. Example:

public class Teste {
    public static void main(String[] args) {
        MeuGenerico<? extends Number> mg = new MeuGenerico<>();
        //tentando escrever em uma variável
        //mg.setVar(new Integer(1));                    //inválido!!
        //mg.setVar(new Float(2.0f));                   //inválido!!
        //mg.setVar(new BigInteger("99999999999999"));  //inválido!!
        //mg.setVar(new String("999999999"));           //inválido!!
    }
}

At this point you may be wondering "How to read something from this variable if you can’t write anything to it?".

IS simple thus: As its use is to allow the reading of the contents of the variables but without allowing writing them, this statement is used when a parameter of a method is desired to pass a variable with data already written in it as argument. Basically it is to allow the use of polymorphic methods to the same as generic ones. Example:

import java.math.BigInteger;

class MeuGenerico<T> {  //T abreviacao de tipo
    private T var;
    public MeuGenerico() { }
    public T getVar() { return var; }
    public void setVar(T var) { this.var = var; }
}

public class Teste {
    public static void main(String[] args) {
        MeuGenerico<Number> mg = new MeuGenerico<>();
        mg.setVar(new Float(9.0f));                 
        fazAlgoImportante(mg);      //passa o argumento
        mg.setVar(new BigInteger("999"));                   
        fazAlgoImportante(mg);      //passa o argumento
    }
    public static void fazAlgoImportante(MeuGenerico<? extends Number> mg) {
        //nesse momento mg tem permissão apenas de leitura
        System.out.println(mg.getVar().intValue() * mg.getVar().intValue()); //OK
        //mg.setVar(new Float(9.0f));   //inválido!!
    }
}

The argument received by the method fazAlgoImportante() shall be treated as if it were an object of the class Meugenerico, the type being used instead of T as if it were a Number. At this point, the kind that will take the place of T may be any subclass of Number, but regardless of whether it is an Integer, Atomiclong or Biginteger, only the methods provided by number class can be accessed, as is the expected behavior according to what is known of polymorphism.

More details on the use of polymorphism and generics in that question.

Already <?> would be identical to do <? extends Object>.

It’s worth remembering that <? extends Object> is not the same thing as <Object>, because in the first case you cannot write in the variable.

Completion

As we can see, the placeholder and the wildcard have very different characteristics and under no circumstances can they be exchanged. Therefore, answering your question of what is the difference between the two is: ALL! Since in common only the fact that they are used with generics, there is nothing else.

  • Did not know this feature contained in <? extends Object> to impose restriction on the writing of the object. Congratulations! Very good answer.

  • @Geisonsantos’s function is to allow polymorphic methods with generics, essential to the language but at the same time a little confused, if you try to write in the variable you will have problems. I’m glad you liked the answer, although I have not answered directly your bold I believe I have been understood in the course of the text.

  • Math, they were answered yes, though not directly, which was by no means a requirement of mine. You even explained more than was asked :)

  • 3

    It’s a shame I didn’t find that answer 2 years ago, when I screwed up a test on this topic :/. Either way, excellent response.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.