vamos la
um dos grandes problemas dos chamados Collections é a tipagem.
um array vc tem array de Strings, array de URLs, array de algum tipo que vc criou, mas como fica um ArrayList, ou Vector, ou mesmo uma Pilha?
até o java 1.4 as Collections trabalhavam com o tipo Object. Isso significa que aceitavam qualquer coisa. E ai vc tinha que fazer
List foo = new ArrayList();
foo.add( "oi" );
String x = ( String ) foo.get( 0 );
e ai vc pergunta “mas por que?”
por que o metodo get retorna um Object. ArrayList é um container genérico. logo vc pode ter isso:
List foo = new ArrayList();
foo.add( "oi" );
foo.add( new Integer( 1 ) );
String x = ( String ) foo.get( 0 );
Integer y = ( Integer ) goo.get( 1 );
isso faz sentido? as vezes (ex: emular uma Tupla). mas na maioria das vezes vc quer agrupar tipos semelhantes.
vc percebeu que se vc inverter a ordem que vc adiciona os objetos na Lista foo, vc tera um codigo que compila, porem que explode um erro em Runtime. Por que? porque a Lista não é tipada.
Agora isso aqui é bonito:
List<String> foo = new ArrayList<>();
foo.add( "oi" );
foo.add( new Integer( 1 ) ); // erro em compile time!
exatamente! o codigo não compila! isso é otimo pra vc evitar equivocos. se falar que vc nao precisa fazer o cast no metodo get
List<String> foo = new ArrayList<>();
foo.add( "oi" );
String x = foo.get( 0 );
e por que? pq a tipagem é mais ou menos assim
public interface List<T> {
boolean add(T coisa);
T get(int indice);
}
nesse caso usar o List<T> cria uma magica: um tipo Generico T. assim em compile time, uma vez que vc definiu uma variavel como List<String>, sempre que tiver T isso sera interpretado como String.
Como isso entra na questão da sua Pilha: eis a declaração de um tipo Parametrizado em T.
Vc pode chamar a Pilha de Pilha de Objects, pilha de Strings, pilha do que vc quiser. pode ser uma Pilha de Pilhas. Uma pilha de pilhas de pilhas. é magico!
No caso do seu programa, vc tem uma Pilha que guarda uma private class No, que vai representar os Nós como em uma Lista encadeada.
entendido?