Why was the parameterized class attribute <T> not instantiated?

Asked

Viewed 454 times

7

I have this class that implements the IDAO interface

package DAO;
import java.util.ArrayList;


public class BdApp<T> implements IDAO<T> {

ArrayList<T> lst = new ArrayList<T>(); 
//ArrayList<Administrador> lstAdministrador = new ArrayList<Administrador>();
@Override
public void add(T c) {
    lst.add(c);
}


@Override
public void update(T o) {
    // TODO Auto-generated method stub

}


@Override
public ArrayList<T> listar() {
    // TODO Auto-generated method stub
    return lst;
}
}

And this class that arose my doubt:

package UI;

import java.util.ArrayList;
import java.util.Scanner;

import DTO.Contato;
import DAO.BdApp;

public class Menu {

private BdApp<Contato> bd;

public Menu(BdApp bd){
    this.bd = bd; 
}

public void cadContato(){
    Scanner sc = new Scanner(System.in);
    Contato contato = new Contato();
    System.out.print("Digite o nome: ");
    contato.setNome(sc.next());
    System.out.print("Digite o cpf: ");
    contato.setCpf(sc.next());

    bd.add(contato);
}

public void listarContatos(){
    ArrayList<Contato> lista = bd.listar();
    for (Contato contato : lista) {
        System.out.println(contato.getNome());
    }
}   
}

In that part:

private BdApp<Contato> bd;

Why didn’t he prompt us to do it this way:

  private BdApp<Contato> bd = new BdApp<Contato>(); ?

And if it weren’t for the parameterized class the composition would look like this?

 private BdApp bd;
  • Funny that I’ve tried to do something like Arraylist several times (unsuccessful, of course), but I resolved instantiating inside the builder, instead of going for clarifications as you did kkk

3 answers

6

If the class wasn’t parameterized, it would still look like this.

The ideal is that the parameter type of the constructor method is the same as the member it will initialize, that is, it should also be parameterized.

Usually you stop initializing the member when the initialization should happen in the constructor, which is exactly what was done, there is no reason to initialize twice, the direct initialization of the member would be lost before being used.

  • 1

    So parameterized classes should not be started directly in the variable declaration, within the class, but in the constructor of that class?

  • 1

    The fact of being parametrized or not is mere coincidence there. Do not confuse the class to be parametrized (case of BdApp) with the constructor method parameter, these are completely different things that happen to be using the same word to define themselves. Initializing in the declaration or constructor depends on the goal you want to achieve.

  • True, I tested it here and it worked, I think I got confused with the hehe definitions

  • :Was that it? I think I got it.

  • "The direct initialization of the limb would be lost before it was used." This was put twice, counting on the constructor? *.

  • That. It would be something like doing x = 0; x = 1; Zero x was never used, so why do this?

Show 1 more comment

6


Briefly I would define as follows: badly made class design :), the constructor argument of Menu should also be typed, since BdApp is a raw type, in addition to which it could be a reference to IDAO, nay BdApp.

Why didn’t he prompt us to do it this way: private BdApp<Contato> bd = new BdApp<Contato>();?

The way this code is, it doesn’t really make much difference to initialize in the declaration or constructor, one way or another at the end it only makes sense to assign BdApp<Contato> or the attribute bd in Menu do not depend on anything of the generic type (which leads us to believe that it did not need to be generic). For example:

final BdApp<Integer> bd = new BdApp<>();
final Menu menu = new Menu(bd);
menu.listar();

This example above compiles and runs smoothly, but it doesn’t make any sense to how the class design is. As it stands, the attribute is typed (private BdApp<Contato> bd), then even when building an instance of Menu i tried to change the type of generic could have problems, according to which it was used later in the code.

In addition, the advantage of having assignment per constructor, Setter, etc. is that who instantncia defines the concrete type, be able to exchange implementations, change implementation in Runtime (with Setter, for example), etc.

However this is quite common, see the example below:

  • abstract class Menu:
public abstract class Menu<T> {

    private final IDAO<T> bd;

    public Menu(final IDAO<T> bd) {
        this.bd = bd;
    }

    public void cadastrar() {
        try(final Scanner sc = new Scanner(System.in)) {
            bd.add(this.instance(sc));
        }
    }

    protected abstract T instance(final Scanner sc);

    public void listar() {
        final List<T> lista = bd.listar();
        for (final T t : lista) {
            this.imprimir(t);;
        }
    }

    protected abstract void imprimir(final T t);

}
  • class MenuContato:
public class MenuContato extends Menu<Contato> {

    public MenuContato(final IDAO<Contato> bd) {
        super(bd);
    }

    @Override
    protected Contato instance(final Scanner sc) {
        final Contato contato = new Contato();
        System.out.print("Digite o nome: ");
        contato.setNome(sc.next());
        System.out.print("Digite o cpf: ");
        contato.setCpf(sc.next());
        return contato;
    }

    @Override
    protected void imprimir(final Contato t) {
        System.out.println(t.getNome());
    }

}

See what we make Menu also generic, so we could have Menu of anything. Besides (and one of the better parts of this) is that we can change the implementation of IDAO, as stated above. That is, we can pass an instance that saves the data in a list, one that uses BD persistence, etc., without needing to change absolutely anything.

And if it weren’t for the parameterized class the composition would look like this?

Yeah, if it’s not a generic type it wouldn’t have to parameterize it, then it would be like you yourself observed, just private BdApp bd;

Probably this code is not yours, but follow some observations, in addition to the points cited above:

  • consider always having the reference not to the concrete type, but to the interface, this gives you greater flexibility. Ie, private BdApp<Contato> bd = new BdApp<>(); in place of private BdApp<Contato> bd = new BdApp<Contato>();, private List<T> lst = new ArrayList<>(); in place of ArrayList<T> lst = new ArrayList<T>(); and so on. See more;
  • from Java 7 there is the diamond operator, then you do not need to qualify the concrete type to instantiate the object, it will be inferred by the reference, ie, private List<T> lst = new ArrayList<>(); and not private List<T> lst = new ArrayList<T>();;

I quoted some Smells of the code just to notice how much he seems to be in trouble =)

1

It’s simply separation of responsibilities. Design decision, only. " Injecting" dependencies in this way is useful to facilitate testing, among other things.

If the class were not parameterized, the whole <AlgumTipo> vanishing.

If your question is about why the constructor parameter has no type specified within the <>, the answer is omission-- probably lack of attention or knowledge. The compiler accepts this type of thing, although it generates an alert. If you don’t decide a guy there, anything will be able to get in, which compromises the safety of your application types, basically destroying the purpose of using Generics.

  • Awaiting the explanation of the negative vote.

  • 4

    Perhaps some negative votes came when his reply contained only two lines. Not that I was wrong, but people in general expect a little more explanation. I think there is no justification for the 3 negative votes, even more after the edition.

Browser other questions tagged

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