Estoy aprendiendo la herencia de Java en VScode (características de la herencia de Java, palabra clave super, comparación entre super y this, reescritura de métodos, constructor de subclases) II

Los miembros de la clase incluyen: variables miembro; métodos miembro; métodos de construcción.

Método de construcción: no importa qué modificadores se puedan heredar.
Variables miembro: todas se pueden heredar, pero preste atención a un punto (¡herencia! = llamada, las privadas no se pueden llamar)
Métodos de miembros: los no privados pueden. No privado.

Página de inicio de mi blog personal: si '' realmente puede escapar 1️⃣ diga 1️⃣ página de inicio del blog
sobre el aprendizaje de gramática básica de Java ----> puede consultar mi blog: "Aprendo Java en VScode"
sobre -> puede consultar mi blog Este artículo "Aprendo la herencia de Java en VScode (qué es la herencia de Java, características, qué significa la herencia de subclases) 1"

Directorio de artículos

Características del acceso a variables miembro en herencia: el principio de proximidad

Esto significa que si hay una variable miembro con el mismo nombre que la clase principal en la subclase, la subclase accederá preferentemente a su propia variable miembro en lugar de a la variable miembro con el mismo nombre heredada de la clase principal.

Específicamente, cuando se usa una variable miembro en una subclase, el sistema primero verifica si la subclase misma tiene esta variable miembro y, de ser así, usa directamente la variable miembro de la subclase. Si no existe dicha variable miembro en la subclase, el sistema continuará buscando hacia arriba para encontrar si hay una variable miembro con el mismo nombre en la clase principal. Si se encuentra una variable miembro con el mismo nombre en la clase principal, se utilizará la variable miembro de la clase principal.

Esta característica garantiza que en la relación de herencia, las subclases puedan ocultar o anular las variables miembro de la clase principal definiendo variables miembro con el mismo nombre que la clase principal. De esta forma, las subclases pueden personalizar las variables miembro heredadas de la clase principal según sus propias necesidades.

Cabe señalar que aunque la subclase puede ocultar las variables miembro de la clase principal, esto no afecta las variables miembro de la clase principal en sí, y las variables miembro de la clase principal todavía existen en la clase principal. Si necesita acceder a las variables miembro de la clase principal en la subclase, puede usar la palabra clave super para hacer referencia a las variables miembro de la clase principal.
inserte la descripción de la imagen aquí

súper palabra clave

En Java, superes una palabra clave que se utiliza para indicar una referencia a una clase principal o superclase (clase base). Se puede utilizar en subclases para acceder a variables miembro, métodos miembro o constructores de la clase principal. Existen principalmente los siguientes usos:

  1. Acceda a las variables miembro de la clase principal: use superpalabras clave para acceder a las variables miembro de la clase principal en la subclase, incluso si hay una variable miembro con el mismo nombre en la subclase.

  2. Llame al método miembro de la clase principal: en la subclase, use superpalabras clave para llamar al método en la clase principal que está anulado por la subclase, o llame al método en la clase principal que no está cubierto por la subclase.

  3. Llame al constructor de la clase principal: en el constructor de la subclase, el superconstructor de la clase principal se puede llamar explícitamente mediante palabras clave para garantizar que se ejecute la lógica de inicialización en la clase principal.

El uso de superpalabras clave puede ayudar a las subclases a interactuar y heredar de las clases principales, extendiendo y reutilizando así el código de manera efectiva.

super y esta comparacion

En Java, thistanto las palabras clave como superlas palabras clave se utilizan para acceder a miembros de una clase o llamar a un constructor, pero tienen diferentes funciones y usos.

关键字:
- `this`:用于引用当前类的实例,用于访问当前类的成员变量、方法和构造方法。
- `super`:用于引用当前类的父类,用于访问父类的成员变量、方法和构造方法。

1. thisPalabra clave:

`this` 关键字用于引用当前类的实例。可以理解为一个变量。
		表示当前对象的地址,并且用于访问或调用当前类的成员变量和方法。
实际上是通过这个方法的隐式参数来传递当前对象的引用。
		这个隐式参数就是 this,它指向当前调用该方法的对象。
  • Se utiliza para referirse a la instancia del objeto actual, es decir, el objeto cuyo método o constructor se está invocando actualmente.
  • Se puede utilizar para eliminar la ambigüedad entre variables miembro y variables locales si tienen el mismo nombre.
  • Se puede utilizar para llamar a otros constructores de la clase para reutilizar el código en un constructor (sobrecarga de constructores).

2. superPalabras clave:

`super` 关键字用于引用当前类的父类(超类)。
	它表示父类的存储空间,并且用于访问或调用父类的成员变量、方法或构造方法。
  • Se utiliza para referirse a miembros de la clase principal (superclase) o para llamar al constructor de la clase principal.
  • Se puede acceder supera los métodos y miembros de la superclase a través de palabras clave, especialmente cuando el método de la superclase se anula en la subclase.
  • En el método de construcción de la subclase, puede usar superpalabras clave para llamar al método de construcción de la clase principal para garantizar que se pueda ejecutar el trabajo de inicialización de la clase principal.

3. Ejemplo:

class Parent {
    
    
    int value = 10;

    void display() {
    
    
        System.out.println("Parent class method");
    }
}

class Child extends Parent {
    
    
    int value = 20;

