Java é uma linguagem fortemente tipada.
Conversões padrão e promoções automáticas são aplicadas aos tipos primitivos.
A compatibilidade de tipos é rigorosamente imposta.
Normalmente, uma variável de referência de uma classe não pode referenciar um objeto de outra classe.
Mesmo que as classes X e Y sejam estruturalmente iguais, não é possível atribuir uma referência de X a um objeto de Y porque os tipos são diferentes.
Em geral, uma variável de referência de objeto só pode referenciar objetos de seu tipo.
A exceção à imposição de tipos é que a variável de referência de uma superclasse pode referenciar objetos de qualquer subclasse derivada dessa superclasse.
Como Y é derivada de X, é permitido que x2 receba uma referência a um objeto de Y.
O tipo da variável de referência, e não o tipo do objeto que ela referencia, determina os membros que podem ser acessados.
Quando uma referência a um objeto da subclasse é atribuída a uma variável da superclasse, só é possível acessar os membros definidos pela superclasse.
No exemplo, x2 não pode acessar o membro b de Y, pois a classe X não tem conhecimento dos membros adicionados pela subclasse.
Referências de subclasse atribuídas a variáveis da superclasse são comuns, especialmente ao chamar construtores em hierarquias de classes.
Subclasses podem se beneficiar de construtores que recebem um objeto da superclasse como parâmetro, permitindo a criação de cópias de objetos.
Nesse programa, t2 é construída a partir de t1 e, portanto, é idêntica.
Atenção neste construtor de Triangle:
// Constrói um objeto a partir de outro.
Triangle(Triangle ob) {
super(ob); // passa o objeto para o construtor de TwoDShape
style = ob.style;
}Ele recebe um objeto de tipo Triangle e o passa (por intermédio de super) para este construtor de TwoDShape:
//Constrói um objeto a partir de outro.
TwoDShape(TwoDShape ob) {
width = ob.width;
height = ob.height;
}O construtor TwoDShape() espera receber um objeto do tipo TwoDShape.
O construtor da subclasse Triangle() passa para ele um objeto do tipo Triangle.
Isso funciona porque uma referência de uma superclasse, como TwoDShape, pode referenciar um objeto de uma subclasse, como Triangle.
É aceitável passar uma referência de um objeto de uma classe derivada para um construtor da superclasse.
O construtor da superclasse, TwoDShape(), só inicializa os membros pertencentes à classe TwoDShape, independentemente dos membros adicionais da subclasse Triangle.