`
这些年
  • 浏览: 399886 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

内部类(转)

 
阅读更多

可以将一个类的定义放在另一个类的定义内部,这就是内部类。

转自:http://blog.csdn.net/chenssy/article/details/13024951

  

    内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二)。

       第一次见面

       内部类我们从外面看是非常容易理解的,无非就是在一个类的内部在定义一个类。

 

  1. public class OuterClass {  
  2.     private String name ;  
  3.     private int age;  
  4.   
  5.     public String getName() {  
  6.         return name;  
  7.     }  
  8.   
  9.     public void setName(String name) {  
  10.         this.name = name;  
  11.     }  
  12.   
  13.     public int getAge() {  
  14.         return age;  
  15.     }  
  16.   
  17.     public void setAge(int age) {  
  18.         this.age = age;  
  19.     }  
  20.       
  21.     class InnerClass{  
  22.         public InnerClass(){  
  23.             name = "chenssy";  
  24.             age = 23;  
  25.         }  
  26.     }  
  27. }  

 

       在这里InnerClass就是内部类,对于初学者来说内部类实在是使用的不多,鄙人菜鸟一个同样没有怎么使用过(貌似仅仅只在做swing 注册事件中使用过),但是随着编程能力的提高,我们会领悟到它的魅力所在,它可以使用能够更加优雅的设计我们的程序结构。在使用内部类之间我们需要明白为什么要使用内部类,内部类能够为我们带来什么样的好处。

 

       一、为什么要使用内部类

       为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响

      在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整

 

  1. public interface Father {  
  2.   
  3. }  
  4.   
  5. public interface Mother {  
  6.   
  7. }  
  8.   
  9. public class Son implements Father, Mother {  
  10.   
  11. }  
  12.   
  13. public class Daughter implements Father{  
  14.   
  15.     class Mother_ implements Mother{  
  16.           
  17.     }  
  18. }  

 

 

      其实对于这个实例我们确实是看不出来使用内部类存在何种优点,但是如果Father、Mother不是接口,而是抽象类或者具体类呢?这个时候我们就只能使用内部类才能实现多重继承了。

      其实使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继承问题,那么我们自然可以使用其他的编码方式,但是使用内部类还能够为我们带来如下特性(摘自《Think in java》):

      1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

      2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

      3、创建内部类对象的时刻并不依赖于外围类对象的创建。

      4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

      5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。

 

       二、内部类基础

       在这个部分主要介绍内部类如何使用外部类的属性和方法,以及使用.this与.new。

       当我们在创建一个内部类的时候,它无形中就与外围类有了一种联系,依赖于这种联系,它可以无限制地访问外围类的元素。

 

  1. public class OuterClass {  
  2.     private String name ;  
  3.     private int age;  
  4.   
  5.     /**省略getter和setter方法**/  
  6.       
  7.     public class InnerClass{  
  8.         public InnerClass(){  
  9.             name = "chenssy";  
  10.             age = 23;  
  11.         }  
  12.           
  13.         public void display(){  
  14.             System.out.println("name:" + getName() +"   ;age:" + getAge());  
  15.         }  
  16.     }  
  17.       
  18.     public static void main(String[] args) {  
  19.         OuterClass outerClass = new OuterClass();  
  20.         OuterClass.InnerClass innerClass = outerClass.new InnerClass();  
  21.         innerClass.display();  
  22.     }  
  23. }  
  24. --------------  
  25. Output:  
  26. name:chenssy   ;age:23  

 

 

       在这个应用程序中,我们可以看到内部了InnerClass可以对外围类OuterClass的属性进行无缝的访问,尽管它是private修饰的。这是因为当我们在创建某个外围类的内部类对象时,此时内部类对象必定会捕获一个指向那个外围类对象的引用,只要我们在访问外围类的成员时,就会用这个引用来选择外围类的成员。

       其实在这个应用程序中我们还看到了如何来引用内部类:引用内部类我们需要指明这个对象的类型:OuterClasName.InnerClassName。同时如果我们需要创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类:OuterClass.InnerClass innerClass = outerClass.new InnerClass();。

       同时如果我们需要生成对外部类对象的引用,可以使用OuterClassName.this,这样就能够产生一个正确引用外部类的引用了。当然这点实在编译期就知晓了,没有任何运行时的成本。

 

  1. public class OuterClass {  
  2.     public void display(){  
  3.         System.out.println("OuterClass...");  
  4.     }  
  5.       
  6.     public class InnerClass{  
  7.         public OuterClass getOuterClass(){  
  8.             return OuterClass.this;  
  9.         }  
  10.     }  
  11.       
  12.     public static void main(String[] args) {  
  13.         OuterClass outerClass = new OuterClass();  
  14.         OuterClass.InnerClass innerClass = outerClass.new InnerClass();  
  15.         innerClass.getOuterClass().display();  
  16.     }  
  17. }  
  18. -------------  
  19. Output:  
  20. OuterClass...  

 

 

       到这里了我们需要明确一点,内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。

       在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。

 

       三、成员内部类

       成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

       在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

 

  1. public class OuterClass {  
  2.     private String str;  
  3.       
  4.     public void outerDisplay(){  
  5.         System.out.println("outerClass...");  
  6.     }  
  7.       
  8.     public class InnerClass{  
  9.         public void innerDisplay(){  
  10.             //使用外围内的属性  
  11.             str = "chenssy...";  
  12.             System.out.println(str);  
  13.             //使用外围内的方法  
  14.             outerDisplay();  
  15.         }  
  16.     }  
  17.       
  18.     /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */  
  19.     public InnerClass getInnerClass(){  
  20.         return new InnerClass();  
  21.     }  
  22.       
  23.     public static void main(String[] args) {  
  24.         OuterClass outer = new OuterClass();  
  25.         OuterClass.InnerClass inner = outer.getInnerClass();  
  26.         inner.innerDisplay();  
  27.     }  
  28. }  
  29. --------------------  
  30. chenssy...  
  31. outerClass...  

 

 

推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 。

 

       四、局部内部类

       有这样一种内部类,它是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

       对于局部内部类实在是想不出什么好例子,所以就引用《Think in java》中的经典例子了。

       定义在方法里:

 

  1. public class Parcel5 {  
  2.     public Destionation destionation(String str){  
  3.         class PDestionation implements Destionation{  
  4.             private String label;  
  5.             private PDestionation(String whereTo){  
  6.                 label = whereTo;  
  7.             }  
  8.             public String readLabel(){  
  9.                 return label;  
  10.             }  
  11.         }  
  12.         return new PDestionation(str);  
  13.     }  
  14.       
  15.     public static void main(String[] args) {  
  16.         Parcel5 parcel5 = new Parcel5();  
  17.         Destionation d = parcel5.destionation("chenssy");  
  18.     }  
  19. }  

 

 

       定义在作用域内:

 

  1. public class Parcel6 {  
  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("chenssy");  
  14.             String string = ts.getSlip();  
  15.         }  
  16.     }  
  17.       
  18.     public void track(){  
  19.         internalTracking(true);  
  20.     }  
  21.       
  22.     public static void main(String[] args) {  
  23.         Parcel6 parcel6 = new Parcel6();  
  24.         parcel6.track();  
  25.     }  
  26. }  

 

       五、匿名内部类

       在做Swing编程中,我们经常使用这种方式来绑定事件

 

  1. button2.addActionListener(    
  2.                 new ActionListener(){    
  3.                     public void actionPerformed(ActionEvent e) {    
  4.                         System.out.println("你按了按钮二");    
  5.                     }    
  6.                 });  

 

        我们咋一看可能觉得非常奇怪,因为这个内部类是没有名字的,在看如下这个例子:

 

  1. public class OuterClass {  
  2.     public InnerClass getInnerClass(final int num,String str2){  
  3.         return new InnerClass(){  
  4.             int number = num + 3;  
  5.             public int getNumber(){  
  6.                 return number;  
  7.             }  
  8.         };        /* 注意:分号不能省 */  
  9.     }  
  10.       
  11.     public static void main(String[] args) {  
  12.         OuterClass out = new OuterClass();  
  13.         InnerClass inner = out.getInnerClass(2"chenssy");  
  14.         System.out.println(inner.getNumber());  
  15.     }  
  16. }  
  17.   
  18. interface InnerClass {  
  19.     int getNumber();  
  20. }  
  21.   
  22. ----------------  
  23. Output:  
  24. 5  

 

       这里我们就需要看清几个地方

      1、 匿名内部类是没有访问修饰符的。

      2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。

      3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。

      4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。

PS:由于篇幅有限,对匿名内部类就介绍到这里,有关更多关于匿名内部类的知识,我就会在下篇博客(java提高篇-----详解匿名内部类)做详细的介绍,包括为何形参要定义成final,怎么对匿名内部类进行初始化等等,敬请期待……

 

       六、静态内部类

       在java提高篇-----关键字static中提到Static可以修饰成员变量、方法、代码块,其他它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

      1、 它的创建是不需要依赖于外围类的。

      2、 它不能使用任何外围类的非static成员变量和方法。

 

  1. public class OuterClass {  
  2.     private String sex;  
  3.     public static String name = "chenssy";  
  4.       
  5.     /** 
  6.      *静态内部类 
  7.      */  
  8.     static class InnerClass1{  
  9.         /* 在静态内部类中可以存在静态成员 */  
  10.         public static String _name1 = "chenssy_static";  
  11.           
  12.         public void display(){  
  13.             /*  
  14.              * 静态内部类只能访问外围类的静态成员变量和方法 
  15.              * 不能访问外围类的非静态成员变量和方法 
  16.              */  
  17.             System.out.println("OutClass name :" + name);  
  18.         }  
  19.     }  
  20.       
  21.     /** 
  22.      * 非静态内部类 
  23.      */  
  24.     class InnerClass2{  
  25.         /* 非静态内部类中不能存在静态成员 */  
  26.         public String _name2 = "chenssy_inner";  
  27.         /* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */  
  28.         public void display(){  
  29.             System.out.println("OuterClass name:" + name);  
  30.         }  
  31.     }  
  32.       
  33.     /** 
  34.      * @desc 外围类方法 
  35.      * @author chenssy 
  36.      * @data 2013-10-25 
  37.      * @return void 
  38.      */  
  39.     public void display(){  
  40.         /* 外围类访问静态内部类:内部类. */  
  41.         System.out.println(InnerClass1._name1);  
  42.         /* 静态内部类 可以直接创建实例不需要依赖于外围类 */  
  43.         new InnerClass1().display();  
  44.           
  45.         /* 非静态内部的创建需要依赖于外围类 */  
  46.         OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();  
  47.         /* 方位非静态内部类的成员需要使用非静态内部类的实例 */  
  48.         System.out.println(inner2._name2);  
  49.         inner2.display();  
  50.     }  
  51.       
  52.     public static void main(String[] args) {  
  53.         OuterClass outer = new OuterClass();  
  54.         outer.display();  
  55.     }  
  56. }  
  57. ----------------  
  58. Output:  
  59. chenssy_static  
  60. OutClass name :chenssy  
  61. chenssy_inner  
  62. OuterClass name:chenssy  

 

 

       上面这个例子充分展现了静态内部类和非静态内部类的区别。

       到这里内部类的介绍就基本结束了!对于内部类其实本人认识也只是皮毛,逼近菜鸟一枚,认知有限!我会利用这几天时间好好研究内部类!

巩固基础,提高技术,不惧困难,攀登高峰!!!!!!

分享到:
评论

相关推荐

    java 匿名内部类的使用规范

    Java匿名内部类是Java语言中一个独特且强大的特性,它允许我们在不需要定义一个单独的类的情况下创建类的实例。这在处理回调、事件监听、单例模式以及其他需要短时间内定义一个简单类的情况时非常有用。本篇文章将...

    内部类知识总结3--匿名内部类

    内部类可以是静态的,也可以是非静态的,而匿名内部类则是一种没有名字的内部类,通常用于快速实现简单的回调或者接口实现。这篇总结将深入探讨匿名内部类的相关知识点。 1. **匿名内部类的概念** 匿名内部类是...

    内部类的使用

    首先,内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类就像其他成员变量一样,可以直接访问外部类的所有成员,包括私有成员。局部内部类只存在于某个方法内,它的作用范围更小,...

    java中的匿名内部类总结

    Java 中的匿名内部类总结 Java 中的匿名内部类是一种特殊的内部类,它没有名字,因此也称为匿名类。匿名内部类是一种简洁的编程方式,能够简化代码编写,但它也有一些限制和特点。 匿名内部类的定义 匿名内部类是...

    java基础第七章内部类与异常类.doc

    Java 基础第七章内部类与异常类 Java 语言支持在一个类中定义另一个类,这样的类称做内部类。内部类和外嵌类之间存在着紧密的关系:内部类可以访问外嵌类的成员变量和方法,而外嵌类也可以使用内部类声明的对象作为...

    java和kotlin的内部类静态嵌套类

    内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态嵌套类。其中,静态嵌套类是与外部类关联但不持有对外部类的引用,因此它可以像普通类一样被静态引用,而无需外部类实例。 Java的静态嵌套类通常用于...

    控制器(内部类)

    内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。控制器通常会用到的是成员内部类或静态内部类,因为它们可以访问外部类的属性和方法,同时又具有一定的封装性。 1. **成员内部类**:这种...

    反射私有内部类的例子

    ### 反射私有内部类的例子 #### 一、引言 在Java编程语言中,反射(Reflection)是一项强大的功能,允许程序在运行时检查和修改自身结构与行为。通过反射,可以动态地获取类的信息并操作其字段、方法以及构造器等。...

    JAVA内部类

    ### JAVA内部类详解 #### 引言 自Java1.1版本起,内部类的引入为面向对象编程提供了更为灵活的封装机制。然而,如同所有强大的特性,内部类的不当使用可能导致代码复杂度的增加,甚至产生维护上的困难。本文旨在...

    Hadoop源代码分析(Task的内部类和辅助类)

    ### Hadoop源代码分析——Task的内部类与辅助类 #### 概述 在Hadoop框架中,`Task`类是处理数据的核心组件之一,它包括`MapTask`和`ReduceTask`两种类型,分别负责数据的映射处理和归约处理。本文将深入剖析`Task`...

    java(Day12)---内部类

    内部类主要有四种类型:成员内部类、静态内部类、局部内部类和匿名内部类。 1. 成员内部类: 成员内部类可以直接访问外部类的所有成员,包括实例变量和方法。它定义的位置是在类中,但不在任何方法之内。成员内部...

    详解Android XML中引用自定义内部类view的四个why

    当我们尝试在XML布局文件中引用自定义的内部类视图时,可能会遇到一些问题。本文将详细解析这一过程中的四个关键点,帮助开发者理解为何需要遵循这些规则。 1. **静态内部类**: 在XML中引用自定义内部类视图时,...

    内部类介绍

    ### 内部类概念及其类型详解 #### 一、内部类概述 在Java语言中,内部类是一个重要的特性,它允许开发者在一个类的内部定义另一个类。这种结构上的嵌套使得内部类能够直接访问外部类的成员(包括私有成员),从而...

    java学习资料抽象类,接口,内部类

    在这个Java学习资料中,我们重点探讨抽象类、接口和内部类。 首先,抽象类是一种不能实例化的类,它主要用于被其他类继承。在Java中,使用`abstract`关键字来定义一个抽象类。抽象类可以包含抽象方法(无方法体的...

    java基础第七章-内部类与异常类.doc

    Java 基础第七章 -内部类与异常类 本章节主要讲解 Java 的内部类和异常类的概念、特点、使用方法和注意事项。 内部类 ------ 内部类是 Java 支持的一种特殊类,定义在另一个类的内部。内部类和外嵌类之间存在关系...

    MapReduce,泛型,匿名内部类,Runnable和Callable

    MapReduce可以帮助开发者在分布式环境中有效地处理海量数据,而泛型、匿名内部类以及Runnable和Callable接口则为Java编程提供了强大的工具,使我们能够编写更加灵活、安全和高效的代码。在实际开发中,结合这些技术...

    使用适配器类(匿名内部类).rar_适配器

    在Java中,适配器模式通常通过继承或实现来实现,而在本例中,我们关注的是使用匿名内部类作为适配器的方法。 在Java中,匿名内部类是一种没有名字的类,它可以继承一个类或实现一个接口。这种类通常用于快速实现...

    day03-内部类&API1

    【标题】:“内部类&API1”的讲解 【描述】:本内容主要涵盖了类名、抽象类和接口作为参数及返回值的使用,以及内部类的基础应用。 【知识点详解】: 1. 参数传递: - **类名作为形参和返回值**:在Java中,当...

    day05_内部类和Lambda表达式.zip

    在Java编程语言中,内部类和Lambda表达式是两种非常重要的高级特性,它们极大地提高了代码的简洁性和可读性。让我们深入探讨这两个概念。 首先,我们来看内部类。内部类,顾名思义,是在一个外部类(也称为外部或...

Global site tag (gtag.js) - Google Analytics