    void display() {
    
    
        System.out.println("Child class method");
    }

    void printValues() {
    
    
        int value = 30;
        System.out.println(value); // Prints local variable value (30)
        System.out.println(this.value); // Prints Child class variable value (20)
        System.out.println(super.value); // Prints Parent class variable value (10)

        this.display(); // Calls Child class method
        super.display(); // Calls Parent class method
    }
}
Resumir:
  • thisLas palabras clave se utilizan para referencias de objetos actuales y llamadas al constructor.
  • superLas palabras clave se utilizan para acceder a los miembros de la superclase y llamar a los constructores de la superclase.
uso:
  • Acceder a variables miembro: this.成员变量名indica las variables miembro de la clase actual y super.成员变量名las variables miembro de la clase principal.
  • Método miembro de acceso: this.方法名(...)significa el método miembro de la clase actual, super.方法名(...)significa el método miembro de la clase principal.
  • Constructor de acceso: this(...)indica el método de construcción de la clase actual y super(...)el método de construcción de la clase principal.
1.> Cuando los nombres de las variables locales y las variables miembro son diferentes, thisse puede omitir la palabra clave.

En Java, si la variable local en el método no tiene el mismo nombre que la variable miembro de la clase, el compilador las distinguirá automáticamente y usará la variable local primero. Entonces, cuando no hay conflicto de nombres, puede omitir thisla palabra clave para hacer referencia a las variables miembro de la clase.

Sin embargo, cuando una variable local y una variable miembro tienen el mismo nombre, para especificar claramente que está utilizando una variable miembro de la clase, debe usar la palabra thisclave para distinguirlas.

public class Student {
    
    
    private String name; // 成员变量

    public Student(String name) {
    
    
        // 参数name和成员变量name同名,需要使用this关键字来区分
        this.name = name;
    }

    public void displayInfo(String name) {
    
    
        // 参数name和成员变量name不同名,可以省略this关键字
        System.out.println("传入的参数name:" + name);
        System.out.println("成员变量name:" + this.name);
    }
}

En el ejemplo anterior,Los parámetros en el constructor tienen el mismo nombre nameque las variables miembro de la clase name , por lo que usamos this.namepara referirnos a las variables miembro..
En el método displayInfo, los parámetros namey las variables miembro name tienen nombres diferentes, por lo que podemos omitir this palabras clave y usar variables locales directamente name.

2.> this(...) Se utiliza para llamar a otros constructores de la misma clase en un constructor. Sólo se puede utilizar dentro del constructor y debe ser la primera declaración del constructor.
 // Constructor with three parameters___具有三个参数的构造函数
    public Student(String name, int age, String school) {
    
    
        this.name = name;
        this.age = age;
        this.school = school;
    }

    // Constructor with no parameters, calling the three-parameter constructor using this(...)
    //没有参数的构造函数,使用以下(...)调用三参数构造函数
    public Student() {
    
    
        this(null, 0, "Magic_School");
    }

En Java, si hay variables miembro con el mismo nombre, se pueden distinguir mediante palabras clave específicas. Generalmente hay tres formas:

就近原则

1. Comience desde la posición local y busque hacia arriba:

Si se define una variable local con el mismo nombre en el alcance actual (método o bloque de código), anulará la variable miembro con el mismo nombre. En este caso, para acceder a las variables miembro, puede utilizar thispalabras clave para indicar claramente que desea acceder a las variables miembro de la clase actual.

public class MyClass {
    
    
    private String name = "Class member variable";

    public void printName(String name) {
    
    
        System.out.println(name);       // 局部变量name
        System.out.println(this.name);  // 类的成员变量name
    }
}

2. Busque hacia arriba desde la posición del miembro de esta clase:

Si una variable miembro con el mismo nombre aparece en diferentes métodos de la clase actual, puede usar directamente el nombre de la variable miembro para acceder y el compilador seleccionará automáticamente la variable miembro correcta.

public class MyClass {
    
    
    private String name = "Class member variable";

    public void method1() {
    
    
        System.out.println(name);  // 类的成员变量name
    }

    public void method2() {
    
    
        System.out.println(name);  // 类的成员变量name
    }
}

3. Mire hacia arriba desde la posición del miembro padre de la clase:

Si la clase actual hereda de otras clases y hay variables miembro con el mismo nombre en la clase principal y en la clase secundaria, puede usar superpalabras clave para acceder a las variables miembro de la clase principal.

public class ParentClass {
    
    
    protected String name = "Parent class member variable";
}

public class ChildClass extends ParentClass {
    
    
    private String name = "Child class member variable";

    public void printNames() {
    
    
        System.out.println(name);          // 子类的成员变量name
        System.out.println(this.name);     // 子类的成员变量name
        System.out.println(super.name);    // 父类的成员变量name
    }
}

Resumen: en Java, al usar thispalabras clave, puede apuntar a las variables miembro de la clase actual y superlas palabras clave pueden apuntar a las variables miembro de la clase principal. Usando diferentes palabras clave, puede acceder a las variables miembro correctas.

esta palabra clave + súper palabra clave

在Java中,如果在不同的作用域(例如实例变量和局部变量)中出现了同名的变量,
	可以使用`this`关键字来引用实例变量并访问正确的变量。`
this`关键字是对当前类实例的引用。

Por ejemplo:

