Java-Lernen: Objektorientiert (2)

Fünf, objektorientiert (zwei)

5.1 Stichwort: Dies

  • In Java ist das Schlüsselwort this nicht schwer zu verstehen und seine Funktion kommt seiner Bedeutung sehr nahe.

    • Es wird innerhalb einer Methode (genauer gesagt einer Instanzmethode oder einer nicht statischen Methode) verwendet, um das Objekt darzustellen, das die Methode aufruft
    • Es wird innerhalb eines Konstruktors verwendet, um das Objekt darzustellen, das der Konstruktor initialisiert.
  • Die Struktur, die dadurch aufgerufen werden kann: Mitgliedsvariablen, Methoden und Konstruktoren

5.1.1 Dieses Nutzungsszenario

① Mitglieder des aktuellen Objekts werden in der Instanzmethode oder im Konstruktor verwendet

Wenn Sie in der Instanzmethode oder im Konstruktor die Mitgliedsvariable oder Mitgliedsmethode der aktuellen Klasse verwenden, können Sie diese voranstellen, um die Lesbarkeit des Programms zu verbessern. Normalerweise sind wir es jedoch gewohnt, dies wegzulassen.

Wenn jedoch die formale Mitgliedsvariable denselben Namen hat und Sie die Mitgliedsvariable in der Methode oder im Konstruktor verwenden müssen, müssen Sie dies hinzufügen, um anzugeben, dass die Variable eine Mitgliedsvariable der Klasse ist. Das heißt: Wir können dies verwenden, um zu unterscheiden 成员变量und 局部变量. Zum Beispiel:
Fügen Sie hier eine Bildbeschreibung ein

Wenn Sie damit auf Eigenschaften und Methoden zugreifen und diese nicht in dieser Klasse finden, werden sie außerdem in der übergeordneten Klasse gefunden.

Beispiel 1:

class Person{
    
    		// 定义Person类
	private String name ;	
	private int age ;			
	public Person(String name,int age){
    
    	
		this.name = name ;   
		this.age = age ;  
    }
    public void setName(String name){
    
    
        this.name = name;
    }
    public void setAge(int age){
    
    
        this.age = age;
    }
	public void getInfo(){
    
    	
		System.out.println("姓名:" + name) ;
		this.speak();
	}
	public void speak(){
    
    
		System.out.println(“年龄:” + this.age);	
	}
}

Beispiel 2:

public class Rectangle {
    
    
    int length;
    int width;

    public int area() {
    
    
        return this.length * this.width;
    }

    public int perimeter(){
    
    
        return 2 * (this.length + this.width);
    }

    public void print(char sign) {
    
    
        for (int i = 1; i <= this.width; i++) {
    
    
            for (int j = 1; j <= this.length; j++) {
    
    
                System.out.print(sign);
            }
            System.out.println();
        }
    }

    public String getInfo(){
    
    
        return "长:" + this.length + ",宽:" + this.width +",面积:" + this.area() +",周长:" + this.perimeter();
    }
}

Testklasse:

public class TestRectangle {
    
    
    public static void main(String[] args) {
    
    
        Rectangle r1 = new Rectangle();
        Rectangle r2 = new Rectangle();

        System.out.println("r1对象:" + r1.getInfo());
        System.out.println("r2对象:" + r2.getInfo());

        r1.length = 10;
        r1.width = 2;
        System.out.println("r1对象:" + r1.getInfo());
        System.out.println("r2对象:" + r2.getInfo());

        r1.print('#');
        System.out.println("---------------------");
        r1.print('&');

        System.out.println("---------------------");
        r2.print('#');
        System.out.println("---------------------");
        r2.print('%');
    }
}

② Konstrukteure derselben Klasse rufen sich gegenseitig auf

Dies kann als spezielles Format für Konstruktoren in einer Klasse verwendet werden, um sich gegenseitig aufzurufen.

  • this(): Rufen Sie den Parameterlosen Konstruktor dieser Klasse auf
  • this (Liste der tatsächlichen Parameter): Rufen Sie den parametrisierten Konstruktor dieser Klasse auf
public class Student {
    
    
    private String name;
    private int age;

    // 无参构造
    public Student() {
    
    
//        this("",18);//调用本类有参构造器
    }

    // 有参构造
    public Student(String name) {
    
    
        this();//调用本类无参构造器
        this.name = name;
    }
    // 有参构造
    public Student(String name,int age){
    
    
        this(name);//调用本类中有一个String参数的构造器
        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;
    }

    public String getInfo(){
    
    
        return "姓名:" + name +",年龄:" + age;
    }
}

Notiz:

  • Rekursive Aufrufe können nicht erfolgen. Rufen Sie beispielsweise Ihren eigenen Konstruktor auf.
    • Folgerung: Wenn n Konstruktoren in einer Klasse deklariert sind, verwenden höchstens n - 1 Konstruktoren „dies (Parameterliste)“
  • this() und this (eigentliche Parameterliste) können nur in der ersten Zeile des Konstruktors deklariert werden.
    • Folgerung: In einem Konstruktor einer Klasse kann höchstens ein „this (parameter list)“ deklariert werden

5.2 Merkmal 2: Vererbung

Geerbte Vorteile

  • Das Aufkommen der Vererbung reduziert die Coderedundanz und verbessert die Wiederverwendbarkeit des Codes.

  • Das Aufkommen der Vererbung begünstigt eher die Erweiterung der Funktionen.

  • Durch die Entstehung der Vererbung entsteht is-aeine Beziehung zwischen Klassen und Klassen, die eine Voraussetzung für die Verwendung von Polymorphismus darstellt.

    • Vererbung beschreibt die Eigentumsbeziehung zwischen Dingen, diese Beziehung ist: is-adie Beziehung. Es ist ersichtlich, dass die übergeordnete Klasse allgemeiner und allgemeiner und die Unterklasse spezifischer ist.

Hinweis: Erben Sie nicht nur, um eine Funktion in einer anderen Klasse zu erhalten!

Grammatische Formatierung in der Vererbung

Mit extendsdem Schlüsselwort können Sie deklarieren, dass eine Klasse B eine andere Klasse A erbt. Das Definitionsformat lautet wie folgt:

[修饰符] classA {
    
    
	...
}

[修饰符] classB extendsA {
    
    
	...
}

Klasse B, genannt Unterklasse, abgeleitete Klasse (abgeleitete Klasse), Unterklasse

Klasse A, genannt übergeordnete Klasse, Superklasse, Basisklasse (Basisklasse), SuperClass

Codebeispiel

1. Elternklasse

/*
 * 定义动物类Animal,做为父类
 */
public class Animal {
    
    
    // 定义name属性
    String name;
    // 定义age属性
    int age;

    // 定义动物的吃东西方法
    public void eat() {
    
    
        System.out.println(age + "岁的"
                + name + "在吃东西");
    }
}

2. Unterklassen

/*
 * 定义猫类Cat 继承 动物类Animal
 */
public class Cat extends Animal {
    
    
    int count;//记录每只猫抓的老鼠数量

    // 定义一个猫抓老鼠的方法catchMouse
    public void catchMouse() {
    
    
        count++;
        System.out.println("抓老鼠,已经抓了"
                + count + "只老鼠");
    }
}

3. Testklasse

public class TestCat {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个猫类对象
        Cat cat = new Cat();
        // 为该猫类对象的name属性进行赋值
        cat.name = "Tom";
        // 为该猫类对象的age属性进行赋值
        cat.age = 2;
        // 调用该猫继承来的eat()方法
        cat.eat();
        // 调用该猫的catchMouse()方法
        cat.catchMouse();
        cat.catchMouse();
        cat.catchMouse();
    }
}

Vererbungsdetails

1. Die Unterklasse erbt alle Instanzvariablen und Instanzmethoden der übergeordneten Klasse.
2. Die Unterklasse kann nicht direkt auf die privaten (privaten) Mitgliedsvariablen und -methoden in der übergeordneten Klasse zugreifen.
3. In Java verwendet das geerbte Schlüsselwort „extends“. Das heißt, die Unterklasse ist keine Teilmenge der übergeordneten Klasse, sondern eine „Erweiterung“ der übergeordneten Klasse
4. Java unterstützt die mehrschichtige Vererbung (Vererbungssystem).

class A{
    
    }
class B extends A{
    
    }
class C extends B{
    
    }

veranschaulichen:

  • Unterklasse und übergeordnete Klasse sind relative Konzepte

  • Die übergeordnete Klasse der obersten Ebene ist die Object-Klasse. Alle Klassen erben standardmäßig Object als übergeordnete Klasse.

5. Eine übergeordnete Klasse kann mehrere Unterklassen gleichzeitig haben

class A{
    
    }
class B extends A{
    
    }
class D extends A{
    
    }
class E extends A{
    
    }

6. Java unterstützt nur die Einzelvererbung, nicht die Mehrfachvererbung

public class A{
    
    }
class B extends A{
    
    }

//一个类只能有一个父类,不可以有多个直接父类。
class C extends B{
    
    } 	//ok
class C extends A,B...	//error

üben:

(1) Definieren Sie eine ManKind-Klasse, einschließlich

  • Mitgliedsvariablen int Geschlecht und int Gehalt;
  • Methode void manOrWoman(): Zeigt „Mann“ entsprechend dem Wert des Geschlechts an (sex1) oder „Frau“ (Geschlecht0);
  • Methode voidemployed(): Zeigt „kein Job“ (Gehalt==0) oder „Job“ (Gehalt!=0) entsprechend dem Gehaltswert an.
public class ManKind {
    
    
    int sex; // 成员变量:性别
    int salary; // 成员变量:工资

