Was ist eine abstrakte Klasse?
„Eine Klasse, die eine oder mehrere abstrakte Methoden enthält, ist eine abstrakte Klasse, und eine abstrakte Methode ist eine Methode ohne Methodenkörper.“ Sowohl abstrakte Methoden als auch abstrakte Klassen müssen als abstrakt
deklariert werden. Zum Beispiel: <code>// 抽象类<br>public abstract class Person {<br> // 抽象方法<br> public abstract String getDescription();<br>}</code>
abstract
。例如:
<code>public abstract class Person{<br> private String name;<br> public Person(String name){<br> this.name = name ;<br> }<br> public abstract String getDescription();<br> public String getName(){<br> return name;<br> }<br>}</code>
切记!「除了抽象方法之外,抽象类还可以包含具体数据和具体方法」。例如, 抽象类 Person
还保存着姓名和一个返回姓名的具体方法:
<code>new Person("Jack"); // Error</code>
❝许多程序员都会「错误」的认为,在抽象类中不能包含具体方法。其实这也是接口和抽象类的不同之处,接口中是不能包含具体方法的。
❞
「抽象类不能被实例化」。也就是说,如果将一个类声明为 abstract
, 就不能创建这个类的对象。
<code>Person p = new Student("Jack"); // Right</code>
可以定义一个抽象类的对象变量, 但是它只能引用非抽象子类的对象。假设 Student
类是 Person
的非抽象子类:
<code>public class Student extends Person { <br> private String major; <br> public Student(String name, String major) { <br> super(name); <br> this.major = major; <br> } <br> @Override<br> public String getDescription(){ // 实现父类抽象方法<br> return "a student majoring in " + major; <br> } <br>} </code>
所谓非抽象子类就是说,如果创建一个继承抽象类的子类并为之创建对象,那么就「必须为父类的所有抽象方法提供方法定义」。如果不这么做(可以选择不做),子类仍然是一个抽象类,编译器会强制我们为新类加上 abstract
关键字。
下面定义扩展抽象类 Person
的具体子类 Student
:
<code>Person p = new Student("Jack","Computer Science");<br>p.getDescription();<br></code>
在 Student
类中实现了父类中的抽象方法 getDescription
。因此,「在 Student
类中的全部方法都是非抽象的, 这个类不再是抽象类」。
???? 调用如下:
<code>public interface Concept {<br> void idea1();<br> void idea2();<br>}</code>
由于不能构造抽象类 Person
的对象, 所以变量 p
永远不会引用 Person
对象, 而是引用诸如 Student
这样的具体子类对象, 而这些对象中都重写了 getDescription
方法。
接口的本质其实也是一个类,而且是一个比抽象类还要抽象的类。怎么说呢?抽象类是能够包含具体方法的,而接口杜绝了这个可能性,「在 Java 8 之前,接口非常纯粹,只能包含抽象方法,也就是没有方法体的方法」。而 Java 8 中接口出现了些许的变化,开始允许接口包含默认方法和静态方法,这个下文会讲解。
Java 使用关键字 interface
而不是 class
来创建接口。和类一样,通常我们会在关键字 interface
前加上 public
关键字,否则接口只有包访问权限,只能在接口相同的包下才能使用它。
<code>class Implementation implements Concept {<br> @Override<br> public void idea1() {<br> System.out.println("idea1");<br> }<br> <br> @Override<br> public void idea2() {<br> System.out.println("idea2");<br> }<br>}<br></code>
同样的,接口中既然存在抽象方法,那么他就需要被扩展(继承)。使用 implements
关键字使一个类扩展某个特定接口(或一组接口),通俗来说:接口只是外形,现在这个扩展子类要说明它是如何工作的。
<code>public interface Concept {<br> void idea1(); // public void idea1();<br> // 静态属性<br> double item = 95; // a public static final constant<br>}</code>
这里需要注意的是,你可以选择显式地声明接口中的方法为 public
,但是「即使你不这么做,它们也是 public
的」。所以当实现一个接口时,来自接口中的方法必须被定义为 public
。否则,它们只有包访问权限,这样在被继承时,它们的可访问权限就被降低了,这是 Java 编译器所不允许的。
另外,接口中是允许出现常量的,与接口中的方法都自动地被设置为 public
—样,「接口中的域将被自动被设置为 public static final
类型」,例如:
<code>x = new Concept(. . .); // ERROR</code>
❝可以将接口方法标记为
❞public
,将域标记为public static final
。有些程序员出于习惯或提高清晰度的考虑, 愿意这样做。但 Java 语言规范却「建议不要书写这些多余的关键字」。
接口和类其中不同的一点就是,我们「无法像类一样使用 new
"Abstrakte Klassen können neben abstrakten Methoden auch konkrete Daten und konkrete Methoden enthalten". Beispielsweise speichert die abstrakte Klasse Person
auch den Namen und eine konkrete Methode, die den Namen zurückgibt:
<code>Concept x; // OK</code>
❝🎜🎜"Abstrakte Klassen können nicht instanziiert werden"🎜. Mit anderen Worten: Wenn eine Klasse alsViele Programmierer werden
„irrtümlicherweise“glauben, dass Konkret nicht in eine einbezogen werden kann abstrakte Klassenmethode. Tatsächlich ist dies auch der Unterschied zwischen Schnittstellen und abstrakten Klassen. Schnittstellen können keine spezifischen Methoden enthalten.
❞
abstract
deklariert ist, können keine Objekte dieser Klasse erstellt werden. 🎜<code>x = new Implementation(. . .); // OK provided Implementation implements Concept</code>
Student
eine nicht-abstrakte Unterklasse von Person
ist: 🎜<code>if(x instanceof Concept){<br> ...<br>}</code>
abstract
zur neuen Klasse hinzuzufügen. 🎜🎜Im Folgenden wird die spezifische Unterklasse Student
der erweiterten abstrakten Klasse Person
definiert: 🎜<code>public interface Concept1 {<br> void idea1();<br> void idea2();<br>}<br><br>-------------------------------------------<br> <br>public interface Concept2 extends Concept1{<br> double idea3();<br>}</code>
Student
Klasse getDescription
. Daher 🎜 „Alle Methoden in der Klasse Student
sind nicht abstrakt, und diese Klasse ist keine abstrakte Klasse mehr“ 🎜. 🎜🎜???? Der Aufruf lautet wie folgt: 🎜<code>class Implementation implements Concept1, Concept2 // OK</code>
Person
nicht konstruiert werden kann, wird die Variable p
niemals auf Person
-Objekt, bezieht sich jedoch auf bestimmte Unterklassenobjekte wie Student
, und die Methode getDescription
wird in diesen Objekten überschrieben. 🎜interface
anstelle von class
, um Schnittstellen zu erstellen. Wie bei Klassen fügen wir normalerweise das Schlüsselwort public
vor dem Schlüsselwort interface
hinzu. Andernfalls verfügt die Schnittstelle nur über Paketzugriffsrechte und kann nur unter dem Paket mit derselben Schnittstelle verwendet werden. . 🎜<code>public interface Concept {<br> // 静态方法<br> public static void get(String name){<br> System.out.println("hello " + name);<br> }<br> // 默认方法<br> default void idea1(){<br> System.out.println("this is idea1");<br> };<br>}</code>
implements
, um eine bestimmte Schnittstelle (oder eine Gruppe von Schnittstellen) zu erweitern: Die Schnittstelle ist nur das Erscheinungsbild. Nun muss diese erweiterte Unterklasse erklärt werden. 🎜<code>interface A {<br> default void idea(){<br> System.out.println("this is A");<br> }<br>}<br><br>interface B {<br> default void idea(){<br> System.out.println("this is B");<br> }<br>}<br><br>// 需要在 D 类中覆盖 idea 方法<br>class D implements A, B{<br> public void getName(){<br> System.out.println("this is D");<br> }<br>}</code>
public
deklarieren können, aber 🎜„Selbst wenn Sie dies nicht tun, sind sie immer noch public<.> "🎜. Bei der Implementierung einer Schnittstelle müssen daher Methoden der Schnittstelle als <code>public
definiert werden. Andernfalls haben sie nur Zugriff auf das Paket. Wenn sie vererbt werden, ist ihre Zugänglichkeit eingeschränkt, was der Java-Compiler nicht zulässt. 🎜🎜Darüber hinaus sind Konstanten in der Schnittstelle zulässig. Genauso wie die Methoden in der Schnittstelle automatisch auf public
gesetzt werden, 🎜„Die Felder in der Schnittstelle werden automatisch auf public static final gesetzt
Typ"🎜, zum Beispiel: 🎜<code>interface B {<br> void idea();<br>}</code>
❝ 🎜Sie können die Schnittstellenmethode alspublic
und das Feld alspublic static final
markieren. Einige Programmierer sind bereit, dies aus Gewohnheit oder zur Verbesserung der Übersichtlichkeit zu tun, aber die Java-Sprachspezifikation „empfiehlt, diese redundanten Schlüsselwörter nicht zu schreiben“. 🎜❞
new
-Operator nicht wie eine Klasse verwenden können eine Schnittstelle“🎜:🎜rrreee🎜Der Grund ist auch sehr einfach. Die Schnittstelle hat nicht einmal eine bestimmte Konstruktionsmethode, daher darf sie nicht instanziiert werden. 🎜🎜Obwohl Schnittstellenobjekte nicht erstellt werden können, ist es natürlich dennoch möglich, Schnittstellenvariablen zu deklarieren: 🎜<code>Concept x; // OK</code>
接口变量必须引用实现了接口的类对象:
<code>x = new Implementation(. . .); // OK provided Implementation implements Concept</code>
接下来, 如同使用 instanceof
检查一个对象是否属于某个特定类一样, 也可以使用 instanceof
检查一个对象是否实现了某个特定的接口:
<code>if(x instanceof Concept){<br> ...<br>}</code>
另外,与可以建立类的继承关系一样,「接口也可以被继承」:
<code>public interface Concept1 {<br> void idea1();<br> void idea2();<br>}<br><br>-------------------------------------------<br> <br>public interface Concept2 extends Concept1{<br> double idea3();<br>}</code>
当然,读到这里大家可能依然无法理解,既然有了抽象类,为什么 Java 程序设计语言还要不辞辛苦地引入接口这个概念?
很重磅!因为「一个类可以实现多个接口,但是一个类只能继承一个父类」。正是接口的出现打破了 Java 这种单继承的局限,为定义类的行为提供了极大的灵活性。
<code>class Implementation implements Concept1, Concept2 // OK</code>
有一条实际经验:在合理的范围内尽可能地抽象。显然,接口比抽象类还要抽象。因此,一般更倾向使用接口而不是抽象类。
上文提过一嘴,「在 Java 8 中,允许在接口中增加静态方法和默认方法」。理论上讲,没有任何理由认为这是不合法的,只是这有违于将接口作为抽象规范的初衷。举个例子:
<code>public interface Concept {<br> // 静态方法<br> public static void get(String name){<br> System.out.println("hello " + name);<br> }<br> // 默认方法<br> default void idea1(){<br> System.out.println("this is idea1");<br> };<br>}</code>
用 default
修饰符标记的方法就是默认方法,这样子类就不需要去实现这个方法了。
不过,引入默认方法后,就出现了一个「默认方法冲突」的问题。如果先在一个接口 A 中将一个方法 idea
定义为默认方法, 然后又在另一个接口 B 或者超类 C 中定义了同样的方法 idea
,然后类 D 实现了这两个接口 A 和 B(或超类 C)。于是类 D 中就有了方法 idea
的两个默认实现,出现了冲突,为此,Java 制定了一套规则来解决这个二义性问题:
1 ) 「超类优先」。如果超类提供了一个具体方法,接口中的同名且有相同参数类型的默认方法会被忽略。
2 ) 「接口冲突」。如果一个父类接口提供了一个默认方法,另一个父类接口也提供了一个同名而且参数类型相同的方法,子类必须覆盖这个方法来解决冲突。例如:
<code>interface A {<br> default void idea(){<br> System.out.println("this is A");<br> }<br>}<br><br>interface B {<br> default void idea(){<br> System.out.println("this is B");<br> }<br>}<br><br>// 需要在 D 类中覆盖 idea 方法<br>class D implements A, B{<br> public void getName(){<br> System.out.println("this is D");<br> }<br>}</code>
现在假设 B
接口没有为 idea
提供默认实现:
<code>interface B {<br> void idea();<br>}</code>
那么 D 类会直接从 A 接口继承默认方法吗?这好像挺有道理, 不过,Java 设计者更强调一致性。两个接口如何冲突并不重要,「只要有一个接口提供了一个默认实现,编译器就会报告错误, 我们就必须解决这个二义性」。
当然,如果两个接口都没有为共享方法提供默认实现, 那么就与 Java 8 之前的情况一样,这里不存在冲突。
在我自己早期学习编程的时候,对接口存在的意义实在困惑,我自己乱写代码的时候基本上不可能意识到需要去写接口,不知道接口到底有什么用,为什么要定义接口,感觉定义接口只是提前做了个多余的工作。
其实不是,定义接口并非多余,「接口是用来提供公用的方法,规定子类的行为的」。举个例子,让大家直观的感受下接口的作用:
比如有个网站, 需要保存不同客户的信息, 有些客户从 Web 网站来, 有些客户从手机客户端来, 有些客户直接从后台管理系统录入。假设不同来源的客户有不同的处理业务流程, 这个时候我们定义接口来提供一个保存客户信息的方法,然后不同的平台实现我们这个保存客户信息的接口,以后保存客户信息的话, 我们只需要知道这个接口就可以了,具体调用的方法被封装成了黑盒子,这也就是 Java 的多态的体现,「接口帮助我们对这些有相同功能的方法做了统一管理」。
Das obige ist der detaillierte Inhalt vonWelche Rolle spielen Schnittstellen in Java?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!