public class MyClass {
    
    
    private String name; // 这是实例变量

    public MyClass(String name) {
    
    
        this.name = name; // 使用"this"关键字来给实例变量赋值
    }

    public void printName() {
    
    
        String name = "局部变量"; // 这是局部变量
        System.out.println(name); // 这里引用的是局部变量
        System.out.println(this.name); // 这里引用的是实例变量
    }
}
类似地,如果一个类继承自另一个父类,并且两个类中有同名的变量,
	可以使用`super`关键字来引用父类的变量。

Por ejemplo:

public class ParentClass {
    
    
    protected String name = "父类成员变量";
}

public class ChildClass extends ParentClass {
    
    
    private String name = "子类成员变量";

    public void printNames() {
    
    
        System.out.println(name); // 这里引用的是子类的变量
        System.out.println(this.name); // 这里也引用的是子类的变量
        System.out.println(super.name); // 这里引用的是父类的变量
    }
}

Resumen: en Java, thislas palabras clave se utilizan para hacer referencia a la instancia de clase actual y superlas palabras clave se utilizan para hacer referencia a la clase principal. Estas palabras clave son útiles cuando necesita acceder a variables con el mismo nombre pero que pertenecen a diferentes ámbitos o clases.

Características del acceso al método miembro en herencia: principio de proximidad + superllamada:

En la herencia de Java, el acceso a métodos de miembros tiene dos características importantes: el principio de proximidad y el uso de superllamadas de palabras clave.

1. Principio de proximidad:

Java中的就近原则是指在方法调用或变量访问时,会优先选择离当前位置最近的方法或变量。
	这意味着如果在当前类中存在与父类相同名称的方法或变量,Java会优先使用当前类中的方法或变量。	

El principio de proximidad significa que en la cadena de herencia, si hay métodos miembro con el mismo nombre en la subclase y en la clase principal, la subclase llamará primero a su propio método, en lugar del método de la clase principal. En otras palabras, los métodos de la subclase "cubren" (sobrescriben) los métodos de la superclase. Esta característica permite a las subclases personalizar o modificar métodos heredados según sea necesario.

class Parent {
    
    
    void print() {
    
    
        System.out.println("This is the parent's print method.");
    }
}

class Child extends Parent {
    
    
    void print() {
    
    
        System.out.println("This is the child's print method.");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Child child = new Child();
        child.print(); // Output: This is the child's print method.
    }
}

En el ejemplo anterior, el método Childde la clase secundaria printanula el método de la Parentclase principal print.

2. Utilice superla palabra clave llamada:

通过super关键字,可以直接访问父类中的方法或变量。

A veces, es posible que el método de la subclase necesite llamar al método cubierto de la clase principal, lo que se puede superlograr mediante el uso de palabras clave. superLa palabra clave permite llamar a un método de una superclase en una subclase, incluso si la subclase anula el método.

class Parent {
    
    
    void print() {
    
    
        System.out.println("This is the parent's print method.");
    }
}

class Child extends Parent {
    
    
    void print() {
    
    
        super.print(); // Call the parent's print method
        System.out.println("This is the child's print method.");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Child child = new Child();
        child.print();
        /* Output:
           This is the parent's print method.
           This is the child's print method.
        */
    }
}

En el ejemplo anterior, el método Childde la subclase printprimero usa el método super.print()que llama a la clase principal Parenty printluego realiza la salida de la subclase misma.

Resumen:
en la herencia de Java, los métodos miembro siguen el principio de proximidad y los métodos de las subclases llamarán primero a sus propios métodos, en lugar de a los métodos de la clase principal. Pero si necesita llamar al método de la clase principal, puede usar superpalabras clave para lograrlo.

Ejemplo de código:

class Person {
    
    
    public void eat() {
    
    
        System.out.println("Person eats rice and vegetables");
    }

    public void drink() {
    
    
        System.out.println("Person drinks water");
    }
}

class Student extends Person {
    
    
    public void lunch() {
    
    
        // 首先,检查在本类中是否有"eat"和"drink"方法,如果有,则调用本类中的方法。
        this.eat();
        this.drink();
        // 然后,直接调用父类(Person)中的"eat"和"drink"方法。
        super.eat();
        super.drink();
    }
}

// OverseasStudent类,继承自Person类
class OverseasStudent extends Person {
    
    
    public void lunch() {
    
    
        // 首先,检查在本类(OverseasStudent)中是否有"eat"和"drink"方法, 如果有,则调用本类中的方法。

        this.eat();
        this.drink();
        // 然后,直接调用父类(Person)中的"eat"和"drink"方法。

        super.eat();
        super.drink();
    }
    // 重写Person类中的"eat"方法
    @Override
    public void eat() {
    
    
        System.out.println("OverseasStudent eats spaghetti");
    }
    
    // 重写Person类中的"drink"方法
    @Override
    public void drink() {
    
    
        System.out.println("OverseasStudent drinks cold water");
    }
}

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Student localStudent = new Student();
        localStudent.lunch();

        System.out.println("--------------------");

        OverseasStudent overseasStudent = new OverseasStudent();
        overseasStudent.lunch();
    }
}

Producción:

Person eats rice and vegetables
Person drinks water
Person eats rice and vegetables
Person drinks water
--------------------
OverseasStudent eats spaghetti
OverseasStudent drinks cold water
Person eats rice and vegetables
Person drinks water