    public void manOrWoman(){
    
     // 方法:判断男女性别并输出
        if(sex == 1){
    
     // 如果性别为 1,表示男性
            System.out.println("man"); // 输出 man
        }else if(sex == 0){
    
     // 如果性别为 0,表示女性
            System.out.println("woman"); // 输出 woman
        }
    }

    public void employeed(){
    
     // 方法:判断是否有工作并输出
        if(salary == 0){
    
     // 如果工资为 0,表示没有工作
            System.out.println("no job"); // 输出 no job
        }else{
    
     // 否则有工作
            System.out.println("job"); // 输出 job
        }
    }
}

(2) Definieren Sie die Klasse Kids, die ManKind erben und einbeziehen soll

  • Mitgliedsvariable int yearsOld;
  • Die Methode printAge() gibt den Wert von yearsOld aus.
package demo07;

public class Kids extends ManKind{
    
     // 继承自 ManKind
    int yearsOld; // 成员变量:年龄

    public void printAge(){
    
     // 方法:输出年龄
        System.out.println(yearsOld); // 输出成员变量 yearsOld 的值
    }
}

(3) Definieren Sie die Klasse KidsTest, instanziieren Sie das Objekt someKid of Kids in der Hauptmethode der Klasse und verwenden Sie dieses Objekt, um auf die Mitgliedsvariablen und Methoden der übergeordneten Klasse zuzugreifen.

package demo07;

public class KidsTest {
    
    
    public static void main(String[] args) {
    
    
        Kids someKid = new Kids();// 实例化 Kids 类的对象 someKid
        someKid.sex = 1; // 调用继承自 ManKind 的成员变量 sex,赋值为 1
        someKid.salary = 1000; // 调用继承自 ManKind 的成员变量 salary,赋值为 1000
        someKid.manOrWoman(); // 调用继承自 ManKind 的方法 manOrWoman,输出 man
        someKid.employeed(); // 调用继承自 ManKind 的方法 employeed,输出 job
        someKid.yearsOld = 10; // 调用 Kids 自己的成员变量 yearsOld,赋值为 10
        someKid.printAge(); // 调用 Kids 自己的方法 printAge,输出 10
    }
}

5.3 Umschreiben der Methode (Überschreiben/Überschreiben)

Alle Methoden der übergeordneten Klasse werden von der Unterklasse geerbt. Wenn jedoch eine Methode an die Unterklasse geerbt wird, ist die Unterklasse der Meinung, dass die ursprüngliche Implementierung der übergeordneten Klasse nicht für ihre aktuelle Klasse geeignet ist. Was soll sie tun? Unterklassen können die von der übergeordneten Klasse geerbten Methoden transformieren, die wir Methoden nennen 重写 (override、overwrite). Auch als Methoden bekannt 重置.覆盖

Wenn das Programm ausgeführt wird, überschreibt die Methode der Unterklasse die Methode der übergeordneten Klasse.

Beispiel

Beispielsweise verfügt das neue Mobiltelefon über die Funktion, den Avatar des Anrufers anzuzeigen. Der Code lautet wie folgt:

public class Phone {
    
    
    public void sendMessage(){
    
    
        System.out.println("发短信");
    }
    public void call(){
    
    
        System.out.println("打电话");
    }
    public void showNum(){
    
    
        System.out.println("来电显示号码");
    }
}

//SmartPhone:智能手机
public class SmartPhone extends Phone{
    
    
    //重写父类的来电显示功能的方法
	@Override
    public void showNum(){
    
    
        //来电显示姓名和图片功能
        System.out.println("显示来电姓名");
        System.out.println("显示头像");
    }
    //重写父类的通话功能的方法
    @Override
    public void call() {
    
    
        System.out.println("语音通话 或 视频通话");
    }
}
//TestOverride类
public class TestOverride {
    
    
    public static void main(String[] args) {
    
    
        // 创建子类对象
        SmartPhone sp = new SmartPhone();

        // 调用父类继承而来的方法
        sp.call();

        // 调用子类重写的方法
        sp.showNum();
    }
}

@Override Gebrauchsanweisung:

Es wird in die Methode geschrieben und dient dazu, festzustellen, ob die Anforderungen der umgeschriebenen Methode erfüllt sind. Auch wenn diese Anmerkung nicht geschrieben wird, ist sie, solange die Anforderungen erfüllt sind, die richtige Methode zum Überschreiben und Neuschreiben. Es wird empfohlen, es beizubehalten, damit der Compiler uns bei der Überprüfung des Formats helfen und Programmierern, die den Quellcode lesen, klar machen kann, dass es sich um eine überschriebene Methode handelt.

Methodenübergeordnete Anforderungen

  1. Die von der Unterklasse überschriebene Methode hat dieselben Eigenschaften wie 必须die überschriebene Methode der übergeordneten Klasse .方法名称参数列表

  2. Der Rückgabewerttyp der überschriebenen Methode der Unterklasse. 不能大于Der Rückgabewerttyp der überschriebenen Methode der übergeordneten Klasse. (z. B.: Student <Person).

Hinweis: Wenn der Rückgabewerttyp ein Basisdatentyp und void ist, muss er identisch sein

  1. Von Unterklassen überschriebene Methoden nutzen die Zugriffsrechte 不能小于überschriebener Methoden der übergeordneten Klasse. (öffentlich > geschützt > Standard > privat)

Hinweis: ① Die private Methode der übergeordneten Klasse kann nicht überschrieben werden; ② Die Standardmethode der paketübergreifenden übergeordneten Klasse kann nicht überschrieben werden

  1. Die von der Unterklassenmethode ausgelöste Ausnahme darf nicht größer sein als die Ausnahme der überschriebenen Methode der übergeordneten Klasse

Darüber hinaus müssen die Methoden mit demselben Namen und denselben Parametern in der Unterklasse und der übergeordneten Klasse gleichzeitig als nicht statisch (dh umschreibend) oder statisch (nicht umschreibend) deklariert werden. Da die statische Methode zur Klasse gehört, kann die Unterklasse die Methode der übergeordneten Klasse nicht überschreiben.

Überladen und Umschreiben von Methoden

Java中的方法重载(Overloading): Dies bedeutet, dass es in derselben Klasse mehrere Methoden mit demselben Namen, aber unterschiedlicher Anzahl oder Art von Parametern geben kann, dh derselbe Methodenname kann durch unterschiedliche Parameterlisten überladen werden. Beim Aufruf dieser überladenen Methoden wählt der Compiler die am besten geeignete Methode entsprechend der Art, Anzahl und Reihenfolge der tatsächlichen Parameter aus. Methodenüberladung in Java wird normalerweise verwendet, um einige ähnliche Funktionen zu erreichen und dadurch die Wiederverwendung von Code zu verbessern.

Java中的方法重写(Overriding): bedeutet, dass die Unterklasse die Methode in der übergeordneten Klasse überschreibt, was auch als Überschreiben bezeichnet wird. Definieren Sie eine Methode in der Unterklasse, die denselben Namen, dieselbe Parameterliste und denselben Rückgabewerttyp wie die Methode in der übergeordneten Klasse hat, und markieren Sie sie mit dem Annotationssymbol @Override, um anzuzeigen, dass die Methode in der übergeordneten Klasse überschrieben wird.

Methodenüberladung und Umschreiben sind zwei in Java häufig verwendete Methoden, um die Wiederverwendung von Code zu erreichen und die Skalierbarkeit zu verbessern.

(1) In derselben Klasse

public class TestOverload {
    
    
    public int max(int a, int b){
    
    
        return a > b ? a : b;
    }
    public double max(double a, double b){
    
    
        return a > b ? a : b;
    }
    public int max(int a, int b,int c){
    
    
        return max(max(a,b),c);
    }
}

(2) In der Eltern-Kind-Klasse

public class TestOverloadOverride {
    
    
    public static void main(String[] args) {
    
    
        Son s = new Son();
        s.method(1);//只有一个形式的method方法

        Daughter d = new Daughter();
        d.method(1);
        d.method(1,2);//有两个形式的method方法
    }
}

class Father{
    
    
    public void method(int i){
    
    
        System.out.println("Father.method");
    }
}
class Son extends Father{
    
    
    public void method(int i){
    
    //重写
        System.out.println("Son.method");
    }
}
class Daughter extends Father{
    
    
    public void method(int i,int j){
    
    //重载
        System.out.println("Daughter.method");
    }
}

5.4 Stichwort: super

Verwenden Sie super in einer Java-Klasse, um die angegebene Operation in der übergeordneten Klasse aufzurufen:

  • super kann verwendet werden, um auf Eigenschaften zuzugreifen, die in der übergeordneten Klasse definiert sind
  • super kann verwendet werden, um Mitgliedsmethoden aufzurufen, die in der übergeordneten Klasse definiert sind
  • super kann verwendet werden, um den Konstruktor der übergeordneten Klasse im Konstruktor der Unterklasse aufzurufen

Notiz:

  • Insbesondere wenn in der untergeordneten übergeordneten Klasse Mitglieder mit demselben Namen vorhanden sind, können Sie mit super angeben, dass das Mitglied in der übergeordneten Klasse aufgerufen wird
  • Die Rückverfolgbarkeit von Super ist nicht auf die unmittelbare übergeordnete Klasse beschränkt
  • Die Verwendung von super und this ist ähnlich, dies stellt die Referenz des Objekts dieser Klasse dar und super repräsentiert die Identität des Speicherplatzes der übergeordneten Klasse

5.4.1 Super-Nutzungsszenarien

