frente - pack java para que sirve
A qué método sobrecargado se llama en Java (5)
Solución específica del problema
En algunos idiomas, los parámetros se resuelven a su tipo dinámico, pero no en java.
El compilador ya determina en el momento de la compilación dónde está su
getWorkDetail(this);
iré.
this
es de tipo
Person
, por lo que se
getWorkDetail(Person e)
.
En su caso específico la solución es bastante obvia.
Como otros ya han señalado, deberá anular
getWorkDetail()
en la clase
Employee
.
Resolviendo métodos a sus tipos de parámetros dinámicos.
Para resolver el problema general de resolver tipos de parámetros en el tiempo de ejecución, se debe evitar el uso de la
instanceof
operador, ya que generalmente conduce a un código sucio.
Si tiene dos clases diferentes, ya no es posible una solución tan simple como se indicó anteriormente. En estos casos tendrás que utilizar el patrón de visitante .
Considera las siguientes clases:
public interface Animal {
default void eat(Food food) {
food.eatenBy(this);
}
void eatMeat(Meat meat);
void eatVegetables(Vegetables vegetables);
}
public class Shark implements Animal {
public void eatMeat (Meat food) {
System.out.println("Tasty meat!");
}
public void eatVegetables (Vegetables food) {
System.out.println("Yuck!");
}
}
public interface Food {
void eatenBy(Animal animal);
}
public class Meat implements Food {
public void eatenBy(Animal animal) {
animal.eatMeat(this);
}
}
public class Vegetables implements Food {
public void eatenBy(Animal animal) {
animal.eatVegetables(this);
}
}
Que puedes llamar así:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
Siguiendo el
patrón de
Animal.eat
,
Animal.eat
llamará
Food.eatenBy
, que se implementa tanto en la
Meat
como en las
Vegetables
.
Esas clases llamarán el método más específico
eatMeat
o
eatVegetables
, que utiliza los tipos correctos (dinámicos).
Tengo una situación de herencia básica con un método sobrecargado en la súper clase.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
La siguiente clase de
Employee
extiende la clase de
Person
arriba:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
El método principal simplemente crea un objeto
Employee
(tanto de tipo estático como dinámico) y llama a
.work()
en él:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
Esto termina imprimiendo.
This person is not an Employee
Al analizar esto, pensé que dado que tanto el tipo estático como el dinámico del objeto
e1
es
Employee
, llamaría al método sobrecargado en Persona que toma a un
Employee
como parámetro.
Ya que estoy claramente equivocado acerca de esto, abrí un depurador asumiendo que la referencia a "esto" en la línea
getWorkDetail(this)
en la clase
Person
debe haberse transformado en su súper clase.
Sin embargo esto no es lo que encontré.
Claramente, en este punto del código,
this
es un objeto
Employee
, sin embargo, todavía eligió ejecutar el método sobrecargado
getWorkDetail(Person p)
.
¿Alguien puede explicar este comportamiento?
A diferencia de las anulaciones de métodos, las sobrecargas de métodos se vinculan en función del tipo estático.
Y en este caso,
getWorkDetail(this)
en
Person
solo conoce el tipo de
Person
.
La sobrecarga de métodos no está diseñada para proporcionar un comportamiento dinámico en tiempo de ejecución.
Para aprovechar el enlace dinámico, es posible que deba rediseñar su código para anular los métodos, en su lugar:
public static void main(String[] args) throws IOException {
new Employee("Manager1", 1976, "Female").getWorkDetail();
new Person("Manager1", 1976, "Female").getWorkDetail();
}
Y modificar el comportamiento basado en la implementación de clases. Por supuesto, puede sobrecargar los métodos, siempre y cuando se ocupe de anular los métodos sobrecargados, si es necesario.
class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex) {
name = theName;
dob = birth;
gender = sex;
}
public void getWorkDetail() {
System.out.println("This person is not an Employee");
}
}
class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex) {
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
public void getWorkDetail() {
System.out.println("This person is an Employee");
}
}
La resolución de sobrecarga ocurre durante el tiempo de compilación, no en tiempo de ejecución.
Por lo tanto, cuando llama a
getWorkDetails(this)
, se asume que se trata de una
Person
(que es el tipo estático) y, por lo tanto, se denomina la sobrecarga correspondiente.
Nota: el uso de
this
clase dentro de
Employee
la habría convertido en un tipo de
Employee
.
Puedes verificar esto sobrecargando el
work()
en
Employee
esta manera.
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
getWorkDetail (esto) no sabe cuáles son las subclases. llamar a getWorkDetail en su lugar.
Preferencia de llamada
class Foo {
static void test(int arg) { System.out.println("int"); }
static void test(float arg) { System.out.println("float"); }
static void test(Integer arg) { System.out.println("Integer"); }
static void test(int... arg) { System.out.println("int..."); }
public static void main(String[] arg) {
test(6);
}
}
La salida se imprimirá en la consola.
Ahora comenta el primer método de
test()
y ve cuál es el resultado que viene.
Esta es la preferencia hirarchey en los tipos de datos primitivos.
Ahora llegando a tipos derivados declaran una clase
FooChild
como esta
class FooChild extends Foo {
}
y crear dos nuevos métodos en
Foo
como
static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }
luego, en el método principal, intente llamar a
testChild
como este
testChild(new FooChild());
.