Explicar el código:

En Java, la palabra clave this se usa para llamar a métodos en la clase actual o acceder a variables miembro de la clase actual, y la palabra clave super se usa para llamar a métodos en la clase principal o acceder a variables miembro de la clase principal.

En el método del almuerzo, this.eat() y this.drink() llaman a los métodos de comer y beber reescritos en la clase actual (OverseasStudent o Student). Y super.eat() y super.drink() llaman a los métodos comer y beber en la clase principal (Persona).

Por lo tanto, cuando OverseasStudent o Student llama al método de almuerzo, primero llamará al método anulado en la clase actual y luego llamará al método en la clase principal.

En el código, la clase OverseasStudent anula los métodos de comer y beber en la clase Persona. Cuando el objeto OverseasStudent llama al método de almuerzo, primero verifica si hay métodos para comer y beber en la clase OverseasStudent y, de ser así, llama a los métodos en la clase OverseasStudent. Por lo tanto, cuando el objeto OverseasStudent llama al método de almuerzo, generará "OverseasStudent come espagueti" y "OverseasStudent bebe agua fría".

Luego, el método de almuerzo en la clase OverseasStudent llama directamente a los métodos de comer y beber en la clase principal Persona, usando la palabra clave super. Esto hace que se llame a los métodos comer y beber en la clase principal. Por lo tanto, el objeto OverseasStudent generará "La persona come arroz y verduras" y "La persona bebe agua" después de llamar al método del almuerzo.

Por el contrario, el objeto localStudent es una instancia de la clase Student sin anular los métodos de comer y beber en la clase Person. Por lo tanto, cuando el objeto localStudent llama al método de almuerzo, primero verifica si hay métodos de comer y beber en la clase Estudiante, descubre que no los hay y luego llama directamente a los métodos de comer y beber en la clase principal Persona. Esto explica por qué el resultado de salida de llamar al método lunch del objeto localStudent es diferente del del objeto OverseasStudent, pero igual que el resultado de salida de la clase principal Persona.

La anulación de métodos (anulación de métodos) es un concepto importante en la programación orientada a objetos, que permite a las subclases redefinir métodos con el mismo nombre, lista de parámetros y tipo de retorno que los de la clase principal para lograr su propia implementación específica. La anulación de métodos es la clave para lograr el polimorfismo en tiempo de ejecución.

重写方法的核心目的是允许子类提供自己特定的实现,以便更好地适应子类的行为和需求。
	在运行时,当子类对象调用被重写的方法时,会优先执行子类中的实现,而不是父类中的实现,
这实现了运行时多态性。这意味着父类引用指向子类对象时,根据对象的实际类型来决定调用哪个方法。

1. El nombre del método de reescritura y la lista de parámetros formales deben ser coherentes:

Cuando la subclase necesita reescribir el método de la clase principal, debe asegurarse de que el nombre del método reescrito y la lista de parámetros formales sean exactamente los mismos que los del método de la clase principal. Esto significa que el nombre del método y los tipos de parámetros, el número de parámetros y el orden de los parámetros en la subclase deben ser los mismos que los del método de la clase principal. Esto es para garantizar que las subclases puedan anular (anular) correctamente los métodos de la clase principal para que se llame al método correcto en tiempo de ejecución según el tipo real del objeto.

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Dog is barking");
    }
}

En este ejemplo, la clase Perro extiende la clase Animal y anula el método makeSound. El nombre del método y la lista de parámetros formales en la subclase son exactamente los mismos que los de la clase principal.

ilustrar:

inserte la descripción de la imagen aquí

Presta atención al problema:

为什么Animal可以new一个Dog,而Dog不可以new一个Animal()
Animal ccc = new Dog();
ccc.makeSound();
Dog eee = new Animal();
eee.makeSound();

En Java, una clase puede crear una instancia de otra clase siempre que la clase que se está creando sea una subclase de la clase que se está creando. Esto se debe a que la subclase hereda las propiedades y métodos de la clase principal, por lo que se puede hacer referencia al objeto de la subclase a través de la referencia de la clase principal.

在你的代码中,Dog是Animal的子类,所以可以使用Animal类的引用来创建一个Dog对象。
	这是因为Dog继承了Animal的属性和方法。
然而,Animal不是Dog的子类,所以不能使用Dog类的引用来创建一个Animal对象。
	这是因为Animal类可能没有Dog类特有的属性和方法。
所以,你可以使用Animal类的引用来创建一个Dog对象,
	但不能使用Dog类的引用来创建一个Animal对象。

No se puede asignar una referencia de superclase a una subclase:

inserte la descripción de la imagen aquí
Si desea llamar al método fetch () de la clase Perro, primero debe convertir el objeto de tipo Animal al tipo Perro y luego llamar al método fetch (). Esto se puede lograr usando un yeso.((Dog)ddd).fetch();