①Rufen Sie die überschriebene Methode der übergeordneten Klasse in der Unterklasse auf

  • Wenn die Unterklasse die Methode der übergeordneten Klasse nicht überschreibt, kann die Methode der übergeordneten Klasse direkt in der Unterklasse aufgerufen werden, sofern der Berechtigungsmodifikator dies zulässt.
  • Wenn die Unterklasse die Methode der übergeordneten Klasse überschreibt, muss sie in der Unterklasse übergeben werden, um super.die überschriebene Methode der übergeordneten Klasse aufzurufen. Andernfalls wird standardmäßig die von der Unterklasse neu geschriebene Methode aufgerufen

Beispiel:

public class Phone {
    
    
    public void sendMessage(){
    
    
        System.out.println("发短信");
    }
    public void call(){
    
    
        System.out.println("打电话");
    }
    public void showNum(){
    
    
        System.out.println("来电显示号码");
    }
}

//smartphone:智能手机
public class SmartPhone extends Phone{
    
    
    //重写父类的来电显示功能的方法
    public void showNum(){
    
    
        //来电显示姓名和图片功能
        System.out.println("显示来电姓名");
        System.out.println("显示头像");

        //保留父类来电显示号码的功能
        super.showNum();//此处必须加super.,否则就是无限递归,那么就会栈内存溢出
    }
}

Zusammenfassen:

  • Es gibt keine super. und das. vor der Methode.

    • Suchen Sie zuerst die passende Methode aus der Unterklasse. Wenn nicht, suchen Sie sie dann aus der direkten übergeordneten Klasse. Wenn nicht, fahren Sie mit der Rückverfolgung fort
  • Dies geht der Methode voraus.

    • Suchen Sie zuerst die passende Methode aus der Unterklasse. Wenn nicht, suchen Sie sie dann aus der direkten übergeordneten Klasse. Wenn nicht, fahren Sie mit der Rückverfolgung fort
  • Der Methode geht super voran.

    • Suchen Sie es in der direkten übergeordneten Klasse der aktuellen Unterklasse. Wenn nicht, fahren Sie mit der Rückverfolgung fort

②Rufen Sie die gleichnamige Mitgliedsvariable in der übergeordneten Klasse in der Unterklasse auf

  • Wenn die Instanzvariable denselben Namen wie die lokale Variable hat, können Sie diesen zur Unterscheidung vor der Instanzvariablen hinzufügen
  • Wenn die Instanzvariable der Unterklasse und die Instanzvariable der übergeordneten Klasse denselben Namen haben und die Instanzvariable der übergeordneten Klasse in der Unterklasse weiterhin sichtbar ist, können Sie auf die von der übergeordneten Klasse in der Unterklasse deklarierte Instanzvariable zugreifen , müssen Sie super. vor der Instanzvariablen der übergeordneten Klasse hinzufügen, andernfalls ist der Standardzugriff die von der Unterklasse selbst deklarierte Instanzvariable
  • Wenn die Instanzvariablen der übergeordneten und untergeordneten Klassen nicht denselben Namen haben, kann, sofern der Berechtigungsmodifikator dies zulässt, direkt in der Unterklasse auf die in der übergeordneten Klasse deklarierten Instanzvariablen zugegriffen werden. Instanz- oder super.instanzvariable

Beispiel:

class Father{
    
    
	int a = 10;
	int b = 11;
}
class Son extends Father{
    
    
	int a = 20;
    
    public void test(){
    
    
		//子类与父类的属性同名,子类对象中就有两个a
		System.out.println("子类的a:" + a);//20  先找局部变量找,没有再从本类成员变量找
        System.out.println("子类的a:" + this.a);//20   先从本类成员变量找
        System.out.println("父类的a:" + super.a);//10    直接从父类成员变量找
		
		//子类与父类的属性不同名,是同一个b
		System.out.println("b = " + b);//11  先找局部变量找,没有再从本类成员变量找,没有再从父类找
		System.out.println("b = " + this.b);//11   先从本类成员变量找,没有再从父类找
		System.out.println("b = " + super.b);//11  直接从父类局部变量找
	}
	
	public void method(int a, int b){
    
    
		//子类与父类的属性同名,子类对象中就有两个成员变量a,此时方法中还有一个局部变量a		
		System.out.println("局部变量的a:" + a);//30  先找局部变量
        System.out.println("子类的a:" + this.a);//20  先从本类成员变量找
        System.out.println("父类的a:" + super.a);//10  直接从父类成员变量找

        System.out.println("b = " + b);//13  先找局部变量
		System.out.println("b = " + this.b);//11  先从本类成员变量找
		System.out.println("b = " + super.b);//11  直接从父类局部变量找
    }
}
class Test{
    
    
    public static void main(String[] args){
    
    
        Son son = new Son();
		son.test();
		son.method(30,13);  
    }
}

Zusammenfassung: unterschiedliche Ausgangspunkte (Näheprinzip)

  • Variablen werden nicht durch super. und this vorangestellt.

    • Wenn eine Variable in einem Konstruktor, Codeblock oder einer Methode verwendet wird, prüfen Sie zunächst, ob sie vom aktuellen Block deklariert wird 局部变量.
    • Wenn es sich nicht um eine lokale Variable handelt, beginnen Sie mit dem aktuell ausgeführten Code本类去找成员变量
    • Wenn es in der Klasse, die den Code gerade ausführt, nicht gefunden wird, wird es nachgeschlagen 父类声明的成员变量(Berechtigungsmodifikatoren ermöglichen den Zugriff in Unterklassen).
  • Variablen werden dadurch vorangestellt.

    • Wenn Sie auf diese Weise nach Mitgliedsvariablen suchen, beginnen Sie zunächst mit dem aktuell ausgeführten CodeDiese Klasse findet Mitgliedsvariablen
    • Wenn es in der Klasse, die den Code gerade ausführt, nicht gefunden wird, sucht es nach == Mitgliedsvariablen, die von der übergeordneten Klasse deklariert wurden (== Berechtigungsmodifikatoren ermöglichen den Zugriff in Unterklassen)
  • Variablen mit vorangestelltem super.

    • Finden Sie Mitgliedsvariablen über Super und suchen Sie Mitgliedsvariablen direkt aus der direkten übergeordneten Klasse des aktuell ausgeführten Codes (Berechtigungsmodifikatoren ermöglichen den Zugriff in Unterklassen).
    • Wenn es keine direkte übergeordnete Klasse gibt, gehen Sie zur übergeordneten Klasse der übergeordneten Klasse, um sie zu finden (Berechtigungsmodifikatoren ermöglichen den Zugriff in Unterklassen).

Besonderer Hinweis: Unterklassendeklarationen und Mitgliedsvariablen mit demselben Namen wie die übergeordnete Klasse sollten vermieden werden

③Rufen Sie den Konstruktor der übergeordneten Klasse im Konstruktor der Unterklasse auf

In Java kann eine Unterklasse den Konstruktor der übergeordneten Klasse aufrufen, um die Mitgliedsvariablen der übergeordneten Klasse zu initialisieren, und die super()-Methode verwenden, um den Konstruktor der übergeordneten Klasse explizit aufzurufen. Wenn der Konstruktor der Unterklasse den Konstruktor der Oberklasse nicht explizit aufruft, wird standardmäßig der Konstruktor ohne Argumente der Oberklasse aufgerufen. Verwenden Sie die super()-Methode in der ersten Zeile des Unterklassenkonstruktors, um den Oberklassenkonstruktor aufzurufen. Zum Beispiel:

class Parent {
    
    
    int x;
    Parent(int x) {
    
    
        this.x = x;
    }
}

class Child extends Parent {
    
    
    int y;
    Child(int x, int y) {
    
    
        super(x); // 调用父类的构造器,初始化父类的 x 成员变量
        this.y = y;
    }
}

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Child c = new Child(10, 20);
        System.out.println(c.x); // 输出 10,父类的 x 成员变量已经被初始化
        System.out.println(c.y); // 输出 20
    }
}

Verwenden Sie die Methode super () im Konstruktor der Unterklasse, um den Konstruktor der übergeordneten Klasse explizit aufzurufen, sodass die Unterklasse während der Initialisierung auch die Initialisierung der übergeordneten Klasse abschließen kann, um den korrekten Betrieb des Programms sicherzustellen. Gleichzeitig müssen Sie bei der eigentlichen Programmierung auf die folgenden Punkte achten:

  1. Wenn der Konstruktor der übergeordneten Klasse im Konstruktor der Unterklasse nicht explizit aufgerufen wird, ruft das System standardmäßig den Konstruktor ohne Argumente der übergeordneten Klasse auf. Wenn die übergeordnete Klasse keinen Konstruktor ohne Argumente oder die Zugriffskontrolle des Konstruktors ohne Argumente hat ist privat, es wird ein Kompilierungsfehler auftreten. Zu diesem Zeitpunkt müssen Sie den Konstruktor der übergeordneten Klasse im Konstruktor der Unterklasse explizit aufrufen. Die Syntax lautet super (Parameterliste).
  2. Der Aufruf des Oberklassenkonstruktors sollte in der ersten Zeile des Unterklassenkonstruktors erfolgen.
  3. Wenn der Konstruktor der übergeordneten Klasse über mehrere Konstruktoren verfügt, kann die Unterklasse den angegebenen Konstruktor der übergeordneten Klasse explizit über super (Parameterliste) aufrufen. Ein Unterklassenkonstruktor kann nur einen Oberklassenkonstruktor aufrufen und muss in der ersten Zeile deklariert werden.
  4. Wenn im Konstruktor der übergeordneten Klasse eine Initialisierungsanweisung vorhanden ist, muss die Unterklasse ihren eigenen Konstruktor schreiben und den Konstruktor der übergeordneten Klasse aufrufen.

