Java中为什么要使用内部类

朱雀 2022-06-09 00:44 327阅读 0赞

一、前言
关于Java的内部类,要说的东西实在太多,这篇博文中也无法一一具体说到,所以就挑些重点的讲。关于内部类的使用,你可能会疑问,为什么我们要使用内部类?为了回答这个问题,你需要知道一些关于内部类的重点。所以本篇文章首先介绍了一些关于内部类的一些与众不同的地方,后面再解答为什么我们要使用内部类这个问题。各位看官,文章稍微有点长,深吸一口气。来,我们开始吧!

二、内部类定义

#

内部类定义非常简单,就是把一个类的定义放在另外一个外围类定义的里面。如下面代码所示:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. class OutterClass {
  2. class InnerClass {
  3. }
  4. }

你可能会想,内部类和组合有什么区别?就这么简单把内部类的定义放在外部类里面,能惹出多少事儿来?诶,你还别说,还真有不少的事儿。

三、内部类惹出来的那些事儿

  1. 内部类能访问外围类的所有成员,包括私有成员。

#

当生成一个内部类对象时,此对象与制造它的外围类对象之间就有了一种联系,所以它能访问其外围类对象的所有成员,而不需要任何特殊的条件。如下面代码所示:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. class OutterClass {
  2. private**int** i = 1;
  3. class InnerClass {
  4. public**void** displayPrivate() {
  5. System.out.println(i);
  6. }
  7. }
  8. }
  9. public**class** MainClass{
  10. public**static**void main(String[] args) {
  11. OutterClass outter = new OutterClass();
  12. OutterClass.InnerClass inner = outter.new InnerClass();
  13. inner.displayPrivate();
  14. }
  15. }

由上面的代码可以看出,内部类能够访问外部类的私有成员变量。在这段代码中,还需要注意的是

①生成内部类对象,必须要先有外围类对象,具体的做法请见代码;

②内部类能访问外围类的私有成员这一点,C++中的嵌套类是没有这个特性的。

#

#

  1. 内部类与static

①内部类不能含有static方法;

②内部类不能含有static数据成员,除非是static final;

③内部类可以继承含有static成员的类。

  1. 匿名内部类

匿名内部类,看起来非常奇怪。因为它太简洁了,但这也带来一个好处,用匿名内部类写出来的代码通常比较简洁啦!见下面代码:

匿名类简化版代码

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. public**class** MainClass {
  2. public Contents contents() {
  3. return**new** Contents() { // Insert a class definition
  4. private**int** i = 11;
  5. public**int value() { return** i; }
  6. }; // Semicolon required in this case
  7. }
  8. public**static**void main(String[] args) {
  9. MainClass p = new MainClass();
  10. Contents c = p.contents();
  11. }
  12. }

正常代码

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. public**class** MainClass {
  2. class MyContents implements Contents {
  3. private**int** i = 11;
  4. public**int value() { return** i; }
  5. }
  6. public Contents contents() { return**new** MyContents(); }
  7. public**static**void main(String[] args) {
  8. Parcel7b p = new Parcel7b();
  9. Contents c = p.contents();
  10. }
  11. }

分析左边的代码,可以看出这个语法非常的奇怪。但是仔细想想,也比较容易理解。语法的核心就是return new () {匿名类定义},这个匿名类是AnonymouysBase的子类,然后向上转型为AnonymouysBase类。其实上面代码是下面代码的简化,大家可以对照看一下。所以呢,匿名内部类,可以简化代码。关于匿名内部类还需要注意:

①匿名内部类所使用的参数必须是final;

②匿名内部类因为没有名字,所以不可能有构造函数,只能通过实例初始化来达到一个构造器的效果。

4.内部类允许继承多个非接口类型

#

众所周知,Java和c++中其中一个不同的地方在于,java是没有多重继承的。可是在某些时候,我们的确还是需要多重继承的,为此java中提出了“接口”的概念。一个类可以实现多个接口,这就解决了多重继承问题吗?我们仔细想想,其实接口只部分解决了多重继承的问题。而每一个内部类都能独立地继承自一个接口或者类,所以无论外围类是否继承了某个接口或者类,对内部类都没有影响。所以内部类和接口双剑合璧,给出了java中多重继承的完美替代方案。见下面代码:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. class D {}
  2. abstract**class** E {}
  3. class Z extends D {
  4. E makeE() { return**new** E() {}; }
  5. }
  6. public**class** MultiImplementation {
  7. static**void** takesD(D d) {}
  8. static**void** takesE(E e) {}
  9. public**static**void main(String[] args) {
  10. Z z = new Z();
  11. takesD(z);
  12. takesE(z.makeE());
  13. }
  14. } ///:~

5.内部类继承