Otros ejemplos de código:
class Animal {
    
    
    public void eat() {
    
    
        System.out.println("Animal is eating.");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void eat() {
    
    
        System.out.println("Dog is eating.");
    }

    public void bark() {
    
    
        System.out.println("Dog is barking.");
    }
}

public class Mains {
    
    
    public static void main(String[] args) {
    
    
        Animal animal = new Animal();
        animal.eat(); // 输出: Animal is eating.

        Dog dog = new Dog();
        dog.eat(); // 输出: Dog is eating.
        dog.bark(); // 输出: Dog is barking.

        Animal animalDog = new Dog(); // 使用父类引用指向子类对象
        animalDog.eat(); // 输出: Dog is eating.
        // animalDog.bark(); // 错误,Animal类型的引用不能访问子类特有的方法

        ((Dog) animalDog).bark(); // 使用强制类型转换调用子类特有的方法
    }
}

En Java, la razón por la que no se admite la asignación directa de referencias de superclase (clase principal) a variables de subclase tiene que ver con los conceptos de herencia y polimorfismo.

La herencia en Java es unidireccional: las subclases pueden heredar las propiedades y métodos de la clase principal, pero no ocurre lo contrario. Esto se debe a que las subclases pueden introducir nuevas propiedades y métodos que las clases principales no tienen. Si una referencia de superclase se asigna directamente a una variable de subclase, puede resultar en la imposibilidad de acceder a propiedades y métodos específicos de la subclase, violando así la seguridad de tipos.

El polimorfismo en Java se logra apuntando a objetos de subclase a través de referencias de clases principales. Esto se hace para permitir una programación más flexible al permitir que diferentes instancias de subclases se elijan dinámicamente en tiempo de ejecución. Sin embargo, debido a consideraciones de compatibilidad de tipos, Java no permite la asignación directa de referencias de superclase a variables de subclase.

Si desea convertir una referencia de superclase en un tipo de subclase, puede utilizar la conversión de tipos. Pero al realizar la conversión de tipos, debe prestar atención al tipo real del objeto para evitar excepciones de conversión de tipos (ClassCastException) en tiempo de ejecución.

Por ejemplo:

Superclass superClassInstance = new Subclass();
Subclass subclassInstance = (Subclass) superClassInstance; // Type Casting

Para hacerlo, es necesario asegurarse superClassInstancede que sea realmente Subclassuna instancia de; de ​​lo contrario, ClassCastExceptionse generará una excepción. Por lo tanto, tenga cuidado al realizar conversiones de tipos.

Cuando usamos un ejemplo para ilustrar por qué no está permitido asignar una referencia a una superclase (clase principal) a una variable de subclase en Java, supongamos que tenemos una superclase llamada y una subclase que hereda de Animalllamada . Ambas clases tienen un método llamado .AnimalDogmakeSound()

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("一些通用的动物声音。");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void makeSound() {
    
    
        System.out.println("汪汪!汪汪!");
    }

    public void fetch() {
    
    
        System.out.println("在找球玩耍。");
    }
}

Ahora, si intentamos Dogasignar un objeto a una Animalreferencia, está bien porque Dogeso también es un archivo Animal.

Animal animal = new Dog(); // 这是有效的,因为Dog是Animal的子类

Sin embargo, si intentamos animalacceder al método usando una referencia fetch(), resultará en un error de compilación, porque animallas referencias son Animaltipos, fetch()pero Dogmétodos específicos de clases.

animal.fetch(); // 错误:无法为Animal类型找到fetch()方法

Al no permitir este tipo de asignación, Java garantiza que sólo pueda acceder a métodos y propiedades que realmente existen en el tipo de objeto real. Esto ayuda a mantener la seguridad de tipos y evitar errores de tiempo de ejecución.

Si necesita acceder fetch()a métodos u otras funciones específicas de una subclase, puede convertir al tipo de subclase. Sin embargo, debe asegurarse de que el objeto al que se hace referencia sea realmente del tipo de subclase correcto para evitar excepciones en tiempo de ejecución.

Para acceder a métodos u otras funciones específicas de la subclase, puede utilizar la conversión de tipos para convertir la referencia de superclase al tipo de subclase. Hacerlo le permite tratar las referencias de superclase como referencias de subclase en el momento de la compilación, lo que le permite llamar a métodos específicos de la subclase.

En Java, la conversión de tipos se puede lograr convirtiendo una referencia de superclase a un tipo de subclase. De esta manera, puede acceder a métodos específicos de subclase.

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("一些通用的动物声音。");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void makeSound() {
    
    
        System.out.println("汪汪!汪汪!");
    }

    public void fetch() {
    
    
        System.out.println("在找球玩耍。");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Animal animal = new Dog(); // 创建一个Dog对象,并用Animal引用引用它

        animal.makeSound(); // 调用的是Dog类的makeSound()方法,因为它是动态绑定的

        // 使用类型转换将Animal引用转换为Dog类型
        if (animal instanceof Dog) {
    
    
            Dog dog = (Dog) animal;
            dog.fetch(); // 现在我们可以访问Dog类特有的fetch()方法
        }
    }
}

En este ejemplo, primero nos referimos a un objeto con Animaluna referencia . Luego llamamos , que llamará al método en la clase , porque Java admite el enlace dinámico (enlace dinámico), y el método correspondiente se llamará de acuerdo con el tipo de objeto real en tiempo de ejecución.animalDoganimal.makeSound()DogmakeSound()

A continuación, usamos instanceofel operador para verificar animalsi la referencia es Dogun objeto de tipo. Si es así, encasillamos animalla referencia a Dogun tipo y la asignamos a dogla referencia. Ahora podemos llamar al método por dogreferencia fetch()ya que es Dogun método específico de la clase.