5.4.2 das und super

1. Die Bedeutung von this und super

Dies: das aktuelle Objekt

  • In Konstruktoren und nicht statischen Codeblöcken Objekte, die neu sind
  • In einer Instanzmethode das Objekt, das die aktuelle Methode aufruft

super: Bezieht sich auf die von der übergeordneten Klasse deklarierten Mitglieder

2. Das Verwendungsformat von this und super

  • Das
    • this.Member-Variable: Stellt eine Mitgliedsvariable des aktuellen Objekts dar, keine lokale Variable
    • this.Member-Methode: Gibt eine Member-Methode des aktuellen Objekts an. Sie können dies vollständig weglassen.
    • this () oder this (aktuelle Parameterliste): Rufen Sie einen anderen Konstruktor auf, um die Instanziierung des aktuellen Objekts zu unterstützen. Nur in der ersten Zeile des Konstruktors wird nur der Konstruktor dieser Klasse gefunden und ein Fehler wird gemeldet, wenn es kann nicht gefunden werden
  • super
    • super. Mitgliedsvariable: Gibt eine Mitgliedsvariable des aktuellen Objekts an, die in der übergeordneten Klasse deklariert ist
    • super. Mitgliedsmethode: Gibt eine Mitgliedsmethode des aktuellen Objekts an, die in der übergeordneten Klasse deklariert ist
    • super () oder super (Liste der tatsächlichen Parameter): Rufen Sie den Konstruktor der übergeordneten Klasse auf, um die Instanziierung des aktuellen Objekts zu unterstützen. Nur in der ersten Zeile des Konstruktors wird nur der entsprechende Konstruktor der direkten übergeordneten Klasse gefunden , und es wird ein Fehler gemeldet, wenn es nicht gefunden werden kann

üben

1. Erstellen Sie ein Klassen-Demokonto mit dem Namen „Konto“. Die Eigenschaften und Methoden dieser Klasse sind in der folgenden Abbildung dargestellt. In dieser Klasse enthaltene Attribute: Konto-ID, Kontostand, annualInterestRate; enthaltene Methoden: Zugriffsmethode (Getter- und Setter-Methoden), Methode getMonthlyInterest(), die den monatlichen Zinssatz zurückgibt, Auszahlungsmethode „draw()“, Einzahlungsmethode „deposit()“.

[Bildübertragung mit externem Link fehlgeschlagen, die Quellseite verfügt möglicherweise über einen Anti-Leeching-Mechanismus. Es wird empfohlen, das Bild zu speichern und direkt hochzuladen (img-ZPqLKGpD-1680682124909)(images/image-20220324003430464.png)]

package demo08;

public class Account {
    
    
    private int id; //账号id
    private double balance; //余额balance
    private double annualInterestRate; //年利率annualInterestRate
    public Account(int id, double balance, double annualInterestRate) {
    
    
        this.id = id;
        this.balance = balance;
        this.annualInterestRate = annualInterestRate;

    }
    public int getId() {
    
     // 获取账户
        return id;
    }

    public void setId(int id) {
    
     // 设置账户
        this.id = id;
    }

    public double getBalance() {
    
     // 获取余额
        return balance;
    }

    public void setBalance(double balance) {
    
     // 设置余额
        this.balance = balance;
    }

    public double getAnnualInterestRate() {
    
     //获取年利率
        return annualInterestRate;
    }

    public void setAnnualInterestRate(double annualInterestRate) {
    
     // 设置年利率
        this.annualInterestRate = annualInterestRate;
    }

    public double getMonthlyInterest() {
    
     // 获取月利率
        return annualInterestRate / 12;
    }

    public void withdraw(double amount) {
    
     // 取款
        if (amount > balance) {
    
    
            System.out.println("余额不足");
        } else {
    
    
            balance -= amount;
            System.out.println("成功取款" + amount + "元,账户余额为" + balance + "元");
        }
    }

    public void deposit(double amount) {
    
     // 存款
        balance += amount;
        System.out.println("成功存款" + amount + "元,账户余额为" + balance + "元");
    }
}

2. Erstellen Sie eine Unterklasse CheckAccount der Account-Klasse, um ein Konto darzustellen, das überzogen werden kann. Im Konto wird ein Attribut Überziehung definiert, um das Überziehungslimit darzustellen. Überschreiben Sie die Auszahlungsmethode in der CheckAccount-Klasse. Ihr Algorithmus lautet wie folgt:

如果(取款金额<账户余额),
	可直接取款
如果(取款金额>账户余额),
	计算需要透支的额度
	判断可透支额overdraft是否足够支付本次透支需要,如果可以
		将账户余额修改为0,冲减可透支金额
	如果不可以
		提示用户超过可透支额的限额
package demo08;

public class CheckAccount extends Account{
    
    
    private double overdraft;

    public CheckAccount(int id, double balance, double annualInterestRate, double overdraft) {
    
    
        super(id, balance, annualInterestRate);
        this.overdraft = overdraft;
    }

    public double getOverdraft() {
    
    
        return overdraft;
    }

    public void setOverdraft(double overdraft) {
    
    
        this.overdraft = overdraft;
    }
    @Override
    public void withdraw(double amount) {
    
     // 取款
        if (amount <= getBalance() + overdraft) {
    
    
            if (amount <= getBalance()) {
    
    
                setBalance(getBalance() - amount);
                System.out.println("成功取款" + amount + "元,账户余额为" + getBalance() + "元");
            } else {
    
    
                double overdraftAmount = amount - getBalance();
                setBalance(0);
                overdraft -= overdraftAmount;
                System.out.println("成功取款" + amount + "元,账户余额为0元,已透支" + overdraftAmount + "元,可透支额为" + overdraft + "元");
            }
        } else {
    
    
            System.out.println("余额不足,可透支额为" + overdraft + "元");
        }
    }
}

Anforderungen:
Schreiben Sie ein Benutzerprogramm zum Testen der Account-Klasse. Erstellen Sie im Benutzerprogramm ein Kontoobjekt mit der Kontonummer 1122, einem Saldo von 20.000 und einem jährlichen Zinssatz von 4,5 %. Verwenden Sie die Auszahlungsmethode, um 30.000 Yuan abzuheben und den Restbetrag auszudrucken.
Verwenden Sie dann die Abhebungsmethode, um 2.500 Yuan abzuheben, verwenden Sie die Einzahlungsmethode, um 3.000 Yuan einzuzahlen, und drucken Sie dann den Kontostand und den monatlichen Zinssatz aus.
Tipp: Bei der Auszahlungsmethode Auszahlung muss beurteilt werden, ob das Guthaben des Benutzers die Anforderungen des Auszahlungsbetrags erfüllen kann. Wenn nicht, sollte eine Aufforderung erfolgen.
Schreiben Sie ein Benutzerprogramm, um die CheckAccount-Klasse zu testen. Erstellen Sie im Benutzerprogramm ein CheckAccount-Objekt mit der Kontonummer 1122, einem Saldo von 20.000, einem jährlichen Zinssatz von 4,5 % und einem Überziehungslimit von 5.000 Yuan.
Verwenden Sie die Abhebungsmethode, um 5.000 Yuan abzuheben und den Kontostand und den Überziehungsbetrag auszudrucken.
Verwenden Sie dann die Auszahlungsmethode, um 18.000 Yuan abzuheben, und drucken Sie den Kontostand und den Überziehungsbetrag aus.
Verwenden Sie dann die Abhebungsmethode, um 3.000 Yuan abzuheben, und drucken Sie den Kontostand und den Überziehungsbetrag aus.
Tipps:
(1) Die Konstruktionsmethode der Unterklasse CheckAccount muss alle drei von der übergeordneten Klasse geerbten Attribute und die Attribute der Unterklasse selbst initialisieren.
(2) Der Attributsaldo des Kontos der übergeordneten Klasse ist auf privat gesetzt, sein Wert muss jedoch in der Auszahlungsmethode der Unterklasse CheckAccount geändert werden, sodass das Saldoattribut der übergeordneten Klasse geändert und als geschützt definiert werden sollte.

package demo08;
public class Test {
    
    
    public static void main(String[] args) {
    
    
        // 创建账号为1122、余额为20000、年利率4.5%的Account对象
        Account account = new Account(1122, 20000, 0.045);
        // 使用withdraw方法提款30000元,并打印余额
        account.withdraw(30000);
        // 使用withdraw方法提款2500元,使用deposit方法存款3000元,然后打印余额和月利率
        account.withdraw(2500);
        account.deposit(3000);
        System.out.println("账户余额为" + account.getBalance() + "元,月利率为" + account.getMonthlyInterest() * 100 + "%");

        // 创建账号为1122、余额为20000、年利率4.5%,可透支限额为5000元的CheckAccount对象
        CheckAccount checkAccount = new CheckAccount(1122, 20000, 0.045, 5000);
        // 使用withdraw方法提款5000元,并打印账户余额和可透支额
        checkAccount.withdraw(5000);
        System.out.println("账户余额为" + checkAccount.getBalance() + "元,可透支额为" + checkAccount.getOverdraft() + "元");
        // 使用withdraw方法提款18000元,并打印账户余额和可透支额
        checkAccount.withdraw(18000);
        System.out.println("账户余额为" + checkAccount.getBalance() + "元,可透支额为" + checkAccount.getOverdraft() + "元");
        // 使用withdraw方法提款3000元,并打印账户余额和可透支额
        checkAccount.withdraw(3000);
        System.out.println("账户余额为" + checkAccount.getBalance() + "元,可透支额为" + checkAccount.getOverdraft() + "元");
    }
}

