Mehrfache Vererbung bedeutet, dass eine Klasse von mehr als einer erben kann Gleichzeitig erbt eine übergeordnete Klasse Verhaltensweisen und Eigenschaften. Wir wissen jedoch, dass Java nur eine einzelne Vererbung zulässt, um die Datensicherheit zu gewährleisten. Aber manchmal müssen wir eine Mehrfachvererbung erreichen, und solche Situationen gibt es tatsächlich im wirklichen Leben, wie zum Beispiel bei der Vererbung: Wir erben sowohl das Verhalten und die Eigenschaften unseres Vaters als auch die unserer Mutter. Glücklicherweise bietet Java uns zwei Möglichkeiten, Mehrfachvererbung auf umständliche Weise zu implementieren: Schnittstelle und innere Klasse. Tatsächlich ist die Implementierung der Mehrfachvererbung eine äußerst wichtige Anwendung innerer Klassen. Darüber hinaus innere Klassen können auch gut ausgeblendet werden (z. B. innere Klassen privater Mitglieder). Es gibt vier Arten von inneren Klassen, nämlich innere Mitgliedsklassen, statische innere Klassen, lokale innere Klassen und anonyme innere Klassen. Insbesondere
Mitglied der inneren Klasse: Mitglied der inneren Klasse ist Mitglied der äußeren Klasse und an die äußere Klasse angehängt , daher kann das innere Klassenobjekt nur erstellt werden, wenn zuerst das äußere Klassenobjekt erstellt wird. Aus diesem Grund können innere Klassen von statischens Variablen und Methoden
statische innere Klassen nicht enthalten Klasse: Die statische innere Klasse ist eine als statisches modifizierte innere Klasse. Das innere Klassenobjekt hängt nicht vom äußeren Klassenobjekt ab, was bedeutet, dass wir das innere Klassenobjekt direkt erstellen können Auf alle statischen Mitglieder und statischen Methoden externer Klassen kann nur direkt zugegriffen werden.
Lokale innere Klassen: Lokale innere Klassen sind gleich Da die inneren Mitgliedsklassen kompiliert werden, sich ihr -Bereich jedoch geändert hat , kann sie nur in dieser Methode und diesem -Attribut verwendet werden und ist außerhalb dieser Methode und dieses Attributs
Die Voraussetzung für die Definition einer anonymen inneren Klasse ist, dass die innere Klasse eine Klasse erben oder eine Schnittstelle implementieren muss Das Format ist neu übergeordnete Klasse oder Schnittstelle () {definiert den Inhalt der Unterklasse (z. B. Funktion usw.)}. Mit anderen Worten: Was uns die anonyme innere Klasse letztendlich zur Verfügung stellt, ist ein Objekt einer anonymen Unterklasse.
Was intern Klassen beziehen sich auf Es handelt sich um eine innerhalb einer Klasse definierte Klasse. Der Klassenname muss nicht mit dem Namen der Quelldatei identisch sein.
Die innere Klasse ist ein Konzept zur Kompilierungszeit. Nach erfolgreicher Kompilierung werden die innere Klasse und die äußere Klasse zu zwei völlig unterschiedlichen Klassen. Zum Beispiel werden für eine äußere Klasse namens Outer und eine darin definierte innere Klasse namens Inner nach Abschluss der Kompilierung Outer.class und Outer$inner zwei Klassen angezeigt. Daher können die Mitgliedsvariablen-/Methodennamen der inneren Klasse mit denen der äußeren Klasse identisch sein. Innere Klassen können statisch sein oder durch öffentliche, standardmäßige, geschützte und private Klassen geändert werden. Insbesondere in Bezug auf die Beziehung zwischen Java-Quelldateinamen und Klassennamen (die Benennung von Java-Quelldateinamen hat nichts mit internen Klassen zu tun; die in den folgenden drei Regeln beteiligten Klassen und Schnittstellen beziehen sich alle auf extern Klassen/Schnittstellen), müssen die folgenden drei Regeln einhalten:
Wenn in einer Java-Quelldatei eine öffentliche Klasse oder eine öffentliche Schnittstelle vorhanden ist, kann es nur eine öffentliche Klasse oder eine öffentliche Schnittstelle geben und es können nicht mehrere öffentliche Klassen oder Schnittstellen vorhanden sein. Natürlich kann eine Java-Quelldatei mehrere Klassen oder Schnittstellen enthalten, die für das Paket sichtbar sind, d. h. den Standardzugriffsmodifikator (vor dem Klassennamen steht kein Zugriffsmodifikator). Die Reihenfolge der öffentlichen Klassen (Schnittstellen) und der für das Paket sichtbaren Klassen (Schnittstellen) in der Datei kann beliebig sein, d. h. die öffentliche Klasse (Schnittstelle) muss nicht an erster Stelle stehen.
Wenn die Java-Quelldatei keine öffentliche Klasse (öffentliche Schnittstelle) enthält, gibt es keine Begrenzung für den Namen der Java-Quelldatei.
Solange es der Namenskonvention des Dateinamens entspricht, muss es nicht denselben Namen wie eine Klasse oder Schnittstelle in der Datei haben. Natürlich kann es auch denselben Namen haben Nennen Sie einen von ihnen.
Die Benennung von Klassen und Schnittstellen darf nicht in Konflikt geraten.
Jede Klasse oder Schnittstelle im selben Paket kann nicht denselben Namen haben. Klassen oder Schnittstellen in verschiedenen Paketen können den gleichen Namen haben, da sie durch Pakete unterschieden werden können.
2. Die Rolle interner Klassen
Die Verwendung interner Klassen kann uns folgende Vorteile bringen:
Interne Klassen können gut ausgeblendet werden (allgemeine nicht-interne Klassen dürfen keine privaten und geschützten Berechtigungen haben, interne Klassen jedoch schon); 🎜>Die innere Klasse hat Zugriffsrechte auf alle Elemente der äußeren Klasse
kann Mehrfachvererbung implementieren; >
kann das Ändern der Schnittstelle und den Aufruf zweier Methoden mit demselben Namen in derselben Klasse vermeiden.
Normalerweise werden unsere Zugriffsrechte auf Klassen durch den Zugriff vor der Klasse geändert. Im Allgemeinen gilt: Nicht-innere Klassen dürfen keine privaten und geschützten Berechtigungen haben, innere Klassen jedoch schon, sodass wir unsere Informationen durch innere Klassen verbergen können. Sie können das folgende Beispiel sehen:
2) Die innere Klasse hat Zugriffsrechte auf alle Elemente der äußeren Klasse
//测试接口public interface InterfaceTest { public void test(); }//外部类public class Example { //内部类 private class InnerClass implements InterfaceTest{ @Override public void test() { System.out.println("I am Rico."); } } //外部类方法 public InterfaceTest getInnerInstance(){ return new InnerClass(); } }//客户端public class Client { public static void main(String[] args) { Example ex = new Example(); InterfaceTest test = ex.getInnerInstance(); test.test(); } }/* Output: I am Rico. *///:~
Name Diese Mitgliedsvariable ist eine private Variable, die im Beispiel Diese Variable definiert ist Auf innere Klassen kann bedingungslos zugegriffen werden.
//外部类public class Example { private String name = "example"; //内部类 private class Inner{ public Inner(){ System.out.println(name); // 访问外部类的私有属性 } } //外部类方法 public Inner getInnerInstance() { return new Inner(); } }//客户端public class Client { public static void main(String[] args) { Example ex = new Example(); ex.getInnerInstance(); } }/* Output: example *///:~
abstrakte Klassen
erbt die Grenzen von Schnittstellen.4) Vermeiden Sie es, die Schnittstelle zu ändern und zwei Methoden mit demselben Namen in derselben Klasse aufzurufen Stellen Sie sich eine Situation vor, in der eine Klasse eine Klasse erbt und eine Schnittstelle implementiert, aber die Klassen und die von ihm geerbten Schnittstellen haben zwei identische Methoden (Methodensignaturen sind gleich). Wie können wir sie also unterscheiden? Dies erfordert die Verwendung innerer Klassen. Beispiel:
//父类Example1public class Example1 { public String name() { return "rico"; } }//父类Example2public class Example2 { public int age() { return 25; } }//实现多重继承的效果public class MainExample { //内部类Test1继承类Example1 private class Test1 extends Example1 { public String name() { return super.name(); } } //内部类Test2继承类Example2 private class Test2 extends Example2 { public int age() { return super.age(); } } public String name() { return new Test1().name(); } public int age() { return new Test2().age(); } public static void main(String args[]) { MainExample mexam = new MainExample(); System.out.println("姓名:" + mexam.name()); System.out.println("年龄:" + mexam.age()); } }/* Output: 姓名:rico 年龄:25 *///:~
Gehört die test()-Methode in Test zu diesem Zeitpunkt zur test()-Methode, die MyTest abdeckt, oder implementiert sie die test()-Methode in InterfaceTest? Wie können wir die Methode hier in MyTest anpassen? Offensichtlich ist dies schwer zu unterscheiden. Und wenn wir innere Klassen verwenden, kann dieses Problem leicht gelöst werden. Schauen Sie sich den folgenden Code an:
Durch die Verwendung einer inneren Klasse zum Implementieren der Schnittstelle kommt es nicht zu Konflikten mit der gleichnamigen Methode, die von der äußeren Klasse geerbt wird.
3. Arten interner Klassen//Test 所实现的接口public interface InterfaceTest { public void test(); }//Test 所实现的类public class MyTest { public void test(){ System.out.println("MyTest"); } }//不使用内部类的情形public class Test extends MyTest implements InterfaceTest{ public void test(){ System.out.println("Test"); } }
In Java gibt es zwei Situationen bei der Verwendung interner Klassen:
//Test 所实现的接口public interface InterfaceTest { public void test(); }//Test 所实现的类public class MyTest { public void test(){ System.out.println("MyTest"); } }//使用内部类的情形public class AnotherTest extends MyTest { private class InnerTest implements InterfaceTest { @Override public void test() { System.out.println("InterfaceTest"); } } public InterfaceTest getCallbackReference() { return new InnerTest(); } public static void main(String[] args) { AnotherTest aTest = new AnotherTest(); aTest.test(); // 调用类MyTest 的 test() 方法 aTest.getCallbackReference().test(); // 调用InterfaceTest接口中的 test() 方法 } }
(2) Definieren Sie eine Klasse (lokale innere Klasse, anonyme innere Klasse) in der Methode.
2. Innere Klasse der Mitglieder
1. Definition und Prinzip
Die innere Mitgliedsklasse ist an die äußere Klasse angehängt, sodass das innere Klassenobjekt nur erstellt werden kann, wenn zuerst das äußere Klassenobjekt erstellt wird. Aus diesem Grund können innere Mitgliedsklassen keine statischen Variablen und Methoden enthalten
, siehe folgendes Beispiel: 如果上面的代码编译无误, 那么我们就可以直接通过 Outter.Inner.a 拿到内部类Inner的实例。 由于内部类的实例一定要绑定到一个外部类的实例的,所以矛盾。因此,成员内部类不能含有 static 变量/方法。此外,成员内部类与 static 的关系还包括: 2、交互 成员内部类与外部类的交互关系为: 成员内部类可以直接访问外部类的所有成员和方法,即使是 private 的; 外部类需要通过内部类的对象访问内部类的所有成员变量/方法。 对于代码片段 1和2,可以用来生成内部类的对象,这种方法存在两个小知识点需要注意: 1) 开头的 Out 是为了标明需要生成的内部类对象在哪个外部类当中; 因此,成员内部类,外部类和客户端之间的交互关系为: 在成员内部类使用外部类对象时,使用 outer.this 来表示外部类对象; 在外部类中使用内部类对象时,需要先进行创建内部类对象; 在客户端创建内部类对象时,需要先创建外部类对象。 特别地,对于成员内部类对象的获取,外部类一般应提供相应的 getxxx() 方法。 3、私有成员内部类 如果一个成员内部类只希望被外部类操作,那么可以使用 private 将其声明私有内部类。例如, 在上面的代码中,我们必须在Out类里面生成In类的对象进行操作,而无法再使用Out.In in = new Out().new In() 生成内部类的对象。也就是说,此时的内部类只对外部类是可见的,其他类根本不知道该内部类的存在。 1、定义与原理 静态内部类,就是修饰为 static 的内部类,该内部类对象不依赖于外部类对象,就是说我们可以直接创建内部类对象。看下面例子: 2、交互 静态内部类与外部类的交互关系为: 静态内部类可以直接访问外部类的所有静态成员和静态方法,即使是 private 的; 外部类可以通过内部类对象访问内部类的实例成员变量/方法;对于内部类的静态域/方法,外部类可以通过内部类类名访问。 3、成员内部类和静态内部类的区别 成员内部类和静态内部类之间的不同点包括: 静态内部类对象的创建不依赖外部类的实例,但成员内部类对象的创建需要依赖外部类的实例; 成员内部类能够访问外部类的静态和非静态成员,静态内部类不能访问外部类的非静态成员; 1、定义与原理 有这样一种内部类,它是嵌套在方法和作用域内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,但又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。 2、final 参数 对于final参数,若是将引用类型参数声明为final,我们无法在方法中更改参数引用所指向的对象;若是将基本类型参数声明为final,我们可以读参数,但却无法修改参数(这一特性主要用来向局部内部类和匿名内部类传递数据)。 如果定义一个局部内部类,并且希望它的方法可以直接使用外部定义的数据,那么我们必须将这些数据设为是 final 的;特别地,如果只是局部内部类的构造器需要使用外部参数,那么这些外部参数就没必要设置为 final,例如: 有时候我为了免去给内部类命名,便倾向于使用匿名内部类,因为它没有名字。匿名内部类的使用需要注意以下几个地方: 匿名内部类是没有访问修饰符的; 匿名内部类是没有构造方法的 (因为匿名内部类连名字都没有); 定义匿名内部类的前提是,内部类必须是继承一个类或者实现接口,格式为 new 父类或者接口(){子类的内容(如函数等)}。也就是说,匿名内部类最终提供给我们的是一个匿名子类的对象,例如: 若匿名内部类 (匿名内部类没有构造方法) 需要直接使用其所在的外部类方法的参数时,该形参必须为 final 的;如果匿名内部类没有直接使用其所在的外部类方法的参数时,那么该参数就不必为final 的,例如: 从上述代码中可以看到,当匿名内部类直接使用其所在的外部类方法的参数时,那么这些参数必须被设为 final的。为什么呢?本文所引用到的一篇文章是这样解释的: “这是一个编译器设计的问题,如果你了解java的编译原理的话很容易理解。首先,内部类被编译的时候会生成一个单独的内部类的.class文件,这个文件并不与外部类在同一class文件中。当外部类传的参数被内部类调用时,从java程序的角度来看是直接的调用,例如: 从代码来看,好像是内部类直接调用的a参数和b参数,但是实际上不是,在java编译器编译以后实际的操作代码是: 从以上代码来看,内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。这样就很容易理解为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。” 以上关于匿名内部类的每个例子使用的都是默认无参构造函数,下面我们介绍 带参数构造函数的匿名内部类: 特别地,匿名内部类通过实例初始化 (实例语句块主要用于匿名内部类中),可以达到类似构造器的效果,如下: 内部类的继承,是指内部类被继承,普通类 extents 内部类。而这时候代码上要有点特别处理,具体看以下例子: 可以看到,子类的构造函数里面要使用父类的外部类对象.super() [成员内部类对象的创建依赖于外部类对象];而这个外部类对象需要从外面创建并传给形参。 Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in interne Java-Klassen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!public class Outter {
private class Inner {
private final static int x=1; // OK
/* compile errors for below declaration
* "The field x cannot be declared static in a non-static inner type,
* unless initialized with a constant expression" */
final static Inner a = new Inner(); // Error
static Inner a1=new Inner(); // Error
static int y; // Error
}
}
//外部类class Out { private int age = 12; private String name = "rico";
//内部类
class In { private String name = "livia";
public void print() {
String name = "tom";
System.out.println(age);
System.out.println(Out.this.name);
System.out.println(this.name);
System.out.println(name);
}
} // 推荐使用getxxx()来获取成员内部类的对象
public In getInnerClass(){ return new In();
}
}public class Demo {
public static void main(String[] args) {
Out.In in = new Out().new In(); // 片段 1
in.print(); //或者采用注释内两种方式访问
/*
* 片段 2
Out out = new Out();
out.getInnerClass().print(); // 推荐使用外部类getxxx()获取成员内部类对象
Out.In in = out.new In();
in.print();
*/
}
}/* Output:
12
rico
livia
tom
*///:~
2) 必须先有外部类的对象才能生成内部类的对象。class Out { private int age = 12; private class In {
public void print() {
System.out.println(age);
}
} public void outPrint() { new In().print();
}
}public class Demo {
public static void main(String[] args) { /*
* 此方法无效
Out.In in = new Out().new In();
in.print();
*/
Out out = new Out();
out.outPrint();
}
}/* Output:
12
*///:~
三. 静态内部类
四. 局部内部类
// 例 1:定义于方法内部public class Parcel4 {
public Destination destination(String s) {
class PDestination implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel4 p = new Parcel4();
Destination d = p.destination("Tasmania");
}
}
// 例 2:定义于作用域内部public class Parcel5 {
private void internalTracking(boolean b) {
if (b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() {
return id;
}
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
}
public void track() {
internalTracking(true);
}
public static void main(String[] args) {
Parcel5 p = new Parcel5();
p.track();
}
}
五. 匿名内部类
// 例 1abstract class AbsDemo
{ abstract void show();
}public class Outer{
int x=3; public void function()//可调用函数
{ new AbsDwmo()//匿名内部类
{ void show()
{
System.out.println("x==="+x);
} void abc()
{
System.out.println("haha");
}
}.abc(); //匿名内部类调用函数,匿名内部类方法只能调用一次
}
}
// 例 2interface Inner { //注释后,编译时提示类Inner找不到
String getName();
}public class Outer {
public Inner getInner(final String name, String city) {
return new Inner() {
private String nameStr = name;
public String getName() {
return nameStr;
}
};
}
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "gz");
System.out.println(inner.getName());
System.out.println(inner instanceof Inner); //匿名内部类实质上是一个匿名子类的对象
} /* Output:
Inner
true
*///:~ }
// 情形 1:匿名内部类直接使用其所在的外部类方法的参数 namepublic class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "gz");
System.out.println(inner.getName());
}
public Inner getInner(final String name, String city) { // 形参 name 被设为 final
return new Inner() {
private String nameStr = name; // OK
private String cityStr = city; // Error: 形参 city 未被设为 final
public String getName() {
return nameStr;
}
};
}
}
// 情形 2:匿名内部类没有直接使用其所在的外部类方法的参数public class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "gz");
System.out.println(inner.getName());
}
//注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final
public Inner getInner(String name, String city) {
return new Inner(name, city) { // OK,形参 name 和 city 没有被匿名内部类直接使用
private String nameStr = name;
public String getName() {
return nameStr;
}
};
}
}
abstract class Inner {
Inner(String name, String city) {
System.out.println(city);
}
abstract String getName();
}
public void dosome(final String a,final int b){
class Dosome{ public void dosome(){
System.out.println(a+b)
}
};
Dosome some=new Dosome();
some.dosome();
}
class Outer$Dosome{
public Dosome(final String a,final int b){
this.Dosome$a=a;
this.Dosome$b=b;
}
public void dosome(){
System.out.println(this.Dosome$a+this.Dosome$b);
}
}
public class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "gz");
System.out.println(inner.getName());
}
public Inner getInner(final String name, String city) {
return new Inner(name, city) { //匿名内部类
private String nameStr = name;
public String getName() {
return nameStr;
}
};
}
}
abstract class Inner {
Inner(String name, String city) { // 带有参数的构造函数
System.out.println(city);
}
abstract String getName();
}
public class Outer {
public static void main(String[] args) {
Outer outer = new Outer();
Inner inner = outer.getInner("Inner", "gz");
System.out.println(inner.getName());
System.out.println(inner.getProvince());
}
public Inner getInner(final String name, final String city) {
return new Inner() {
private String nameStr = name;
private String province;
// 实例初始化
{
if (city.equals("gz")) {
province = "gd";
}else {
province = "";
}
}
public String getName() {
return nameStr;
}
public String getProvince() {
return province;
}
};
}
}
六. 内部类的继承