Cabe señalar que al realizar la conversión de tipos, es necesario asegurarse de que el objeto al que apunta la referencia sea realmente el tipo de subclase de destino; de lo contrario, se ClassCastExceptiongenerará una excepción en tiempo de ejecución. Por lo tanto, es mejor utilizar comprobaciones antes de realizar conversiones de tipos instanceofpara garantizar que las conversiones de tipos se realicen de forma segura.

2. Los derechos de acceso deben ser mayores o iguales a los de la clase principal:

Cuando un método de una clase principal se anula en una subclase, el modificador de acceso del método anulado en la subclase puede ser mayor (más permisivo) que el método de la clase principal, pero no puede ser menor (más estricto) que el método de la clase principal. clase de padres. El orden de los modificadores de acceso es: privado <predeterminado (paquete-privado) <protegido <público. Por ejemplo, si el método de la clase principal es protected, entonces el método anulado en la clase secundaria puede ser protectedo public,no predeterminado o privado. Esto es para garantizar que las subclases no restrinjan el acceso a los métodos de la clase principal y garantizar la exactitud de la relación de herencia.

 class Animal {
    
    
    protected void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        System.out.println("Dog is eating");
    }
}

En este ejemplo, la clase Perro hereda de la clase Animal y cambia el método protegido de la clase principal a un método público. Los derechos de acceso de los métodos anulados en las subclases son mayores o iguales que los derechos de acceso de los métodos de la clase principal.

3. El tipo de valor de retorno debe ser menor o igual que la clase principal:

Cuando una subclase anula un método de clase principal, el tipo de valor de retorno del método anulado de subclase debe ser un subtipo (covariante) del tipo de valor de retorno del método de clase principal, o ser exactamente el mismo que el tipo de valor de retorno del método de clase principal. Esto es para garantizar que el método de la subclase sea compatible con el método de la clase principal en tipo, de modo que el objeto de la subclase pueda usarse como objeto de la clase principal. Si el tipo de valor de retorno del método anulado de la subclase es incompatible con el método de la clase principal, provocará un error de compilación.

class Animal {
    
    
    public Animal giveBirth() {
    
    
        return new Animal();
    }
}

class Dog extends Animal {
    
    
    public Dog giveBirth() {
    
    
        return new Dog();
    }
}

En este ejemplo, la clase Perro extiende la clase Animal y anula el método GiveBirth. El tipo de valor de retorno en la subclase es una subclase del tipo de valor de retorno del método de la clase principal.

4. Mantenga las firmas de los métodos consistentes:

Al reescribir el método de la clase principal, se recomienda que el método de reescritura de la subclase sea lo más consistente posible con el método de la clase principal, incluido el nombre del método, la lista de parámetros y el tipo de valor de retorno. Hacerlo contribuye a la legibilidad y mantenibilidad del código, haciéndolo más fácil de entender y modificar. Si el método anulado de la subclase no coincide con la firma del método de la clase principal, aunque el compilador no informará un error, causará confusión y errores.

class Animal {
    
    
    public void move() {
    
    
        System.out.println("Animal is moving");
    }
}

class Dog extends Animal {
    
    
    public void move(int distance) {
    
    
        System.out.println("Dog is moving " + distance + " meters");
    }
}

En este ejemplo, la clase Perro hereda de la clase Animal, pero la firma del método anulado es inconsistente con el método de la clase principal. No se recomienda dicha anulación, ya que puede generar confusión y errores.

Comparado:

inserte la descripción de la imagen aquí
Y con parámetros:
inserte la descripción de la imagen aquí
En Java, Animal ccc = new Dog(); El significado de esta línea de código es crear un nuevo objeto Dog y asignar su referencia a una variable ccc de tipo Animal. Esta es una manifestación del polimorfismo de Java.

En este caso, ccc es una referencia de tipo Animal, pero en realidad se refiere a un objeto Perro. Esto significa que puede llamar a todos los métodos definidos por la clase Animal, así como a los métodos de la clase Animal que la clase Dog anula.

Por ejemplo, cuando llamas a ccc.move(1);, en realidad llamas al método move(int Distance) reescrito en la clase Dog, no al método move(int Distance) en la clase Animal. Esto se debe a que la clase Perro anula el método de movimiento (distancia int) de la clase Animal, por lo que cuando llamas al método de movimiento (distancia int) a través de una referencia del tipo Animal, en realidad llamas a la versión en la clase Perro.

Es por eso que en su código, ((Animal) ccc).move(1); en realidad genera "El perro se mueve 1 metro", no "El animal se mueve 1 metro". Debido a que ccc en realidad se refiere a un objeto Dog, llama al método move(int Distance) en la clase Dog.

5. Los métodos privados no se pueden anular:

Los métodos privados solo son accesibles dentro de la clase en la que están declarados y, por lo tanto, no se puede acceder a ellos, y mucho menos anularlos, en subclases. Los métodos privados tampoco se pueden anular porque solo son visibles dentro de su clase propietaria. Si en la subclase se define el mismo método que el método privado de la clase principal, entonces en realidad se crea un nuevo método en la subclase en lugar de anular el método de la clase principal.

class Animal {
    
    
    private void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        System.out.println("Dog is eating");
    }
}

inserte la descripción de la imagen aquí