>运行结果
余额不足
成功取款2500.0元,账户余额为17500.0元
成功存款3000.0元,账户余额为20500.0元
账户余额为20500.0元,月利率为0.375%
成功取款5000.0元,账户余额为15000.0元
账户余额为15000.0元,可透支额为5000.0元
成功取款18000.0元,账户余额为0元,已透支3000.0元,可透支额为2000.0元
账户余额为0.0元,可透支额为2000.0元
余额不足,可透支额为2000.0元
账户余额为0.0元,可透支额为2000.0

Der gesamte Prozess der Instanziierung von Unterklassenobjekten

[Externer Link zur Bildübertragung ist fehlgeschlagen. Die Quellseite verfügt möglicherweise über einen Anti-Leeching-Mechanismus. Es wird empfohlen, das Bild zu speichern und direkt hochzuladen (img-GiQ5vZpD-1680443622972)(images/image-20220324003713230.png)]

Beispiel:

class Creature {
    
    
    public Creature() {
    
    
        System.out.println("Creature无参数的构造器");
	}
}
class Animal extends Creature {
    
    
    public Animal(String name) {
    
    
        System.out.println("Animal带一个参数的构造器,该动物的name为" + name);
    }
    public Animal(String name, int age) {
    
    
        this(name);
        System.out.println("Animal带两个参数的构造器,其age为" + age);
	}
}
public class Dog extends Animal {
    
    
    public Dog() {
    
    
        super("汪汪队阿奇", 3);
        System.out.println("Dog无参数的构造器");
    }
    public static void main(String[] args) {
    
    
        new Dog();
	}
}

5.5 Merkmal drei: Polymorphismus

In den Augen von tausend Lesern gibt es tausend Hamlets.

5.5.1 Form und Verkörperung des Polymorphismus

Objektpolymorphismus

Polymorphismus ist das wichtigste objektorientierte Konzept, das in Java verkörpert ist: Polymorphismus von Objekten: Die Referenz der übergeordneten Klasse zeigt auf das Objekt der Unterklasse

Format: (Übergeordneter Klassentyp: Bezieht sich auf den von der Unterklasse geerbten übergeordneten Klassentyp oder den implementierten Schnittstellentyp.)

父类类型 变量名 = 子类对象;

Beispiel:

Person p = new Student();

Object o = new Person();//Object类型的变量o,指向Person类型的对象

o = new Student(); //Object类型的变量o,指向Student类型的对象

Objektpolymorphismus: In Java kann ein Objekt einer Unterklasse anstelle eines Objekts der übergeordneten Klasse verwendet werden. Daher kann eine Referenztypvariable auf viele verschiedene Objekttypen verweisen (referenzieren).

polymorphes Verständnis

Java-Referenzvariablen haben zwei Typen: 编译时类型und 运行时类型. Der Kompilierzeittyp 声明wird durch den von der Variablen verwendeten Typ bestimmt, und der Laufzeittyp wird 实际赋给该变量的对象durch die Variable bestimmt. Abkürzung: Schauen Sie beim Kompilieren nach links, beim Ausführen nach rechts.

  • Wenn der Typ zur Kompilierungszeit nicht mit dem Typ zur Laufzeit übereinstimmt, liegt ein Polymorphismus des Objekts vor (Polymorphismus).
  • Im Fall von Polymorphismus: „Schauen Sie nach links“: Sehen Sie sich die Referenz der übergeordneten Klasse an (die übergeordnete Klasse verfügt nicht über die für die Unterklasse spezifische Methode). „Schauen Sie nach rechts“: Sehen Sie sich das Objekt der
    Unterklasse an ( Die eigentliche Ausführung ist das Umschreiben der Unterklassenmethode der übergeordneten Klasse.)

Voraussetzungen für Polymorphismus: ① Klassenvererbungsbeziehung ② Methodenumschreibung

Beispiel

public class Pet {
    
    
    private String nickname; //昵称

    public String getNickname() {
    
    
        return nickname;
    }

    public void setNickname(String nickname) {
    
    
        this.nickname = nickname;
    }

    public void eat(){
    
    
        System.out.println(nickname + "吃东西");
    }
}
public class Cat extends Pet {
    
    
    //子类重写父类的方法
    @Override
    public void eat() {
    
    
        System.out.println("猫咪" + getNickname() + "吃鱼仔");
    }

    //子类扩展的方法
    public void catchMouse() {
    
    
        System.out.println("抓老鼠");
    }
}
public class Dog extends Pet {
    
    
    //子类重写父类的方法
    @Override
    public void eat() {
    
    
        System.out.println("狗子" + getNickname() + "啃骨头");
    }

    //子类扩展的方法
    public void watchHouse() {
    
    
        System.out.println("看家");
    }
}

1. Die Zuweisung lokaler Variablen in der Methode spiegelt Polymorphismus wider

public class TestPet {
    
    
    public static void main(String[] args) {
    
    
        //多态引用
        Pet pet = new Dog();
        pet.setNickname("小白");

        //多态的表现形式
        /*
        编译时看父类:只能调用父类声明的方法,不能调用子类扩展的方法;
        运行时,看“子类”,如果子类重写了方法,一定是执行子类重写的方法体;
         */
        pet.eat();//运行时执行子类Dog重写的方法
//      pet.watchHouse();//不能调用Dog子类扩展的方法

        pet = new Cat();
        pet.setNickname("雪球");
        pet.eat();//运行时执行子类Cat重写的方法
    }
}

2. Die formale Parameterdeklaration der Methode spiegelt den Polymorphismus wider

public class Person{
    
    
    private Pet pet;
    public void adopt(Pet pet) {
    
    //形参是父类类型,实参是子类对象
        this.pet = pet;
    }
    public void feed(){
    
    
        pet.eat();//pet实际引用的对象类型不同,执行的eat方法也不同
    }
}
public class TestPerson {
    
    
    public static void main(String[] args) {
    
    
        Person person = new Person();

        Dog dog = new Dog();
        dog.setNickname("小白");
        person.adopt(dog);//实参是dog子类对象,形参是父类Pet类型
        person.feed();

        Cat cat = new Cat();
        cat.setNickname("雪球");
        person.adopt(cat);//实参是cat子类对象,形参是父类Pet类型
        person.feed();
    }
}

3. Der Rückgabewerttyp der Methode spiegelt den Polymorphismus wider

public class PetShop {
    
    
    //返回值类型是父类类型,实际返回的是子类对象
    public Pet sale(String type){
    
    
        switch (type){
    
    
            case "Dog":
                return new Dog();
            case "Cat":
                return new Cat();
        }
        return null;
    }
}
public class TestPetShop {
    
    
    public static void main(String[] args) {
    
    
        PetShop shop = new PetShop();

        Pet dog = shop.sale("Dog");
        dog.setNickname("小白");
        dog.eat();

        Pet cat = shop.sale("Cat");
        cat.setNickname("雪球");
        cat.eat();
    }
}

Wenn wir in der Entwicklung ein Array, eine Mitgliedsvariable oder den formalen Parameter- und Rückgabewerttyp einer Methode entwerfen, können wir manchmal nicht dessen spezifischen Typ bestimmen, sondern nur feststellen, dass es sich um eine bestimmte Reihe von Typen handelt.

Fall:

(1) Deklarieren Sie eine Hundeklasse, einschließlich der öffentlichen Methode void eat(), und geben Sie „Hund nagt an Knochen“ aus.

(2) Deklarieren Sie eine Cat-Klasse, einschließlich der öffentlichen Methode void eat(), und geben Sie „Die Katze frisst den Fisch“ aus.

(3) Deklarieren Sie eine Personenklasse mit den folgenden Funktionen:

  • Enthält Haustiereigenschaften
  • Enthält die Methode zur öffentlichen Adoption eines Haustiers (Haustiertyp „Haustier“).
  • Enthält die Methode public void feed() zum Füttern von Haustieren, implementiert als Aufruf der Methode pet object.eat()
public class Dog {
    
    
    public void eat(){
    
    
        System.out.println("狗啃骨头");
    }
}
public class Cat {
    
    
    public void eat(){
    
    
        System.out.println("猫吃鱼仔");
    }
}
public class Person {
    
    
    private Dog dog;

    //adopt:领养
    public void adopt(Dog dog){
    
    
        this.dog = dog;
    }

    //feed:喂食
    public void feed(){
    
    
        if(dog != null){
    
    
            dog.eat();
        }
    }
}

5.5.2 Vor- und Nachteile des Polymorphismus

Vorteile : Verschiedene Unterklassenobjekte, auf die durch Variablen verwiesen wird, verfügen über unterschiedliche Ausführungsmethoden, wodurch eine dynamische Bindung realisiert wird. Das Schreiben des Codes ist flexibler, die Funktion ist leistungsfähiger und die Wartbarkeit und Skalierbarkeit sind besser.

Nachteile : Wenn eine Referenztypvariable als Typ der übergeordneten Klasse deklariert wird, sich jedoch tatsächlich auf das Unterklassenobjekt bezieht, kann die Variable nicht mehr auf die in der Unterklasse hinzugefügten Eigenschaften und Methoden zugreifen.

Student m = new Student();
m.school = "pku"; 	//合法,Student类有school成员变量
Person e = new Student(); 
e.school = "pku";	//非法,Person类没有school成员变量

// 属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

In Entwicklung:

Die Verwendung der übergeordneten Klasse als formaler Parameter der Methode ist der am häufigsten verwendete Polymorphismus-Anlass. Selbst wenn eine neue Unterklasse hinzugefügt wird, muss die Methode nicht geändert werden, was die Skalierbarkeit verbessert und dem Prinzip des Öffnens und Schließens entspricht.