因为内部类的构造器必须链接到指向外围类对象的引用。所以,当一个类需要继承内部类时,那个神秘的链接到外部类的引用也必须要得到初始化。见代码:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. class WithInner {
  2. class Inner {}
  3. }
  4. public**class InheritInner extends** WithInner.Inner {
  5. //! InheritInner() {} // Won’t compile
  6. InheritInner(WithInner wi) {
  7. wi.super();
  8. }
  9. public**static**void main(String[] args) {
  10. WithInner wi = new WithInner();
  11. InheritInner ii = new InheritInner(wi);
  12. }
  13. }

如上面代码所示,InheritInner继承内部类,为了能够使得指向外部类的那个神秘的引用能够得到初始化,需要将外部类的引用作为参数传进内部类的构造函数,并且在内部类的构造函数中代用外部类的super()函数。

#

6.内部类不能被覆盖

有一个外围类,含有一个内部类。当有另外一个类去继承这个外围类,并且去覆盖这个内部类。真的能覆盖吗?见下面代码:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. class Egg {
  2. private Yolk y;
  3. protected**class** Yolk {
  4. public Yolk() { System.out.println(“Egg.Yolk()”); }
  5. }
  6. public Egg() {
  7. System.out.println(“New Egg()”);
  8. y = new Yolk();
  9. }
  10. }
  11. public**class BigEgg extends** Egg {
  12. public**class** Yolk {
  13. public Yolk() { System.out.println(“BigEgg.Yolk()”); }
  14. }
  15. public**static**void main(String[] args) {
  16. new BigEgg();
  17. }
  18. } /* Output:
  19. New Egg()
  20. Egg.Yolk()
  21. *///:~

由程序的输出结果可以看到,Egg和它的派生类BigEgg中的内部类Yolk其实是独立的,它们分布在不同的空间。

#

#

7.内部类VS嵌套类

Java中的嵌套类是指:将内部类声明为static,那么这个内部类就变成了一个嵌套类。因此,相对于内部类来说,嵌套类两个显著的同点在于:

要创建嵌套类的对象,并不需要其外围类的对象,所以内部类中那个指向外围类的神秘的引用在嵌套类中就消失了;

‚不能从嵌套类的对象,访问其外围类的非static成员;

ƒ嵌套类中可以包括static成员或方法。

Java中的嵌套类和c++中的嵌套类,实际上还是有一点不一样的。C++中的嵌套类不能访问外围类的私有成员,但是java中嵌套类可以访问其外围类中static的私有成员。见代码:

[java] view plain copy

在CODE上查看代码片 派生到我的代码片

  1. class OutterClass {
  2. static**class** AnotherLevel {
  3. public**static**void f() {System.out.println(“test”);}
  4. }
  5. }
  6. public**class** MainClass {
  7. public**static**void main(String[] args) {
  8. OutterClass.AnotherLevel.f();
  9. }
  10. } ///:~

8.为什么要使用内部类?

介绍完java中的内部类,现在我们再回过头来总结一下,为什么要使用内部类?楼主也只能凭着楼主

的理解进行一下总结:

1.内部类提供进入其外围类的绿色通道;

2.一般来说,内部类继承自某个类或实现某个接口,和接口一起实现java中多重继承(可以实现继承多个抽象类或者类)

3.private内部类给类的设计者提供了一种途径,通过这种方式可以完全阻止任何依赖于类型的编码,并且完全隐藏了实现的细节;

4.匿名内部类可以使得代码更加地灵活。

5.内部类提供闭包和回调功能,使得用户可以访问到外部类中private变量。更加灵活

四、后记
关于java中的内部类,就先介绍这么多了。为了避免文章篇幅过长,也只是挑了点重点进行梳理,一些细节上的东西就没怎么讲了。如有不足之处,欢迎批评指正,谢谢。

发表评论

表情:
评论列表 (有 0 条评论,327人围观)

还没有评论,来说两句吧...

相关阅读

    相关 为什么内部

    推荐一、 定义 放在一个类的内部的类我们就叫内部类。 二、 作用 1.内部类可以很好的实现隐藏  一般的非内部类,是不允许有 private 与protected权限的

    相关 Java为什么使用抽象

    抽象类  抽象类与接口紧密相关。然接口又比抽象类更抽象,这主要体现在它们的差别上:1)类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承,从抽象类派生的类仍可实现接

    相关 Java为什么使用内部

    一、前言 关于[Java][]的内部类,要说的东西实在太多,这篇博文中也无法一一具体说到,所以就挑些重点的讲。关于内部类的使用,你可能会疑问,为什么我们要使用内部类?为了回

    相关 Java使用内部实战

    一 点睛 分三种情况讨论内部类的使用: 1 在外部类内部使用内部类 2 在外部类以外使用非静态内部类 3 在外部类以外使用静态内部类 二 在外部类内部使用内部类 可