En este ejemplo, la clase Dog intenta anular el método privado eat de la clase principal, pero como los métodos privados solo son accesibles dentro de la clase en la que están declarados, no se puede acceder a ellos ni anularlos en la subclase.

6. Los métodos estáticos no se pueden anular:

static修饰的方法可以被继承,但是不能被重写

Un método estático es aquel que está asociado con una clase en lugar de una instancia, por lo que una subclase no puede anular un método estático de una clase principal. Sin embargo, una subclase puede declarar un nuevo método en su propia clase con el mismo nombre que el método estático de la clase principal, lo que se denomina ocultación de método. La ocultación de métodos se diferencia de la anulación de métodos en que crea un nuevo método estático en la subclase en lugar de anular el método estático de la clase principal.

class Animal {
    
    
    public static void makeSound() {
    
    
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    
    
    public static void makeSound() {
    
    
        System.out.println("Dog is barking");
    }
}

En este ejemplo, la clase Dog intenta anular el método estático makeSound de la clase principal, pero como el método estático está relacionado con la clase y no con la instancia, no se puede utilizar en la clase secundaria.

detallado:

En Java, los métodos estáticos están asociados con una clase, no con una instancia de la clase. Cuando una clase define un método estático, pertenece a la clase misma, no a una instancia de la clase. Por lo tanto, los métodos estáticos se llaman directamente por el nombre de la clase, no por una instancia de la clase.

当子类定义了一个与父类相同名称和参数列表的静态方法时,
	实际上是在子类中创建了一个新的静态方法,而不是重写父类的静态方法。
在调用静态方法时,编译器会根据引用类型来确定要调用的方法。
	所以,无论是父类引用指向子类对象,还是子类引用指向父类对象,
调用的都是引用类型所属类的静态方法,而不是实际对象的类型。

Dado que los métodos estáticos están asociados con una clase, las subclases no pueden anularlos. Una subclase puede definir un método estático con el mismo nombre y lista de parámetros que la clase principal, pero en realidad esto crea un nuevo método estático en la subclase en lugar de anular el método estático de la clase principal.

Al llamar a un método estático por nombre de clase, el compilador determina qué método llamar según el tipo de referencia. Ya sea que la referencia de la clase principal apunte al objeto de la subclase o la referencia de la subclase apunte al objeto de la clase principal, lo que se llama es el método estático de la clase a la que pertenece el tipo de referencia, no el tipo del objeto real.

Por lo tanto, dado que los métodos estáticos están asociados con una clase y no pueden ser anulados por subclases, los métodos estáticos no se pueden anular en Java.

7. Anormal:

El método anulado no puede generar más excepciones que el método de superclase, pero puede generar excepciones más específicas o ninguna excepción. Esto es para garantizar que el método anulado de la subclase no introduzca nuevas excepciones para que sea compatible con el manejo de excepciones del método de la clase principal. Si el método anulado de la subclase arroja más excepciones que el método de la superclase, provocará un error de compilación.

class Animal {
    
    
    public void makeSound() throws IOException {
    
    
        // code that may throw IOException
    }
}

class Dog extends Animal {
    
    
    public void makeSound() throws FileNotFoundException {
    
    
        // code that may throw FileNotFoundException
    }
}

En este ejemplo, la clase Perro extiende la clase Animal y anula el método makeSound. Los métodos anulados en subclases pueden generar una excepción más específica (FileNotFoundException) o no generar ninguna excepción. Pero no puede generar más excepciones que el método de la clase principal.

8. Usando @Override:

En Java, @Overridelos métodos anulados se pueden marcar con anotaciones. Esta anotación puede ayudar al compilador a verificar si se cumplen las condiciones de reescritura y, de lo contrario, el compilador informará un error. El uso de @Overrideanotaciones puede mejorar la legibilidad y el mantenimiento del código, lo que indica claramente que el método es un método para anular la clase principal.

class Animal {
    
    
    public void move() {
    
    
        System.out.println("Animal is moving");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void move() {
    
    
        System.out.println("Dog is running");
    }
}

En este ejemplo, la clase Dog marca el método anulado con la anotación @Override. Esto puede ayudar al compilador a verificar si se cumplen las condiciones de reescritura y, de lo contrario, el compilador informará un error. El uso de la anotación @Override puede mejorar la legibilidad y el mantenimiento del código, lo que indica claramente que el método es un método para anular la clase principal.

9. Súper palabra clave:

En la subclase, puede utilizar super 关键字para llamar al método de la clase principal. Al utilizar la palabra clave super, las subclases pueden ampliar las funciones del método de la clase principal mientras reescriben el método de la clase principal. Las subclases pueden llamar primero al método de la clase principal en el método anulado y luego agregar su propia lógica. De esta manera, la función original del método de la clase principal se puede conservar y ampliar sobre esta base.

class Animal {
    
    
    public void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        super.eat(); // 调用父类的eat方法
        System.out.println("Dog is eating bones");
    }
}

En este ejemplo, la clase Dog anula el método eat de la clase principal y llama al método eat de la clase principal utilizando la palabra clave super. De esta manera, la función del método de la clase principal se puede extender en la subclase, se conserva la función original del método de la clase principal y se agrega nueva lógica sobre esta base.
inserte la descripción de la imagen aquí

10. El método final:

Si un método en una superclase se declara como final, entonces ese método no puede ser anulado por una subclase. Un método final es un método final que no se puede modificar, su implementación es final en la clase principal y no puede ser modificado ni anulado por subclases. Esto es para garantizar que un método en la clase principal permanezca sin cambios en la subclase y no pueda modificarse.

class Animal {
    
    
    public final void eat() {
    
    
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    
    
    public void eat() {
    
    
        System.out.println("Dog is eating");
    }
}

En este ejemplo, el método eat en la clase Animal se declara final, lo que indica que el método es final y las subclases no pueden anularlo. Por lo tanto, come en la clase Perro.

11. Finalidad y polimorfismo:

El objetivo principal de anular métodos es proporcionar una implementación específica de subclase en subclases, permitiendo características de polimorfismo y herencia. Al reescribir el método de la clase principal, la subclase puede implementar funciones específicas según sus propias necesidades sin reescribir el método completo. Esto puede mejorar la reutilización y la capacidad de mantenimiento del código, y también lograr el polimorfismo, es decir, hacer referencia al objeto de la subclase a través de la clase principal y llamar al método correspondiente según el tipo del objeto real.

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Animal is making a sound");
    }
}