【Öffnungs- und Schließprinzip OCP】

  • Offen für Erweiterungen, geschlossen für Änderungen
  • Beliebte Erklärung: Verschiedene Komponenten in einem Softwaresystem, wie Module (Module), Klassen (Classes) und Funktionen (Functions), sollten neue Funktionen einführen, ohne vorhandene Codes zu ändern.

5.5.3 Aufruf virtueller Methoden

In Java bezieht sich eine virtuelle Methode auf eine Methode, deren Aufrufeintragsadresse nicht in der Kompilierungsphase, sondern nur in der Laufzeitphase bestimmt werden kann, dh eine Methode, die möglicherweise neu geschrieben wird.

Person e = new Student();
e.getInfo();	//调用Student类的getInfo()方法

Die Methode mit demselben Namen und denselben Parametern wie die übergeordnete Klasse wird in der Unterklasse definiert. Im Fall von Polymorphismus wird die Methode der übergeordneten Klasse zu diesem Zeitpunkt als virtuelle Methode bezeichnet. Die übergeordnete Klasse ruft die zugehörigen Methoden dynamisch auf Die Unterklasse entsprechend den verschiedenen ihr zugewiesenen Unterklassenobjekten. Diese Methode. Solche Methodenaufrufe können zur Kompilierungszeit nicht ermittelt werden.

静态链接(或早起绑定): Wenn eine Bytecode-Datei in die JVM geladen wird, wenn die aufgerufene Zielmethode zur Kompilierungszeit bekannt ist und zur Laufzeit unverändert bleibt. In diesem Fall wird der Vorgang der Umwandlung der symbolischen Referenz der aufrufenden Methode in eine direkte Referenz als statisches Linken bezeichnet. Dann wird der Aufruf einer solchen Methode als nicht-virtueller Methodenaufruf bezeichnet. Rufen Sie beispielsweise statische Methoden, private Methoden, endgültige Methoden, Konstruktoren der übergeordneten Klasse und überladene Konstruktoren dieser Klasse auf.

动态链接(或晚期绑定): Wenn die aufgerufene Methode zur Kompilierungszeit nicht ermittelt werden kann, dh die symbolische Referenz der aufrufenden Methode kann nur zur Programmlaufzeit in eine direkte Referenz konvertiert werden, da dieser Referenzkonvertierungsprozess dynamisch ist, wird er auch als It bezeichnet ist ein dynamischer Link. Der Aufruf einer solchen Methode wird als virtueller Methodenaufruf bezeichnet. Rufen Sie beispielsweise die umgeschriebene Methode (für die übergeordnete Klasse) und die implementierte Methode (für die Schnittstelle) auf.

5.5.4 Mitgliedsvariablen sind nicht polymorph

  • Wenn die Unterklasse die Methode der übergeordneten Klasse neu schreibt, bedeutet dies, dass die in der Unterklasse definierte Methode die gleichnamige Methode in der übergeordneten Klasse vollständig abdeckt und das System die Methode in der übergeordneten Klasse nicht auf die übertragen kann Unterklasse.

  • Bei Instanzvariablen existiert dieses Phänomen nicht. Auch wenn die Instanzvariable, die genau mit der übergeordneten Klasse übereinstimmt, in der Unterklasse definiert ist, ist es für diese Instanzvariable immer noch unmöglich, die in der übergeordneten Klasse definierte Instanzvariable zu überschreiben.

public class TestVariable {
    
    
    public static void main(String[] args) {
    
    
        Base b = new Sub();
        System.out.println(b.a);
        System.out.println(((Sub)b).a);

        Sub s = new Sub();
        System.out.println(s.a);
        System.out.println(((Base)s).a);
    }
}
class Base{
    
    
    int a = 1;
}
class Sub extends Base{
    
    
    int a = 2;
}

5.5.5 Aufwärtstransformation und Abwärtstransformation

Erstens: Welche Art von Objekt ein neues Objekt erstellt, ändert sich von Anfang bis Ende nicht. Das heißt, der Laufzeittyp dieses Objekts und der wesentliche Typ werden verwendet, um sich nicht zu ändern. Wenn dieses Objekt jedoch Variablen unterschiedlichen Typs zugewiesen wird, sind die Typen dieser Variablen zur Kompilierungszeit unterschiedlich.
Polymorphismus: Es muss einen Zeitpunkt geben, an dem das Unterklassenobjekt der Variablen der übergeordneten Klasse zugewiesen wird. Zu diesem Zeitpunkt 编译期间tritt ein Typkonvertierungsphänomen auf.
Nachdem wir jedoch die Variable der übergeordneten Klasse zum Empfangen des Objekts der Unterklasse verwendet haben, 不能调用verfügen wir über Methoden, über die die Unterklasse verfügt, die übergeordnete Klasse jedoch nicht. Dies ist auch ein kleines „kleines Problem“, das uns der Polymorphismus bereitet. Wenn Sie daher eine für eine Unterklasse eindeutige Methode aufrufen möchten, müssen Sie eine Typkonvertierung durchführen, damit 编译通过.

  • Upcasting : Wenn der Typ der Variablen links (übergeordnete Klasse) > der Typ des Objekts/der Variablen rechts (Unterklasse) ist, nennen wir es Upcasting

    • Zu diesem Zeitpunkt können Sie beim Kompilieren entsprechend dem Typ der Variablen auf der linken Seite nur die Variablen und Methoden in der übergeordneten Klasse aufrufen und nicht die eindeutigen Variablen und Methoden der Unterklasse.
    • Zur Laufzeit ist es jedoch immer noch der Typ des Objekts selbst . Die ausgeführte Methode ist also der von der Unterklasse neu geschriebene Methodenkörper.
    • Zu diesem Zeitpunkt muss es sicher sein und erfolgt auch automatisch
  • Downcasting : Wenn der Typ (Unterklasse) der Variablen auf der linken Seite < der Kompilierzeittyp (übergeordnete Klasse) des Objekts/der Variablen auf der rechten Seite ist, nennen wir es Downcasting

    • Zu diesem Zeitpunkt können Sie je nach Typ der Variablen auf der linken Seite beim Kompilieren die eindeutigen Variablen und Methoden der Unterklasse aufrufen
    • Zur Laufzeit ist es jedoch immer noch der Typ des Objekts selbst
    • Nicht alle Abwärtstransformationen durch Kompilierung sind korrekt und es kann zu ClassCastException kommen. Aus Sicherheitsgründen können Sie zur Beurteilung das Schlüsselwort isInstanceof verwenden

Aufwärtstransformation: automatische Vervollständigung

Abwärtstransformation: (Unterklassentyp) übergeordnete Klassenvariable

public class ClassCastTest {
    
    
    public static void main(String[] args) {
    
    
        //没有类型转换
        Dog dog = new Dog();//dog的编译时类型和运行时类型都是Dog

        //向上转型
        Pet pet = new Dog();//pet的编译时类型是Pet,运行时类型是Dog
        pet.setNickname("小白");
        pet.eat();//可以调用父类Pet有声明的方法eat,但执行的是子类重写的eat方法体
//        pet.watchHouse();//不能调用父类没有的方法watchHouse

        Dog d = (Dog) pet;
        System.out.println("d.nickname = " + d.getNickname());
        d.eat();//可以调用eat方法
        d.watchHouse();//可以调用子类扩展的方法watchHouse

        Cat c = (Cat) pet;//编译通过,因为从语法检查来说,pet的编译时类型是Pet,Cat是Pet的子类,所以向下转型语法正确
        //这句代码运行报错ClassCastException,因为pet变量的运行时类型是Dog,Dog和Cat之间是没有继承关系的
    }
}

5.5.6 Schlüsselwort: Instanz von

Um das Auftreten von ClassCastException zu vermeiden, stellt Java instanceofdas Schlüsselwort zur Überprüfung des Typs von Referenzvariablen bereit. Das Codeformat ist wie folgt:

//检验对象a是否是数据类型A的对象,返回值为boolean型
对象a instanceof 数据类型A 
  • veranschaulichen:
    • Solange „instanceof“ „true“ zurückgibt, muss die Umwandlung in diesen Typ sicher sein, und ClassCastException wird nicht gemeldet.
    • Wenn Objekt a zur Unterklasse B der Klasse A gehört, ist der Wert einer Instanz von A ebenfalls wahr.
    • Es ist erforderlich, dass die Klasse, zu der das Objekt a gehört, und die Klasse A in der Beziehung zwischen einer Unterklasse und einer übergeordneten Klasse stehen müssen, andernfalls tritt ein Kompilierungsfehler auf.

Code:

public class TestInstanceof {
    
    
    public static void main(String[] args) {
    
    
        Pet[] pets = new Pet[2];
        pets[0] = new Dog();//多态引用
        pets[0].setNickname("小白");
        pets[1] = new Cat();//多态引用
        pets[1].setNickname("雪球");

        for (int i = 0; i < pets.length; i++) {
    
    
            pets[i].eat();

            if(pets[i] instanceof Dog){
    
    
                Dog dog = (Dog) pets[i];
                dog.watchHouse();
            }else if(pets[i] instanceof Cat){
    
    
                Cat cat = (Cat) pets[i];
                cat.catchMouse();
            }
        }
    }
}

Übung: Schriftlicher Test und Vorstellungsgespräch

Thema 1: Der Unterschied zwischen geerbten Mitgliedsvariablen und geerbten Methoden

class Base {
    
    
    int count = 10;
    public void display() {
    
    
        System.out.println(this.count);
    }
}

class Sub extends Base {
    
    
    int count = 20;
    public void display() {
    
    
        System.out.println(this.count);
    }
}

