Bom… vou descrever o que geralmente acontece. Há pequenas variações de linguagem para linguagem, mas o mecanismo básico, a grosso modo, é o seguinte:
Para cada classe que você cria, há uma estrutura criada descrevendo o nome da classe, o endereço de cada método e os tipos de atributos que os objetos dessa classe que forem instanciados devem ter. É muito similar ao que podemos obter por reflexão na classe “class”, mas é claro que é um formato em baixo nível muito menos trabalho e mais compacto.
Quando uma subclasse é criada, uma nova estrutura aparece, descrevendo essa subclasse. Existem duas abordagens que são usadas aqui, não sei exatamente qual é a do java, mas creio que seja a segunda.
-
A subclasse pode ter um ponteiro para a classe pai, e uma cópia apenas dos métodos que sofrem polimorfismo (no caso do C++, isso é explicitamente dito através da palavra chave virtual).
-
A subclasse pode ter uma cópia da estrutura do pai, e também o ponteiro para a superclasse, para que sejamos capazes de identificar a hierarquia de classes. Essa me parece ser a abordagem do java, já que todos os métodos são virtuais.
Estamos falando de classes e estruturas que descrevem classes.
Cada objeto criado, irá usar a estrutura de sua subclasse específica apenas para criar os seus atributos, nesse caso, sem repetição dos ponteiros de método. Haverá apenas um ponteiro para o descritor de sua classe específica, e não uma cópia de toda estrutura, como vc provavelmente pensou.
Quanto ocupa uma estrutura que descreve uma classe? Alguns bytes. Uma classe muito grande pode chegar a alguns kb. Ainda sim, essas estruturas são únicas (no caso do Java, únicas por classloader) e não devem ocupar muita memória. Por isso, volto a repetir, não faça disso uma preocupação. Acho até meio que perda de tempo entrar em detalhes como esse… a menos que você vá desenvolver software para algum microcontrolador ou hardware limitado.