요약:
다중 상속은 클래스가 둘 이상의 클래스에서 상속받을 수 있음을 의미합니다. 동시에 상위 클래스는 동작과 특성을 상속합니다. 그러나 Java는 데이터 보안을 보장하기 위해 단일 상속만 허용한다는 것을 알고 있습니다. 그러나 때때로 우리는 다중 상속을 달성해야 하며, 그러한 상황은 실제로 상속과 같은 현실 생활에 존재합니다. 우리는 아버지와 어머니의 행동과 특성을 모두 물려받습니다. 다행히 Java는 다중 상속을 구불구불한 방식으로 구현할 수 있는 두 가지 방법, 즉 인터페이스와 내부 클래스를 제공합니다. 사실 다중 상속을 구현하는 것은 내부 클래스의 매우 중요한 응용입니다. 또한 내부 클래스도 잘 숨길 수 있습니다(예: 개인 멤버 내부 클래스). 내부 클래스에는 멤버 내부 클래스, 정적 내부 클래스, 로컬 내부 클래스, 익명 내부 클래스의 네 가지 유형이 있습니다. 특히
멤버 내부 클래스: 멤버 내부 클래스는 외부 클래스의 멤버이며 외부 클래스에 연결됩니다 이므로 외부 클래스 객체 가 먼저 생성되어야 내부 클래스 객체를 생성할 수 있습니다. 이러한 이유로 멤버 내부 클래스는 static의 변수 및 메서드를 포함할 수 없습니다. class:
정적 내부 클래스는 정적으로 수정된 내부 클래스입니다. 내부 클래스 객체로컬 내부 클래스:
로컬 내부 클래스는 동일합니다. 멤버 내부 클래스가 컴파일되었지만 해당new 상위 클래스 또는 인터페이스() {하위 클래스의 콘텐츠 정의(예: 함수 등)}입니다. 즉, 익명 내부 클래스가 궁극적으로 우리에게 제공하는 것은 익명 하위 클래스의 객체입니다. 1. 내부 클래스 개요1. 내부 클래스 기본
내부 클래스는 컴파일 타임 개념입니다. 성공적으로 컴파일되면 내부 클래스와 외부 클래스는 완전히 다른 두 클래스가 됩니다. 예를 들어 Outer라는 외부 클래스와 그 안에 정의된 Inner라는 내부 클래스의 경우 컴파일이 완료되면 Outer.class 및 Outer$inner 클래스 두 개가 나타납니다. 따라서 내부 클래스의 멤버 변수/메서드 이름은 외부 클래스의 이름과 동일할 수 있습니다. 내부 클래스는 정적이거나 공개, 기본값, 보호 및 비공개로 수정될 수 있습니다. 특히 Java 소스 파일 이름과 클래스 이름의 관계(Java 소스 파일 이름의 명명은 내부 클래스와 관련이 없으며 다음 세 가지 규칙에 관련된 클래스 및 인터페이스는 모두 외부 클래스를 참조합니다. 클래스/인터페이스), 다음 세 가지 규칙을 준수해야 합니다. Java 소스 파일에 공용 클래스(공용 인터페이스)가 포함된 경우 ), 소스 파일 이름은 퍼블릭 클래스 이름(퍼블릭 인터페이스 이름)과 동일해야 합니다.
Java 소스 파일에 퍼블릭 클래스(퍼블릭 인터페이스)가 포함되어 있지 않은 경우 자바 소스 파일 이름에는 제한이 없습니다.
파일명의 명명 규칙을 준수하는 한 파일의 클래스나 인터페이스와 이름이 동일할 필요는 없습니다. 물론 동일할 수도 있습니다. 그 중 하나로 이름을 지으세요.
클래스 이름과 인터페이스 이름은 충돌할 수 없습니다.
동일한 패키지에 있는 클래스나 인터페이스는 동일한 이름을 지정할 수 없습니다. 서로 다른 패키지에 있는 클래스나 인터페이스는 패키지별로 구별할 수 있으므로 동일한 이름을 지정할 수 있습니다.
2. 내부 클래스의 역할
내부 클래스를 사용하면 다음과 같은 이점을 얻을 수 있습니다.
내부 클래스는 잘 숨길 수 있습니다(일반 내부 클래스가 아닌 경우 비공개 및 보호 권한을 가질 수 없지만 내부 클래스는 가능). 🎜>내부 클래스는
다중 상속을 구현할 수 있습니다.
은 인터페이스 수정과 동일한 클래스에서 동일한 이름을 가진 두 메서드 호출을 피할 수 있습니다.
1) 내부 클래스는 잘 숨겨질 수 있습니다
일반적으로 클래스에 대한 액세스 권한은 클래스 앞의 액세스에 의해 수정됩니다. 일반적으로, 내부 클래스가 아닌 클래스는 개인 및 보호 권한을 가질 수 없지만 내부 클래스는 가능하므로 내부 클래스를 통해 정보를 숨길 수 있습니다. 다음 예시를 볼 수 있습니다://测试接口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. *///:~
//外部类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 *///:~name 이 멤버 변수는 예제에 정의된 private 변수입니다. 내부 클래스는 무조건 접근 가능합니다.
3) 다중 상속이 가능하다
다중 상속의 경우 인터페이스는 문제의 일부만 해결하는 반면 내부 클래스는 다중 상속이 가능하다고 할 수 있다. 상속 솔루션이 더욱 완벽해집니다. 내부 클래스는 Java의 상속 메커니즘을 더욱 완벽하게 만들고 내부 클래스가 존재하는 가장 큰 이유입니다. Java의 클래스는 하나의 클래스만 상속할 수 있으며 다중 상속은 내부 클래스를 배우기 전에 인터페이스를 사용하여 구현됩니다. 그러나 때로는 인터페이스를 사용하는 데 많은 불편함이 있습니다. 예를 들어 인터페이스를 구현하면 내부 클래스가 여러 개의 구체적인 클래스 또는
다음 예를 살펴보세요.
//父类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 *///:~
MainExample 클래스에는 두 개의 내부 클래스 Test1과 Test2가 포함되어 있습니다. 그 중 Test1 클래스는 example1 클래스를 상속하고, Test2 클래스는 example2 클래스를 상속합니다. 이와 같이 MainExample 클래스에는 example1 클래스와 example2 클래스의 메소드가 있어 간접적으로 다중 상속이 구현된다. 4) 인터페이스를 수정하지 말고 동일한 클래스에서 동일한 이름을 가진 두 개의 메소드를 호출하지 마십시오.
클래스가 클래스를 상속하고 인터페이스를 구현하지만 클래스는 그리고 상속받은 인터페이스에는 두 개의 동일한 메서드(메서드 서명이 동일함)가 있는데 어떻게 구별할 수 있을까요? 이를 위해서는 내부 클래스를 사용해야 합니다. 예를 들어//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"); } }이때 Test의 test() 메소드는 MyTest를 포괄하는 test() 메소드에 속합니까, 아니면 InterfaceTest의 test() 메소드를 구현합니까? MyTest에서 메서드를 어떻게 조정할 수 있나요? 당연히 구별하기 어렵습니다. 그리고 내부 클래스를 사용하면 이 문제를 쉽게 해결할 수 있습니다. 다음 코드를 보세요.
//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() 方法 } }
내부 클래스를 사용하여 인터페이스를 구현하면 외부 클래스에서 상속받은 동일한 이름의 메서드와 충돌하지 않습니다.
3. 내부 클래스의 종류 Java에서는 내부 클래스를 사용할 때 두 가지 상황이 있습니다. (1) 클래스 내에 클래스를 정의합니다. 내부 클래스, 정적 내부 클래스);2. 멤버 내부 클래스
1. 정의 및 원리
멤버 내부 클래스는 외부 클래스에 붙어 있으므로 외부 클래스 객체가 먼저 생성되어야 내부 클래스 객체를 생성할 수 있습니다. 이러한 이유로 멤버 내부 클래스는 정적 변수와 메서드 를 포함할 수 없습니다. 다음 예를 참조하세요. 如果上面的代码编译无误, 那么我们就可以直接通过 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() [成员内部类对象的创建依赖于外部类对象];而这个外部类对象需要从外面创建并传给形参。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;
}
};
}
}
六. 内部类的继承
위 내용은 Java 내부 클래스에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!