public class FieldMethodTest {
    
    
    public static void main(String[] args){
    
    
        Sub s = new Sub();
        System.out.println(s.count);
        s.display();
        Base b = s;
        System.out.println(b == s);
        System.out.println(b.count);
        b.display();
    }
}

Thema 2:

//考查多态的笔试题目:
public class InterviewTest1 {
    
    

	public static void main(String[] args) {
    
    
		Base base = new Sub();
		base.add(1, 2, 3);

//		Sub s = (Sub)base;
//		s.add(1,2,3);
	}
}

class Base {
    
    
	public void add(int a, int... arr) {
    
    
		System.out.println("base");
	}
}

class Sub extends Base {
    
    

	public void add(int a, int[] arr) {
    
    
		System.out.println("sub_1");
	}

//	public void add(int a, int b, int c) {
    
    
//		System.out.println("sub_2");
//	}

}

Thema 3:

//getXxx()和setXxx()声明在哪个类中,内部操作的属性就是哪个类里的。
public class InterviewTest2 {
    
    
	public static void main(String[] args) {
    
    
		Father f = new Father();
		Son s = new Son();
		System.out.println(f.getInfo());//atguigu
		System.out.println(s.getInfo());//尚硅谷
		s.test();//尚硅谷  atguigu
		System.out.println("-----------------");
		s.setInfo("大硅谷");
		System.out.println(f.getInfo());//atguigu
		System.out.println(s.getInfo());//大硅谷
		s.test();//大硅谷  atguigu
	}
}

class Father {
    
    
	private String info = "atguigu";

	public void setInfo(String info) {
    
    
		this.info = info;
	}

	public String getInfo() {
    
    
		return info;
	}
}

class Son extends Father {
    
    
	private String info = "尚硅谷";
	
	public void setInfo(String info) {
    
    
		this.info = info;
	}

	public String getInfo() {
    
    
		return info;
	}
	
	public void test() {
    
    
		System.out.println(this.getInfo());
		System.out.println(super.getInfo());
	}
}

Frage 4: Ist Polymorphismus ein Verhalten zur Kompilierungszeit oder ein Verhalten zur Laufzeit?

//证明如下:
class Animal  {
    
    
	protected void eat() {
    
    
		System.out.println("animal eat food");
	}
}

class Cat  extends Animal  {
    
    
	protected void eat() {
    
    
		System.out.println("cat eat fish");
	}
}

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

class Sheep  extends Animal  {
    
    
	public void eat() {
    
    
		System.out.println("Sheep eat grass");
	}
}

public class InterviewTest {
    
    
	public static Animal  getInstance(int key) {
    
    
		switch (key) {
    
    
		case 0:
			return new Cat ();
		case 1:
			return new Dog ();
		default:
			return new Sheep ();
		}

	}

	public static void main(String[] args) {
    
    
		int key = new Random().nextInt(3);
		System.out.println(key);

		Animal  animal = getInstance(key);
		animal.eat(); 
	}
}

5.6 Verwendung der Object-Klasse

Eine Klasse java.lang.Objectist die Stammklasse der Klassenhierarchie, die übergeordnete Klasse aller anderen Klassen. Jede Klasse wird Objectals Superklasse verwendet.

  • Es gibt polymorphe Referenzen zwischen Variablen vom Typ „Objekt“ und Objekten eines beliebigen Referenzdatentyps außer „Objekt“.

    method(Object obj){
          
          } //可以接收任何类作为其参数
    
    Person o = new Person();  
    method(o);
    
    
  • Alle Objekte (einschließlich Arrays) implementieren die Methoden dieser Klasse.

  • Wenn eine Klasse keine übergeordnete Klasse angibt, erbt sie standardmäßig von der Object-Klasse. Zum Beispiel:

    public class Person {
          
          
    	...
    }
    //等价于:
    public class Person extends Object {
          
          
    	...
    }
    

5.6.1 Methoden der Object-Klasse

Gemäß dem JDK-Quellcode und der API-Dokumentation der Object-Klasse sind in der Object-Klasse 11 Methoden enthalten. Hier konzentrieren wir uns hauptsächlich auf sechs davon:

1. (Schlüssel) equal()

= =:

  • Primitive Typen vergleichen Werte: true, wenn die Werte zweier Variablen gleich sind.

    int a=5; 
    if(a==6){
          
          }
    
  • Referenztypen vergleichen Referenzen (unabhängig davon, ob sie auf dasselbe Objekt verweisen): == gibt nur dann true zurück, wenn sie auf dasselbe Objekt verweisen.

    Person p1=new Person();  	    
    Person p2=new Person();
    if (p1==p2){
          
          }
    
    • Wenn Sie zum Vergleich "==" verwenden, wird auf beiden Seiten des Symbols 数据类型必须兼容(mit Ausnahme der Basisdatentypen, die automatisch konvertiert werden können) ein Kompilierungsfehler angezeigt

**equals():**Alle Klassen erben Object, sodass sie die Methode equal() erhalten. Kann auch überschrieben werden.

  • Es können nur Referenztypen verglichen werden. Die Funktion von equal() im Quellcode der Object-Klasse ist dieselbe wie „==“: um zu vergleichen, ob sie auf dasselbe Objekt verweisen.

    Bild-20220503104750655
  • Format: obj1.equals(obj2)

  • Sonderfall: Bei Verwendung der Methode equal() zum Vergleich werden für die Klassen File, String, Date und Wrapper-Klassen (Wrapper-Klasse) Typ und Inhalt unabhängig davon verglichen, ob es sich bei den Referenzen um dasselbe Objekt handelt.

    • Grund: Die Methode equal() der Klasse Object wird in diesen Klassen überschrieben.
  • Beim Anpassen von equal() kann es überschrieben werden. Wird verwendet, um zu vergleichen, ob die „Inhalte“ zweier Objekte gleich sind

  • Das Prinzip des Überschreibens der Methode equal()

    • 对称性: Wenn x.equals(y) „wahr“ zurückgibt, dann sollte y.equals(x) auch „wahr“ zurückgeben.

    • 自反性: x.equals(x) muss „true“ zurückgeben.

    • 传递性: Wenn x.equals(y) „wahr“ und y.equals(z) „wahr“ zurückgibt, dann sollte z.equals(x) auch „wahr“ zurückgeben.

    • 一致性: Wenn x.equals(y) „wahr“ zurückgibt, ist die Rückgabe „wahr“, solange der Inhalt von x und y unverändert bleibt, egal wie oft Sie x.equals(y) wiederholen.

    • In jedem Fall gibt x.equals(null) immer „false“ zurück;

      x.equals (ein Objekt eines anderen Typs als x) gibt immer „false“ zurück.

  • Beispiel zum Umschreiben:

class User{
    
    
	private String host;
	private String username;
	private String password;
	public User(String host, String username, String password) {
    
    
		super();
		this.host = host;
		this.username = username;
		this.password = password;
	}
	public User() {
    
    
		super();
	}
	public String getHost() {
    
    
		return host;
	}
	public void setHost(String host) {
    
    
		this.host = host;
	}
	public String getUsername() {
    
    
		return username;
	}
	public void setUsername(String username) {
    
    
		this.username = username;
	}
	public String getPassword() {
    
    
		return password;
	}
	public void setPassword(String password) {
    
    
		this.password = password;
	}
	@Override
	public String toString() {
    
    
		return "User [host=" + host + ", username=" + username + ", password=" + password + "]";
	}
	@Override
	public boolean equals(Object obj) {
    
    
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (host == null) {
    
    
			if (other.host != null)
				return false;
		} else if (!host.equals(other.host))
			return false;
		if (password == null) {
    
    
			if (other.password != null)
				return false;
		} else if (!password.equals(other.password))
			return false;
		if (username == null) {
    
    
			if (other.username != null)
				return false;
		} else if (!username.equals(other.username))
			return false;
		return true;
	}
	
}

Interviewfrage: Der Unterschied zwischen == und equal

  • == kann sowohl primitive Typen als auch Referenztypen vergleichen. Bei Basistypen handelt es sich um den Vergleich von Werten und bei Referenztypen um den Vergleich von Speicheradressen

  • Für Equals gehört es zur Methode in der Klasse java.lang.Object. Wenn die Methode nicht überschrieben wurde, ist sie standardmäßig auch ==; wir können sehen, dass die Equals-Methode von String und anderen Klassen überschrieben wurde Die String-Klasse wird in der täglichen Entwicklung häufig verwendet und im Laufe der Zeit hat sich die falsche Ansicht gebildet, dass „equals“ ein Vergleichswert ist.

  • Insbesondere hängt es davon ab, ob die Methode equal von Object in der benutzerdefinierten Klasse neu geschrieben wird, um zu beurteilen.

  • Normalerweise wird durch Überschreiben der Methode „equals“ verglichen, ob die entsprechenden Eigenschaften in der Klasse gleich sind.

Übung 1:

int it = 65;
float fl = 65.0f;
System.out.println("65和65.0f是否相等?" + (it == fl)); // 输出 false
//65 和 65.0f 不相等,因为它们虽然值相同,但数据类型不同

char ch1 = 'A'; char ch2 = 12;
System.out.println("65和'A'是否相等?" + (it == ch1)); // 输出 true
//65 和 'A' 相等,因为在 char 类型中,A 的 Unicode 码值是 65,也就是说 ch1 的值是 65
System.out.println("12和ch2是否相等?" + (12 == ch2)); // 输出 true
//12 和 ch2 相等,因为它们的值相同,都是 12

