Für objektorientierte Programmiersprachen sind Klassen zweifellos die wichtigste Grundlage. Die vier Hauptmerkmale Abstraktion, Kapselung, Vererbung und Polymorphismus sind untrennbar mit Klassen verbunden. Nur die Existenz von Klassen kann die Merkmale der objektorientierten Programmierung widerspiegeln. Lassen Sie uns zunächst über Dinge im Zusammenhang mit der Initialisierung von Klassen sprechen und anschließend die großartige Funktion der Vererbung aus verschiedenen Aspekten erläutern. Das Folgende ist die Inhaltsübersicht dieses Artikels:
1. Verstehen Sie den Unterricht?
2. Verstehst du Vererbung?
3. Häufige schriftliche Fragen im Vorstellungsgespräch
1. Verstehen Sie Kategorien?
In Java ist eine Klassendatei eine Codedatei mit dem Suffix .java. In jeder Klassendatei darf nur eine öffentliche Klasse vorkommen das Gleiche wie public. Die Namen der Klassen sind gleich. Wenn es keine öffentliche gibt, kann der Name der Klassendatei ein beliebiger Name sein (Namen, die mit Zahlen beginnen, sind natürlich nicht zulässig).
Innerhalb der Klasse stellt Java für Mitgliedsvariablen sicher, dass jede Mitgliedsvariable der Klasse ordnungsgemäß initialisiert wird, wenn beim Definieren keine explizite Zuweisungsinitialisierung erfolgt:
1) Für Basisvariablen Datentypen wie char, short, byte, int, long, float, double usw. werden standardmäßig auf 0 initialisiert (boolesche Variablen werden standardmäßig auf false initialisiert
2) Für Referenztypenvariablen werden standardmäßig auf Null initialisiert.
Wenn der Konstruktor nicht explizit definiert ist, erstellt der Compiler automatisch einen Konstruktor ohne Argumente. Beachten Sie jedoch, dass der Compiler den Konstruktor nicht automatisch hinzufügt, wenn der Konstruktor explizit definiert ist. Beachten Sie, dass alle Konstruktoren standardmäßig statisch sind.
Als nächstes konzentrieren wir uns auf die Initialisierungssequenz:
Wenn das Programm ausgeführt wird, muss ein Objekt einer bestimmten Klasse generiert werden. Die Java-Ausführungs-Engine prüft zunächst, ob diese Klasse geladen ist. Wenn es nicht geladen ist, wird zuerst die Klasse geladen und dann das Objekt generiert. Wenn es geladen wurde, wird das Objekt direkt generiert.
Während des Ladevorgangs der Klasse werden die statischen Mitgliedsvariablen der Klasse initialisiert. Wenn in der Klasse ein statischer Anweisungsblock vorhanden ist, wird außerdem der statische Anweisungsblock ausgeführt. Die Ausführungsreihenfolge statischer Mitgliedsvariablen und statischer Anweisungsblöcke stimmt mit der Reihenfolge im Code überein. Denken Sie daran, dass in Java Klassen bei Bedarf geladen werden. Diese Klasse wird nur dann geladen, wenn sie benötigt wird, und zwar nur einmal. Schauen Sie sich zum Verständnis das folgende Beispiel an:
public class Test { public static void main(String[] args) throws ClassNotFoundException { Bread bread1 = new Bread(); Bread bread2 = new Bread(); } } class Bread { static{ System.out.println("Bread is loaded"); } public Bread() { System.out.println("bread"); } }
Wenn Sie diesen Code ausführen, werden Sie feststellen, dass „Brot ist geladen“ nur einmal gedruckt wird.
Während des Generierungsprozesses eines Objekts werden zuerst die Mitgliedsvariablen des Objekts initialisiert und dann der Konstruktor ausgeführt. Dies bedeutet, dass die Variablen in der Klasse initialisiert werden, bevor eine Methode (einschließlich des Konstruktors) aufgerufen wird, selbst wenn die Variablen zwischen Methodendefinitionen verstreut sind.
public class Test { public static void main(String[] args) { new Meal(); } } class Meal { public Meal() { System.out.println("meal"); } Bread bread = new Bread(); } class Bread { public Bread() { System.out.println("bread"); } }
Das Ausgabeergebnis ist:
Brot
Mahlzeit
2. Verstehen Sie Vererbung?
Vererbung ist ein unverzichtbarer Bestandteil aller OOP-Sprachen. Das Schlüsselwort „extens“ wird in Java verwendet, um die Vererbungsbeziehung auszudrücken. Beim Erstellen einer Klasse wird diese immer geerbt. Wenn die zu erbende Klasse nicht explizit angegeben wird, wird sie immer implizit von der Stammklasse Object geerbt. Zum Beispiel der folgende Code:
class Person { public Person() { } } class Man extends Person { public Man() { } }
Die Klasse Man erbt von der Klasse Person. In diesem Fall wird die Klasse Person als übergeordnete Klasse (Basisklasse) und die Klasse Man als Unterklasse bezeichnet (abgeleitete Klasse). Wenn zwischen zwei Klassen eine Vererbungsbeziehung besteht, erbt die Unterklasse automatisch die Methoden und Variablen der übergeordneten Klasse, und die Methoden und Variablen der übergeordneten Klasse können in der Unterklasse aufgerufen werden. In Java ist nur Einzelvererbung zulässig, was bedeutet, dass eine Klasse nur von höchstens einer übergeordneten Klasse explizit erben kann. Eine Klasse kann jedoch von mehreren Klassen geerbt werden, was bedeutet, dass eine Klasse mehrere Unterklassen haben kann.
1. Die Unterklasse erbt die Mitgliedsvariablen der übergeordneten Klasse
Wenn die Unterklasse eine bestimmte Klasse erbt, kann sie die Mitgliedsvariablen in der übergeordneten Klasse verwenden, erbt diese jedoch nicht vollständig übergeordnete Klasse. Alle Mitgliedsvariablen. Die spezifischen Prinzipien lauten wie folgt:
1) Sie können die öffentlichen und geschützten Mitgliedsvariablen der Elternklasse erben; Sie können die privaten Mitgliedsvariablen der Elternklasse nicht erben; Die Paketzugriffsrechte der Mitglieder der übergeordneten Klasse sind Variablen. Wenn sich die Unterklasse und die übergeordnete Klasse im selben Paket befinden, kann die Unterklasse nicht erben.
3) Für die übergeordneten Klassenvariablen dass die Unterklasse erben kann, wenn sie sich in der untergeordneten Klasse befindet. Wenn eine Mitgliedsvariable mit demselben Namen in der Klasse erscheint, wird sie ausgeblendet, d. h. die Mitgliedsvariable der Unterklasse blockiert die Mitgliedsvariable der übergeordneten Klasse mit demselben Namen Name. Wenn Sie in einer Unterklasse auf eine gleichnamige Mitgliedsvariable in der übergeordneten Klasse zugreifen möchten, müssen Sie das Schlüsselwort super als Referenz verwenden.
2. Unterklassen erben die Methoden der übergeordneten Klasse
Ebenso erben Unterklassen nicht vollständig alle Methoden der übergeordneten Klasse.
1) Kann die öffentlichen und geschützten Mitgliedsmethoden der übergeordneten Klasse erben;
2) Für die Paketzugriffs-Mitgliedsmethoden der übergeordneten Klasse , wenn die Unterklasse im selben Paket wie die übergeordnete Klasse ist, kann die Unterklasse erben; andernfalls kann die Unterklasse nicht erben;
3)对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。
注意:隐藏和覆盖是不同的。隐藏是针对成员变量和静态方法的,而覆盖是针对普通方法的。(后面会讲到)
3.构造器
子类是不能够继承父类的构造器,但是要注意的是,如果父类的构造器都是带有参数的,则必须在子类的构造器中显示地通过super关键字调用父类的构造器并配以适当的参数列表。如果父类有无参构造器,则在子类的构造器中用super关键字调用父类构造器不是必须的,如果没有使用super关键字,系统会自动调用父类的无参构造器。看下面这个例子就清楚了:
class Shape { protected String name; public Shape(){ name = "shape"; } public Shape(String name) { this.name = name; } } class Circle extends Shape { private double radius; public Circle() { radius = 0; } public Circle(double radius) { this.radius = radius; } public Circle(double radius,String name) { this.radius = radius; this.name = name; } }
这样的代码是没有问题的,如果把父类的无参构造器去掉,则下面的代码必然会出错:
改成下面这样就行了:
4.super
super主要有两种用法:
1)super.成员变量/super.成员方法;
2)super(parameter1,parameter2....)
第一种用法主要用来在子类中调用父类的同名成员变量或者方法;第二种主要用在子类的构造器中显示地调用父类的构造器,要注意的是,如果是用在子类构造器中,则必须是子类构造器的第一个语句。
三.常见的面试笔试题
1.下面这段代码的输出结果是什么?
public class Test { public static void main(String[] args) { new Circle(); } } class Draw { public Draw(String type) { System.out.println(type+" draw constructor"); } } class Shape { private Draw draw = new Draw("shape"); public Shape(){ System.out.println("shape constructor"); } } class Circle extends Shape { private Draw draw = new Draw("circle"); public Circle() { System.out.println("circle constructor"); } }
shape draw constructor
shape constructor
circle draw constructor
circle constructor
这道题目主要考察的是类继承时构造器的调用顺序和初始化顺序。要记住一点:父类的构造器调用以及初始化过程一定在子类的前面。由于Circle类的父类是Shape类,所以Shape类先进行初始化,然后再执行Shape类的构造器。接着才是对子类Circle进行初始化,最后执行Circle的构造器。
2.下面这段代码的输出结果是什么?
public class Test { public static void main(String[] args) { Shape shape = new Circle(); System.out.println(shape.name); shape.printType(); shape.printName(); } } class Shape { public String name = "shape"; public Shape(){ System.out.println("shape constructor"); } public void printType() { System.out.println("this is shape"); } public static void printName() { System.out.println("shape"); } } class Circle extends Shape { public String name = "circle"; public Circle() { System.out.println("circle constructor"); } public void printType() { System.out.println("this is circle"); } public static void printName() { System.out.println("circle"); } }
shape constructor
circle constructor
shapethis is circle
shape
这道题主要考察了隐藏和覆盖的区别(当然也和多态相关,在后续博文中会继续讲到)。
覆盖只针对非静态方法(终态方法不能被继承,所以就存在覆盖一说了),而隐藏是针对成员变量和静态方法的。这2者之间的区别是:覆盖受RTTI(Runtime type identification)约束的,而隐藏却不受该约束。也就是说只有覆盖方法才会进行动态绑定,而隐藏是不会发生动态绑定的。在Java中,除了static方法和final方法,其他所有的方法都是动态绑定。因此,就会出现上面的输出结果。
更多Java: Klassen und Vererbung相关文章请关注PHP中文网!