class Dog extends Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Dog is barking");
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Animal animal = new Animal();
        Animal dog = new Dog();

        animal.makeSound(); // 输出:Animal is making a sound
        dog.makeSound(); // 输出:Dog is barking
    }
}

En este ejemplo, la clase Animal y la clase Perro definen cada una un método makeSound. El polimorfismo se logra creando objetos de las clases Animal y Dog y llamando a sus métodos makeSound. En tiempo de ejecución, el método correspondiente se llama de acuerdo con el tipo real del objeto. Incluso si la referencia de la clase principal se usa para apuntar al objeto de la subclase, aún se puede llamar al método reescrito por la subclase.

Lo anterior es una descripción detallada del método de reescritura. Cada punto es para garantizar que la subclase reescriba correctamente el método de la clase principal y realice el polimorfismo y la herencia. Estas reglas y consideraciones son muy importantes en Java y deben seguirse en la programación real.

class Animal {
    
    
    public void makeSound() {
    
    
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    
    
    @Override
    public void makeSound() {
    
    
        System.out.println("Dog barks");
    }
}

En este ejemplo, Dogla clase hereda de Animalla clase y anula makeSound()el método. Cuando se llama al método makeSound(), si es Animalun objeto, generará "El animal hace un sonido"; si es Dogun objeto, generará "El perro ladra". Esto se debe a que en tiempo de ejecución, Java elegirá dinámicamente llamar al método correspondiente al tipo de objeto.

Al utilizar la reescritura de métodos, preste atención a seguir las reglas anteriores para garantizar que la reescritura de métodos pueda anular correctamente el método de la clase principal en la relación de herencia y pueda satisfacer las necesidades de la subclase.

方法重写(Override)的本质是子类提供了与父类相同签名的方法,以实现不同的功能。
	在运行时,JVM通过虚方法表(Virtual Method Table)来确定调用哪个方法,这就是动态绑定或者后期绑定。

当我们创建一个子类对象并调用一个方法时,JVM会首先在子类的虚方法表中查找该方法。
	如果找到,就执行该方法;如果没有找到,就在父类的虚方法表中查找。这就是为什么子类可以重写父类的方法的原因。

当子类重写父类的方法时,子类的虚方法表中的对应条目会被更新为指向子类的方法,而不是父类的方法。
	这就是所谓的“覆盖虚方法表中的方法”。

Constructor de subclases:

En Java, el constructor de la subclase generalmente llama al constructor de la clase principal para garantizar que todos los campos de la clase principal se inicialicen correctamente. Esto se logra utilizando la palabra clave super. Aquí hay un ejemplo:

public class Animal {
    
    
    private String name;

    public Animal(String name) {
    
    
        this.name = name;
    }
}

public class Dog extends Animal {
    
    
    private String breed;

    public Dog(String name, String breed) {
    
    
        super(name);  // 调用父类的构造器
        this.breed = breed;
    }
}

En este ejemplo, la clase Perro es una subclase de la clase Animal. El constructor de la clase Perro primero llama a super (nombre) para llamar al constructor de la clase principal Animal y luego inicializa su propio campo de raza.

En Java, puede crear JavaBean con estructura de herencia mediante herencia.

你的要求是创建一个JavaBean,它需要满足以下条件:

1. 类名见名知意
2. 所有的成员变量都需要私有
3. 构造方法(空参和带全部参数的构造)
4. get/set方法

Primero, creamos un JavaBean base llamado Persona:

public class Person {
    
    
    private String name;
    private int age;

    public Person() {
    
    
    }

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }
}

Luego, creamos una clase Estudiante que hereda de Persona:

public class Student extends Person {
    
    
    private String school;

    public Student() {
    
    
    }

    public Student(String name, int age, String school) {
    
    
        super(name, age);
        this.school = school;
    }

    public String getSchool() {
    
    
        return school;
    }

    public void setSchool(String school) {
    
    
        this.school = school;
    }
}

En este ejemplo, la clase Estudiante hereda las propiedades y métodos de la clase Persona y agrega su propia propiedad escuela. Así es como se crea un JavaBean con una estructura de herencia.

Supongo que te gusta

Origin blog.csdn.net/m0_74154295/article/details/132049321
Recomendado
Clasificación