String str1 = new String("hello");
String str2 = new String("hello");
System.out.println("str1和str2是否相等?" + (str1 == str2)); // 输出 false
//str1 和 str2 不相等,因为它们虽然存储的字符串相同,但是是两个不同的对象,比较的是两者在内存中的引用地址

System.out.println("str1是否equals str2?" + (str1.equals(str2))); // 输出 true
//str1.equals(str2) 返回 true,说明两个对象存储的字符串相等
System.out.println("hello" == new java.util.Date()); // 抛出编译错误,因为无法比较两个不同类型的对象

Übung 2:

Schreiben Sie die Order-Klasse, die über eine int-Typ-OrderId, einen String-Typ-OrderName, entsprechende getter()- und setter()-Methoden sowie einen Konstruktor mit zwei Parametern verfügt und die equal()-Methode der übergeordneten Klasse überschreibt: public boolean equal(Object obj) und beurteilen Sie, ob die beiden in der Testklasse erstellten Objekte gleich sind.

public class Order {
    
    
    private int orderId; // 订单编号
    private String orderName; // 订单名称

    /**
     * 两个参数的构造器
     * @param orderId 订单编号
     * @param orderName 订单名称
     */
    public Order(int orderId, String orderName) {
    
    
        this.orderId = orderId;
        this.orderName = orderName;
    }

    /**
     * 获取订单编号
     * @return 订单编号
     */
    public int getOrderId() {
    
    
        return orderId;
    }

    /**
     * 设置订单编号
     * @param orderId 订单编号
     */
    public void setOrderId(int orderId) {
    
    
        this.orderId = orderId;
    }

    /**
     * 获取订单名称
     * @return 订单名称
     */
    public String getOrderName() {
    
    
        return orderName;
    }

    /**
     * 设置订单名称
     * @param orderName 订单名称
     */
    public void setOrderName(String orderName) {
    
    
        this.orderName = orderName;
    }

    /**
     * 重写 equals 方法,判断两个对象是否相等
     * @param obj 待比较对象
     * @return true(相等)/false(不相等)
     */
    @Override
    public boolean equals(Object obj) {
    
    
        if (this == obj) //判断是否为同一个对象
            return true;
        if (obj instanceof Order) {
    
     //判断是否为同一类型
            Order order = (Order) obj;
            return this.orderId == order.orderId && this.orderName.equals(order.orderName); // 判断两个对象的 orderId 和 orderName 是否相等
        }
        return false;
    }

    public static void main(String[] args) {
    
    
        Order order1 = new Order(1, "order1"); // 创建 Order 对象 1
        Order order2 = new Order(2, "order2"); // 创建 Order 对象 2
        Order order3 = new Order(1, "order1"); // 创建 Order 对象 3
        System.out.println(order1.equals(order2)); // 判断 Order 对象 1 和 2 是否相等
        // 结果:false
        System.out.println(order1.equals(order3)); // 判断 Order 对象 1 和 3 是否相等
        // 结果:true
    }
}

2. (Hervorhebung) toString()

Methodensignatur: öffentlicher String toString()

① Standardmäßig gibt toString() „die hexadezimale Form des Laufzeittyps des Objekts @ des HashCode-Werts des Objekts“ zurück.

② Beim Verbinden von String und anderen Datentypen wird die Methode toString() automatisch aufgerufen

Date now=new Date();
System.out.println(“now=+now);  //相当于
System.out.println(“now=+now.toString()); 

③ Wenn wir System.out.println (Objekt) direkt aufrufen, wird standardmäßig automatisch toString () dieses Objekts aufgerufen

Da die Speicheradresse des Objekts tatsächlich in der Variablen des Referenzdatentyps von Java gespeichert ist, Java die Speicheradresseninformationen jedoch vor dem Programmierer verbirgt, kann die Speicheradresse nicht direkt angezeigt werden. Wenn Sie also das Objekt drucken, wird die JVM ruft es für toString() Ihres Objekts auf.

④ Die toString()-Methode kann nach Bedarf in den benutzerdefinierten Typ umgeschrieben werden.
Beispielsweise schreibt die String-Klasse die toString()-Methode um, um den Wert der Zeichenfolge zurückzugeben.

s1="hello";
System.out.println(s1);//相当于System.out.println(s1.toString());

Zum Beispiel eine benutzerdefinierte Person-Klasse:

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

    @Override
    public String toString() {
    
    
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

3、klon()

//Object类的clone()的使用
public class CloneTest {
    
    
	public static void main(String[] args) {
    
    
		Animal a1 = new Animal("花花");
		try {
    
    
			Animal a2 = (Animal) a1.clone();
			System.out.println("原始对象:" + a1);
			a2.setName("毛毛");
			System.out.println("clone之后的对象:" + a2);
		} catch (CloneNotSupportedException e) {
    
    
			e.printStackTrace();
		}
	}
}

class Animal implements Cloneable{
    
    
	private String name;

	public Animal() {
    
    
		super();
	}

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

	public String getName() {
    
    
		return name;
	}

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

	@Override
	public String toString() {
    
    
		return "Animal [name=" + name + "]";
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
    
    
		// TODO Auto-generated method stub
		return super.clone();
	}
	
}

4、finalize()

  • Wenn ein Objekt recycelt wird, ruft das System automatisch die finalize()-Methode des Objekts auf. (nicht vom Garbage Collector aufgerufen, sondern vom Objekt dieser Klasse aufgerufen)
    • Die finalize-Methode eines Objekts sollte immer 不要主动调用vom Garbage-Collection-Mechanismus aufgerufen werden.
  • Wann wird es recycelt: Wenn ein Objekt keine Referenzen hat, betrachtet die JVM das Objekt als Garbage-Objekt und verwendet den Garbage-Collection-Mechanismus, um das Objekt zu einem unbestimmten Zeitpunkt später zu zerstören. Bevor das Objekt zerstört wird, ruft es auf finalize ()-Methode.
  • Unterklassen können diese Methode überschreiben, um notwendige Bereinigungsvorgänge durchzuführen, bevor das Objekt bereinigt wird. Trennen Sie beispielsweise verwandte Verbindungsressourcen innerhalb der Methode.
    • Wenn diese Methode überschrieben wird, sodass eine neue Referenzvariable erneut auf das Objekt verweist, wird das Objekt erneut aktiviert.
  • Diese Methode ist in JDK 9 veraltet 标记为过时.
public class FinalizeTest {
    
    
	public static void main(String[] args) {
    
    
		Person p = new Person("Peter", 12);
		System.out.println(p);
		p = null;//此时对象实体就是垃圾对象,等待被回收。但时间不确定。
		System.gc();//强制性释放空间
	}
}

class Person{
    
    
	private String name;
	private int age;

	public Person(String name, int age) {
    
    
		super();
		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;
	}
	//子类重写此方法,可在释放对象前进行某些操作
	@Override
	protected void finalize() throws Throwable {
    
    
		System.out.println("对象被释放--->" + this);
	}
	@Override
	public String toString() {
    
    
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

5、getClass()

public final Class<?> getClass(): Ruft den Laufzeittyp des Objekts ab

Da Java über Polymorphismus verfügt, stimmt der Kompilierzeittyp einer Variablen, die auf einen Datentyp verweist, möglicherweise nicht mit dem Laufzeittyp überein. Wenn Sie also den Typ des Objekts überprüfen müssen, auf das die Variable tatsächlich verweist, müssen Sie ihn verwenden die getClass()-Methode

public static void main(String[] args) {
    
    
	Object obj = new Person();
	System.out.println(obj.getClass());//运行时类型
}

Ergebnis:

class com.atguigu.java.Person

6、hashCode()

public int hashCode(): gibt den Hashwert jedes Objekts zurück. (Die Nachbereitung wird sich auf das Kapitel zum Sammlungsrahmen konzentrieren.)

public static void main(String[] args) {
    
    
	System.out.println("AA".hashCode());//2080
    System.out.println("BB".hashCode());//2112
}

5.6.2 Stichwort: nativ

Verwenden Sie das Schlüsselwort „native“, um anzugeben, dass es sich bei dieser Methode um eine native Funktion handelt. Das heißt, diese Methode ist in einer C/C++Nicht-Java-Sprache implementiert und 被编译成了DLLwird von Java aufgerufen.

  • Native Methoden haben Methodenkörper und sind in der Sprache C geschrieben. Da der Quellcode des Methodenkörpers der lokalen Methode für uns nicht Open Source ist, können wir den Methodenkörper nicht sehen

  • Beim Definieren einer nativen Methode in Java wird kein Implementierungshauptteil bereitgestellt.

1. Warum die native Methode verwenden?

Java ist sehr benutzerfreundlich, aber es ist nicht einfach, einige Aufgaben in Java zu implementieren, oder wenn uns die Effizienz des Programms am Herzen liegt, zum Beispiel: Java muss Informationen mit einigen zugrunde liegenden Betriebssystemen oder Hardware austauschen. Die native Methode ist ein solcher Kommunikationsmechanismus: Sie bietet uns eine sehr übersichtliche Schnittstelle, und wir müssen die umständlichen Details außerhalb der Java-Anwendung nicht verstehen.

2. Die von native deklarierte Methode kann für den Aufrufer genauso wie andere Java-Methoden verwendet werden

Das Vorhandensein nativer Methoden hat keine Auswirkungen auf andere Klassen, die diese nativen Methoden aufrufen. Tatsächlich wissen andere Klassen, die diese Methoden aufrufen, nicht einmal, dass sie eine native Methode aufrufen. Die JVM steuert alle Details des Aufrufs nativer Methoden.

Ich denke du magst

Origin blog.csdn.net/weixin_52357829/article/details/129909882
Empfohlen
Rangfolge