`

java内部类的作用分析

    博客分类:
  • java
 
阅读更多

 

提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比。内部类从表面上看,就是在类中又定义了一个类(下文会看到,内部类可以在很多地方定义),而实际上并没有那么简单,乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。下面从以下几个方面来介绍:
第一次见面
[java] view plaincopy
  1. public interface Contents {  
  2.     int value();  
  3. }  
  4. public interface Destination {  
  5.     String readLabel();  
  6. }  
  7. public class Goods {  
  8.     private class Content implements Contents {  
  9.         private int i = 11;  
  10.         public int value() {  
  11.             return i;  
  12.         }  
  13.     }  
  14.     protected class GDestination implements Destination {  
  15.         private String label;  
  16.         private GDestination(String whereTo) {  
  17.             label = whereTo;  
  18.         }  
  19.         public String readLabel() {  
  20.             return label;  
  21.         }  
  22.     }  
  23.     public Destination dest(String s) {  
  24.         return new GDestination(s);  
  25.     }  
  26.     public Contents cont() {  
  27.         return new Content();  
  28.     }  
  29. }  
  30. class TestGoods {  
  31.     public static void main(String[] args) {  
  32.         Goods p = new Goods();  
  33.         Contents c = p.cont();  
  34.         Destination d = p.dest("Beijing");  
  35.     }  
  36. }  

 

在这个例子里类Content和GDestination被定义在了类Goods内部,并且分别有着protected和private修饰符来控制访问级别。Content代表着Goods的内容,而GDestination代表着Goods的目的地。它们分别实现了两个接口Content和Destination。在后面的main方法里,直接用 Contents c和Destination d进行操作,你甚至连这两个内部类的名字都没有看见!这样,内部类的第一个好处就体现出来了 隐藏你不想让别人知道的操作,也即封装性。
同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。上例中的cont()和dest()方法就是这么做的。那么还有没有别的方法呢?当然有,其语法格式如下:
outerObject=new outerClass(Constructor Parameters);
outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);
注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。至于原因,也就引出了我们下一个话题 非静态内部类对象有着指向其外部类对象的引用,对刚才的例子稍作修改:
[java] view plaincopy
  1. public class Goods {  
  2.     private int valueRate = 2;  
  3.     private class Content implements Contents {  
  4.         private int i = 11 * valueRate;  
  5.         public int value() {  
  6.             return i;  
  7.         }  
  8.     }  
  9.     protected class GDestination implements Destination {  
  10.         private String label;  
  11.         private GDestination(String whereTo) {  
  12.             label = whereTo;  
  13.         }  
  14.         public String readLabel() {  
  15.             return label;  
  16.         }  
  17.     }  
  18.     public Destination dest(String s) {  
  19.         return new GDestination(s);  
  20.     }  
  21.     public Contents cont() {  
  22.         return new Content();  
  23.     }  
  24. }  


在这里我们给Goods类增加了一个private成员变量valueRate,意义是货物的价值系数,在内部类Content的方法value()计算价值时把它乘上。我们发现,value()可以访问valueRate,这也是内部类的第二个好处 一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。
有人会问,如果内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏蔽了,怎么办?没事,Java里用如下格式表达外部类的引用:
outerClass.this
有了它,我们就不怕这种屏蔽的情况了。
静态内部类
和普通的类一样,内部类也可以有静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。这实际上和C++中的嵌套类很相像了,Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用这一点上,当然从设计的角度以及以它一些细节来讲还有区别。
除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。
局部内部类
是的,Java内部类也可以是局部的,它可以定义在一个方法甚至一个代码块之内。
[java] view plaincopy
  1. public class Goods1 {  
  2.     public Destination dest(String s) {  
  3.         class GDestination implements Destination {  
  4.             private String label;  
  5.             private GDestination(String whereTo) {  
  6.                 label = whereTo;  
  7.             }  
  8.             public String readLabel() {  
  9.                 return label;  
  10.             }  
  11.         }  
  12.         return new GDestination(s);  
  13.     }  
  14.     public static void main(String[] args) {  
  15.         Goods1 g = new Goods1();  
  16.         Destination d = g.dest("Beijing");  
  17.     }  
  18. }  


上面就是这样一个例子。在方法dest中我们定义了一个内部类,最后由这个方法返回这个内部类的对象。如果我们在用一个内部类的时候仅需要创建它的一个对象并创给外部,就可以这样做。当然,定义在方法中的内部类可以使设计多样化,用途绝不仅仅在这一点。
下面有一个更怪的例子:
[java] view plaincopy
  1. public class Goods2 {  
  2.     private void internalTracking(boolean b) {  
  3.         if (b) {  
  4.             class TrackingSlip {  
  5.                 private String id;  
  6.                 TrackingSlip(String s) {  
  7.                     id = s;  
  8.                 }  
  9.                 String getSlip() {  
  10.                     return id;  
  11.                 }  
  12.             }  
  13.             TrackingSlip ts = new TrackingSlip("slip");  
  14.             String s = ts.getSlip();  
  15.         }  
  16.     }  
  17.     public void track() {  
  18.         internalTracking(true);  
  19.     }  
  20.     public static void main(String[] args) {  
  21.         Goods2 g = new Goods2();  
  22.         g.track();  
  23.     }  
  24. }  


你不能在if之外创建这个内部类的对象,因为这已经超出了它的作用域。不过在编译的时候,内部类TrackingSlip和其他类一样同时被编译,只不过它由它自己的作用域,超出了这个范围就无效,除此之外它和其他内部类并没有区别。
匿名内部类
java的匿名内部类的语法规则看上去有些古怪,不过如同匿名数组一样,当你只需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。它的语法规则是这样的:
new interfacename(){......}; 或 new superclassname(){......};
下面接着前面继续举例子:
[java] view plaincopy
  1. public class Goods3 {  
  2.     public Contents cont() {  
  3.         return new Contents() {  
  4.             private int i = 11;  
  5.             public int value() {  
  6.                 return i;  
  7.             }  
  8.         };  
  9.     }  
  10. }  

这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。
在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码:
[java] view plaincopy
  1. frame.addWindowListener(new WindowAdapter(){  
  2.     public void windowClosing(WindowEvent e){  
  3.        System.exit(0);  
  4.     }  
  5. });   

有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法:
如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。
将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。
在这个匿名内部类中使用初始化代码块。
为什么需要内部类?
java内部类有什么好处?为什么需要内部类?
首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法的不就行了吗?
的确,以此作为设计内部类的理由,实在没有说服力。
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。
分享到:
评论

相关推荐

    Java内部类继承问题的分析.pdf

    Java内部类继承问题的分析主要关注的是在Java编程中,当内部类(也称为嵌套类)参与继承时所面临的挑战和潜在问题。Java语言采用了单一继承机制,即一个类只能从一个父类继承,这有助于提高代码的可读性和可维护性。...

    浅谈Java内部类的四个应用场景

    通过本文,我们将深入探讨Java内部类的四个典型应用场景,并对每个场景进行详细分析,帮助初学者更好地理解并运用这一特性。 #### 二、Java内部类简介 Java中的内部类分为静态内部类(Static Inner Class)和非...

    Java 内部类的实现

    本文将通过分析给定的示例代码来深入了解Java内部类的实现方式。 #### 内部类概述 内部类可以分为以下几种类型: - **成员内部类**:作为外部类的一个成员,类似于属性或方法。 - **局部内部类**:在方法、构造器...

    java 利用反射获取内部类静态成员变量的值操作.docx

    ### Java 利用反射获取内部类静态成员变量的值操作 #### 一、引言 在Java编程中,反射是一个非常强大的工具,它允许程序在运行时检查类、接口、字段和方法的信息,并且能够创建和操作对象。本文将详细介绍如何使用...

    基于Java的匿名内部类分析与应用.pdf

    "基于Java的匿名内部类分析与应用" 匿名内部类是Java语言中的一大特色,它可以在类的定义中嵌套定义另一个类。匿名内部类没有名字,所以不能用匿名类声明对象,但是可以直接用匿名类创建一个对象。 匿名内部类的...

    基于java内部类作用的深入分析

    本篇文章将深入探讨Java内部类的作用,包括其分类、访问权限、以及如何创建和使用。 首先,Java内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类类似于类的成员变量,可以在类的...

    java内部类的使用

    ### Java内部类的使用 #### 一、内部类的基本概念 内部类是在另一个类的内部定义的类。根据定义的位置不同,内部类可以分为几种不同的类型:成员内部类、局部内部类、静态内部类和匿名内部类。这里我们主要讨论的...

    详细分析Java内部类——局部内部类

    Java内部类之局部内部类 Java内部类是一种特殊的类,它可以嵌套在其他类中,今天我们主要介绍Java局部内部类的相关知识,了解局部内部类的定义、特性和使用场景。 什么是局部内部类? 局部内部类是定义在代码块、...

    C++内部类详细分析

    ### C++内部类详细分析 #### 一、引言 面向对象编程(OOP)自诞生以来,便成为了软件工程领域的重要组成部分。C++作为一种广泛使用的编程语言,支持面向对象编程特性,包括多重继承。多重继承是指一个类可以从多个...

    javacore和dump分析工具

    这个文件最重要的作用就是分析 Java 堆内存泄露问题,heap analyzer,MAT 等工具都可以分析这种文件。 Java core 文件保存的是 java 应用程序在崩溃时或任一时刻关于 Java 运行环境的各种信息。包括 Java 虚拟机的...

    java类修饰词和内部类详解

    ### Java 类修饰词详解 Java 作为一种广泛使用的面向...综上所述,Java 中的类修饰词和内部类在设计和实现面向对象程序时起着至关重要的作用。正确理解和使用这些概念可以帮助开发者构建更加灵活和可维护的软件系统。

    Java匿名类的分析和理解.pdf

    Java匿名类的分析和理解 Java匿名类是Java编程语言中的一种特殊的类,它没有明确的类名。匿名类经常被用在Java GUI程序设计中,例如在Swing库中,以便快速地创建GUI组件。然而,很多Java学习者对匿名类的理解不够...

    java8 探讨与分析匿名内部类、lambda表达式、方法引用的底层实现的测试用例

    在Java 8中,匿名内部类、Lambda表达式和方法引用是重要的新特性,它们极大地简化了代码,提升了代码的可读性和效率。下面将详细探讨这三个知识点,并结合提供的测试用例进行分析。 1. **匿名内部类**: 匿名内部类...

    java期末复习抽象类与接口,内部类,知识点.zip

    复习时,可以详细阅读`Java抽象类.docx`来理解抽象类的定义、用途和实例化规则,通过`Java接口.docx`学习接口的定义、实现方式以及多继承的特点,`Java内部类.docx`将帮助你掌握不同类型的内部类及其应用场景。...

    Java匿名类,匿名内部类实例分析

    Java匿名类和匿名内部类实例分析 Java中的匿名类和匿名内部类是一种特殊的类,它们没有明确的名称,但它们可以继承父类的方法,访问外部类的成员变量和方法,并且可以重写父类的方法。下面将对Java中的匿名类和匿名...

    java线程内部类练习.rar

    通过学习和分析这些代码,我们可以更好地理解和掌握如何在实际项目中利用内部类来创建和控制线程,以及如何处理线程间的同步和通信问题,如使用synchronized关键字、wait()、notify()和notifyAll()等。 总的来说,...

    java学习笔记(内部类)汇集

    #### 四、内部类示例分析 接下来,我们将通过一个具体的例子来理解如何使用内部类以及它们与普通类的区别。 ##### 普通类实现示例 ```java public class TimerTest { public static void main(String[] args) { ...

    Java内部类应用之静态内部类应用示例

    Java内部类应用之静态内部类应用示例主要介绍了Java内部类应用之静态内部类应用,结合实例形式分析了Java静态内部类的原理、功能、用法及相关操作注意事项。 一、静态内部类的定义和特点 静态内部类是使用static...

    javacore分析工具

    JavaCore分析工具是一种在Java应用程序出现问题时,...总之,JavaCore分析工具是Java开发和运维过程中不可或缺的诊断工具,它能够帮助开发者深入理解JVM内部工作原理,有效地解决性能问题,保障Web应用程序的稳定运行。

    Java基于抖音数据分析App源码.zip

    在本项目中,我们关注的是一个名为"Java基于抖音数据分析App源码.zip"的压缩包文件,这显然是一项使用Java编程语言开发的数据分析应用程序,专为解析和挖掘抖音(TikTok)平台上的数据。该项目可能包含了一系列工具...

Global site tag (gtag.js) - Google Analytics