Alguém pode fornecer um exemplo simples que explica a diferença entre o polimorfismo dinâmico e estático em Java?
Alguém pode fornecer um exemplo simples que explica a diferença entre o polimorfismo dinâmico e estático em Java?
Respostas:
Polimorfismo
1. Vinculação estática / vinculação de tempo de compilação / vinculação inicial / sobrecarga de método. (Na mesma classe)
2. Vinculação dinâmica / vinculação em tempo de execução / vinculação tardia / modificação de método. (Em classes diferentes)
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Animal reference but Dog object
, por que não podemos usar Dog reference and dog object
?
A sobrecarga de método seria um exemplo de polimorfismo estático
enquanto a substituição seria um exemplo de polimorfismo dinâmico.
Porque, em caso de sobrecarga, em tempo de compilação o compilador sabe qual método vincular à chamada. No entanto, é determinado em tempo de execução para polimorfismo dinâmico
Polimorfismo dinâmico (tempo de execução) é o polimorfismo existente no tempo de execução. Aqui, o compilador Java não entende qual método é chamado no momento da compilação. Apenas a JVM decide qual método é chamado em tempo de execução. Sobrecarga de método e substituição de método usando métodos de instância são os exemplos de polimorfismo dinâmico.
Por exemplo,
Considere um aplicativo que serializa e desserializa diferentes tipos de documentos.
Podemos ter 'Documento' como a classe base e diferentes classes de tipo de documento derivadas dela. Por exemplo, XMLDocument, WordDocument, etc.
A classe de documento definirá os métodos 'Serialize ()' e 'De-serialize ()' como virtuais e cada classe derivada implementará esses métodos em sua própria maneira, com base no conteúdo real dos documentos.
Quando diferentes tipos de documentos precisam ser serializados / desserializados, os objetos do documento serão referenciados pela referência de classe 'Documento' (ou ponteiro) e quando os métodos 'Serialize ()' ou 'De-serialize ()' são chamados nele, versões apropriadas dos métodos virtuais são chamadas.
Polimorfismo estático (tempo de compilação) é o polimorfismo exibido em tempo de compilação. Aqui, o compilador Java sabe qual método é chamado. Sobrecarga de método e substituição de método usando métodos estáticos; substituição de métodos usando métodos privados ou finais são exemplos de polimorfismo estático
Por exemplo,
Um objeto funcionário pode ter dois métodos print (), um sem argumentos e outro com uma string de prefixo para ser exibida junto com os dados do funcionário.
Dadas essas interfaces, quando o método print () é chamado sem nenhum argumento, o compilador, observando os argumentos da função, sabe qual função deve ser chamada e gera o código-objeto de acordo.
Para obter mais detalhes, leia "O que é polimorfismo" (Google it).
Vinculação refere-se ao link entre a chamada do método e a definição do método.
Esta imagem mostra claramente o que é obrigatório.
Nesta figura, a chamada “a1.methodOne ()” é vinculada à definição do methodOne () correspondente e a chamada “a1.methodTwo ()” é vinculada à definição do methodTwo () correspondente.
Para cada chamada de método, deve haver uma definição de método adequada. Esta é uma regra em java. Se o compilador não vê a definição de método apropriada para cada chamada de método, ele gera um erro.
Agora, vamos à vinculação estática e à vinculação dinâmica em java.
Vinculação estática em Java:
A vinculação estática é uma vinculação que ocorre durante a compilação. Também é chamado de vinculação inicial porque a vinculação acontece antes de um programa realmente ser executado
.
A ligação estática pode ser demonstrada como na imagem abaixo.
Nesta figura, 'a1' é uma variável de referência do tipo Classe A apontando para o objeto da classe A. 'a2' também é uma variável de referência do tipo classe A, mas apontando para o objeto da Classe B.
Durante a compilação, durante a vinculação, o compilador não verifica o tipo de objeto para o qual uma determinada variável de referência está apontando. Ele apenas verifica o tipo de variável de referência através da qual um método é chamado e verifica se existe uma definição de método para ele nesse tipo.
Por exemplo, para a chamada do método “a1.method ()” na imagem acima, o compilador verifica se existe definição de método para o método () na Classe A. Porque 'a1 ′ é do tipo Classe A. Da mesma forma, para chamada de método “a2.method ()”, ele verifica se existe definição de método para method () na Classe A. Porque 'a2' também é do tipo Classe A. Ele não verifica para qual objeto 'a1' e 'a2' estão apontando. Esse tipo de vinculação é denominado vinculação estática.
Vinculação dinâmica em Java:
A vinculação dinâmica é uma vinculação que ocorre durante o tempo de execução. Também é chamado de vinculação tardia porque a vinculação ocorre quando o programa está realmente em execução.
Durante o tempo de execução, os objetos reais são usados para vinculação. Por exemplo, para a chamada “a1.method ()” na imagem acima, o método () do objeto real para o qual 'a1' está apontando será chamado. Para a chamada de “a2.method ()”, o método () do objeto real para o qual 'a2' está apontando será chamado. Esse tipo de vinculação é denominado vinculação dinâmica.
A ligação dinâmica do exemplo acima pode ser demonstrada como abaixo.
Referência static-binding-and-dynamic-binding-in-java
Polimorfismo: Polimorfismo é a capacidade de um objeto de assumir várias formas. O uso mais comum de polimorfismo em OOP ocorre quando uma referência de classe pai é usada para se referir a um objeto de classe filho.
Polimorfismo de ligação dinâmica / tempo de execução:
Polimorfismo de tempo de execução, também conhecido como substituição de método. Neste mecanismo pelo qual uma chamada para uma função substituída é resolvida em um tempo de execução.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Resultado:
Método de partida interno do carro
Polimorfismo de ligação estática / tempo de compilação:
Qual método deve ser chamado é decidido apenas em tempo de compilação.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
Resultado: Método de classificação interna da coleção
sobrecarga de método é um exemplo de tempo de compilação / polimorfismo estático porque a vinculação de método entre a chamada do método e a definição do método acontece em tempo de compilação e depende da referência da classe (referência criada em tempo de compilação e vai para a pilha).
a sobreposição de método é um exemplo de polimorfismo dinâmico / em tempo de execução porque a vinculação de método entre a chamada e a definição do método ocorre em tempo de execução e depende do objeto da classe (objeto criado em tempo de execução e vai para o heap).
Em termos simples :
Polimorfismo estático : o mesmo nome de método está sobrecarregado com diferentes tipos ou números de parâmetros na mesma classe (assinatura diferente). A chamada do método direcionado é resolvida em tempo de compilação.
Polimorfismo dinâmico : o mesmo método é sobrescrito com a mesma assinatura em classes diferentes . O tipo de objeto no qual o método está sendo chamado não é conhecido em tempo de compilação, mas será decidido em tempo de execução.
Geralmente, a sobrecarga não é considerada polimorfismo.
Da página do tutorial Java :
As subclasses de uma classe podem definir seus próprios comportamentos exclusivos e ainda compartilhar algumas das mesmas funcionalidades da classe pai
Generally overloading won't be considered as polymorphism.
você pode elaborar sobre este ponto.
A sobrecarga de método é conhecida como polimorfismo estático e também conhecida como polimorfismo em tempo de compilação ou vinculação estática porque as chamadas de método sobrecarregadas são resolvidas em tempo de compilação pelo compilador com base na lista de argumentos e na referência na qual estamos chamando o método.
E método de substituição é conhecido como dinâmico Polimorfismo ou simples Polimorfismo ou Runtime Método de despacho ou vinculação dinâmica porque substituído chamada de método são resolvidos em tempo de execução.
Para entender por que isso é por isso vamos dar um exemplo de Mammal
e Human
classe
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
Eu incluí a saída, bem como o bytecode nas linhas de código abaixo
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
E olhando para o código acima, podemos ver que os bytecodes de humanMammal.speak (), human.speak () e human.speak ("Hindi") são totalmente diferentes porque o compilador é capaz de diferenciar entre eles com base na lista de argumentos e referência de classe. E é por isso que a sobrecarga de método é conhecida como polimorfismo estático .
Mas o bytecode para anyMammal.speak () e humanMammal.speak () é o mesmo porque, de acordo com o compilador, ambos os métodos são chamados na referência Mammal, mas a saída para ambas as chamadas de método é diferente porque no tempo de execução JVM sabe qual objeto uma referência está mantendo e chamadas JVM o método no objeto e é por isso que a Substituição de Método é conhecida como Polimorfismo Dinâmico.
Portanto, pelo código e bytecode acima, é claro que durante a fase de compilação o método de chamada é considerado a partir do tipo de referência. Mas em tempo de execução o método será chamado a partir do objeto que a referência está segurando.
Se você quiser saber mais sobre isso, pode ler mais em Como a JVM trata a sobrecarga e a substituição de métodos internamente .
Polimorfismo estático: é onde a decisão de decidir qual método realizar, é determinada durante o tempo de compilação. A sobrecarga do método pode ser um exemplo disso.
Polimorfismo Dinâmico: é onde a decisão de escolher qual método executar, é definida durante o tempo de execução. A substituição de método pode ser um exemplo disso.
Polimorfismo se refere à capacidade de um objeto de se comportar de maneira diferente para o mesmo gatilho.
Polimorfismo estático (polimorfismo em tempo de compilação)
Polimorfismo dinâmico (polimorfismo de tempo de execução)
Polimorfismo de tempo de compilação (Static Binding / Early Binding): No polimorfismo estático, se chamarmos um método em nosso código, então qual definição desse método deve ser chamada realmente é resolvida apenas no tempo de compilação.
(ou)
Em tempo de compilação, Java sabe qual método invocar verificando as assinaturas do método. Portanto, isso é chamado de polimorfismo em tempo de compilação ou ligação estática.
Polimorfismo dinâmico (Late Binding / Runtime Polymorphism): Em tempo de execução, o Java espera até o tempo de execução para determinar qual objeto está realmente sendo apontado pela referência. A resolução do método foi tomada em tempo de execução, por isso chamamos de polimorfismo de tempo de execução.
Considere o código abaixo:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
Agora, olhando para o código, você nunca pode dizer qual implementação de methodA () será executada, porque depende de qual valor o usuário dá durante o tempo de execução. Portanto, só é decidido em tempo de execução qual método será chamado. Conseqüentemente, polimorfismo de tempo de execução.
A sobrecarga de método é um polimorfismo em tempo de compilação, vamos dar um exemplo para entender o conceito.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
Neste exemplo, Pessoa tem um método de comer que representa que ela pode comer Pizza ou Macarrão. Que o método eat está sobrecarregado quando compilamos este Person.java o compilador resolve a chamada do método "e.eat (noodles) [que está na linha 6] com a definição do método especificada na linha 8, ou seja, é o método que leva macarrão como parâmetro e todo o processo é feito pelo Compilador, portanto é Polimorfismo em tempo de compilação O processo de substituição da chamada do método pela definição do método é chamado de ligação, neste caso, é feito pelo compilador, por isso é chamado de ligação inicial.
Seguindo a resposta de Naresh, o polimorfismo dinâmico é apenas 'dinâmico' em Java por causa da presença da máquina virtual e sua capacidade de interpretar o código em tempo de execução, em vez do código rodando nativamente.
Em C ++, isso deve ser resolvido em tempo de compilação se estiver sendo compilado para um binário nativo usando gcc, obviamente; no entanto, o salto e a conversão do tempo de execução na tabela virtual ainda são chamados de 'pesquisa' ou 'dinâmica'. Se C herdar B e você declarar B* b = new C(); b->method1();
, b será resolvido pelo compilador para apontar para um objeto B dentro de C (para uma classe simples herda uma situação de classe, o objeto B dentro de C e C começarão no mesmo endereço de memória, então nada precisa ser feito; ele estará apontando para o vptr que ambos usam). Se C herdar B e A, a tabela de função virtual do objeto A dentro da entrada C para o método1 terá uma conversão que deslocará o ponteiro para o início do objeto C que encapsula e o passará para o A :: método1 real () no segmento de texto que C substituiu. ParaC* c = new C(); c->method1()
, c estará apontando para o objeto C externo já e o ponteiro será passado para C :: method1 () no segmento de texto. Consulte: http://www.programmersought.com/article/2572545946/
Em java, for B b = new C(); b.method1();
, a máquina virtual é capaz de verificar dinamicamente o tipo do objeto pareado com be pode passar o ponteiro correto e chamar o método correto. A etapa extra da máquina virtual elimina a necessidade de tabelas de funções virtuais ou o tipo sendo resolvido em tempo de compilação, mesmo quando poderia ser conhecido em tempo de compilação. É apenas uma maneira diferente de fazer isso, o que faz sentido quando uma máquina virtual está envolvida e o código é compilado apenas em bytecode.