How do I specify that the builder type is the same as declared in the class?

6

I created an object that accepts a list of any type, like this:

class Grid<T> {
    private Integer count;
    private Integer offset;
    private Integer limit;
    private List<T> list;

    private T tipo;

    public Grid() {
    }

    public Grid(Integer count, List<T> list) {
        this.count = count;
        this.list = list;
    }
}

However, in this way it allows me to create an object of one type and pass in the constructor another type, like this:

List<Usuario> listaUsuarios = new ArrayList<>();
Grid<Empresa> grid = new Grid(10, listaUsuarios);

That is, I created a Grid of type Empresa , and passed in the constructor a list of type Usuario .

If you do a setList(List<T> list) it works as expected, ie it only accepts if the list is of the same type as declared in the class.

p>     

asked by anonymous 23.09.2015 / 14:57

2 answers

4

You are creating the instance the "wrong way"

  

You are not creating an instance of your generic class, so the compiler is accepting a different type in the constructor without error.

This way you've created an instance of your class:

Grid<Empresa> grid = new Grid(...);

is allowed by the compiler because of backward compatibility. See: The Java Tutorials - Raw Types .

In short, although you have no class Grid because what you declared was Grid<T> , that is, a generic , the compiler considers that there is a class Grid and he calls it raw type . It needs this for compatibility with old code, prior to the advent of generics

However, the way to create an instance of a generic class is this:

Grid<Empresa> grid = new Grid<Empresa>(...);

That is, you should enter the generic parameter when creating the instance , otherwise you are actually creating an instance of raw type and not an instance of your generic class.

If you correctly create an instance of the generic class you will get a compile error when the type passed to your constructor does not hit the generic parameter type.

In C # (other language to support generics ) does not have such a raw type so you are required to explicitly < in> generic parameter as I did above.

In Java you can also use the diamond > syntax, letting the compiler break the generic parameter type from the variable declaration: / p>

Grid<Empresa> grid = new Grid<>(...);

If you follow this practice by explicitly specifying the generic parameter or using diamond syntax, a compile error will be generated if you attempt to use an instance of type incompatible with generic parameter informed.

Why does NetBeans not alert to bad practice?

Because the warning of the compiler regarding the use of raw types is turned off by default. If you look at the hints of the compiler, however, the warning will be there:

Note: Main.java uses unchecked or unsafe operations.

If you enable this warning in NetBeans (in Eclipse it is enabled by default), you will be warned by the editor and also during compilation with the following message:

Grid is a raw type. References to generic type Grid 
should be parameterized.
Type safety: The constructor Grid(Integer, List) belongs to the raw type Grid. 
References to generic type Grid should be parameterized.

You could even treat this warning as an error, preventing compilation when an instance of a raw type was created.

I do not have NetBeans installed but this image shows more or less where this setting is:

    
23.09.2015 / 22:35
1

The search I've done can not resolve this issue at compile time. However the compiler (Eclipse) gives the following warning :

  

Type safety: The expression of type Grid needs unchecked conversion to conform to Grid

in code new Grid(10, listaUsuarios);

This behavior is described in the documentation in the following paragraph:

  

Type Inference and Instantiation of Generic Classes

     

You can replace the type arguments required to invoke the constructor of a generic class with an empty set of type parameters (< >) as long as the compiler can infer the type arguments from the context. This pair of angle brackets is informally called the diamond.

     

For example, consider the following variable declaration:

     

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

     

You can substitute the parameterized type of the constructor with an empty set of type parameters (< >):

     

Map<String, List<String>> myMap = new HashMap<>();

     

Note that to take advantage of type inference during generic class instantiation, you must use the diamond. In the following example, the compiler generates an unchecked conversion warning because the HashMap () constructor refers to the HashMap raw type, not the Map<String, List<String>> type:

     

Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning

It basically says that the type of arguments required to invoke the constructor of a generic class can be overridden by an empty set of argument types (< >) since the compiler can infer the type from the context. br> If the types are not specified or not used <> the compiler will generate an unchecked conversion warning

If you use Grid<Empresa> grid = new Grid<>(10, listaUsuarios); the compiler will generate the following compile error:

  

Can not infer type arguments for Grid < >

Explaining with examples:

  • Different types and without using <>

    List<Usuario> listaUsuarios = new ArrayList<>();
    Grid<Empresa> grid = new Grid(10, listaUsuarios);
    

    The compiler generates a warning :

      

    Type safety: The expression of type Grid needs unchecked conversion to conform to Grid

  • Different types using <>

    List<Usuario> listaUsuarios = new ArrayList<>();
    Grid<Empresa> grid = new Grid(10, listaUsuarios);
    

    The compiler generates an error:

      

    Can not infer type arguments for Grid<>

  • Type equal and without using <>

    List<Empresa> listaUsuarios = new ArrayList<>();
    Grid<Empresa> grid = new Grid(10, listaUsuarios);
    

    The compiler generates a warning :

      

    Type safety: The expression of type Grid needs unchecked conversion to conform to Grid<Empresa>

  • Equal types using <>

    List<Empresa> listaUsuarios = new ArrayList<>();
    Grid<Empresa> grid = new Grid<>(10, listaUsuarios);
    

    The compiler is "content", without error and without warning .

23.09.2015 / 16:38