深刻理解java嵌套类和内部类、匿名类

1、什么是嵌套类及内部类前端

  能够在一个类的内部定义另外一个类,这种类称为嵌套类(nested classes),它有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用不多,最重要的是非静态嵌套类,也便是被称做为内部类(inner)。嵌套类从JDK1.1开始引入。其中inner类又可分为三种:
  其1、在一个类(外部类)中直接定义的内部类;
  其2、在一个方法(外部类的方法)中定义的内部类;
  其3、匿名内部类。
java

  下面,我将说明这几种嵌套类的使用及注意事项。ide

2、静态嵌套类this

  以下所示代码为定义一个静态嵌套类,
spa

  1. public class StaticTest {   .net

  2.         private static String name = "javaJohn";           orm

  3.   private String id = "X001";  对象

  4.   static class Person{  接口

  5.     private String address = "swjtu,chenDu,China";  事件

  6.     public String mail = "josserchai@yahoo.com";//内部类公有成员  

  7.     public void display(){  

  8.       //System.out.println(id);//不能直接访问外部类的非静态成员  

  9.       System.out.println(name);//只能直接访问外部类的静态成员  

  10.       System.out.println("Inner "+address);//访问本内部类成员。  

  11.     }  

  12.   }  

  13.   

  14.   public void printInfo(){  

  15.     Person person = new Person();  

  16.     person.display();  

  17.     //System.out.println(mail);//不可访问  

  18.     //System.out.println(address);//不可访问  

  19.     System.out.println(person.address);//能够访问内部类的私有成员  

  20.     System.out.println(person.mail);//能够访问内部类的公有成员  

  21.   

  22.   }  

  23.   public static void main(String[] args) {  

  24.   StaticTest staticTest = new StaticTest();  

  25.   staticTest.printInfo();  

  26. }  

  27. }  



  在静态嵌套类内部,不能访问外部类的非静态成员,这是由Java语法中"静态方法不能直接访问非静态成员"所限定。若想访问外部类的变量,必须经过其它方法解决,因为这个缘由,静态嵌套类使用不多。注意,外部类访问内部类的的成员有些特别,不能直接访问,但能够经过内部类来访问,这是由于静态嵌套内的全部成员和方法默认为静态的了。同时注意,内部静态类Person只在类StaticTest 范围内可见,若在其它类中引用或初始化,均是错误的。

3、在外部类中定义内部类

  以下所示代码为在外部类中定义两个内部类及它们的调用关系:
  

  1. public class Outer {   

  2.            int outer_x = 100;  

  3.     class Inner{  

  4.       public int y = 10;  

  5.       private int z = 9;  

  6.       int m = 5;  

  7.       public void display(){  

  8.         System.out.println("display outer_x:"+ outer_x);  

  9.       }  

  10.       private void display2(){  

  11.         System.out.println("display outer_x:"+ outer_x);  

  12.       }  

  13.     }  

  14.     void test(){  

  15.       Inner inner = new Inner();  

  16.       inner.display();  

  17.       inner.display2();  

  18.       //System.out.println("Inner y:" + y);//不能访问内部内变量  

  19.       System.out.println("Inner y:" + inner.y);//能够访问  

  20.       System.out.println("Inner z:" + inner.z);//能够访问  

  21.       System.out.println("Inner m:" + inner.m);//能够访问  

  22.       InnerTwo innerTwo = new InnerTwo();  

  23.       innerTwo.show();  

  24.     }  

  25.     class InnerTwo{  

  26.       Inner innerx = new Inner();  

  27.       public void show(){  

  28.         //System.out.println(y);//不可访问Innter的y成员  

  29.         //System.out.println(Inner.y);//不可直接访问Inner的任何成员和方法  

  30.         innerx.display();//能够访问  

  31.         innerx.display2();//能够访问  

  32.         System.out.println(innerx.y);//能够访问  

  33.         System.out.println(innerx.z);//能够访问  

  34.         System.out.println(innerx.m);//能够访问  

  35.       }  

  36.     }  

  37.     public static void main(String args[]){  

  38.       Outer outer = new Outer();  

  39.       outer.test();  

  40.     }  

  41.   }  



  以上代码须要说明有,对于内部类,一般在定义类的class关键字前不加public 或 private等限制符,若加了没有任何影响,同时好像这些限定符对内部类的变量和方法也没有影响(?)。另外,就是要注意,内部类Inner及InnterTwo只在类Outer的做用域内是可知的,若是类Outer外的任何代码尝试初始化类Inner或使用它,编译就不会经过。同时,内部类的变量成员只在内部内内部可见,若外部类或同层次的内部类须要访问,需采用示例程序中的方法,不可直接访问内部类的变量。



4、在外部类中定义内部类


  匿名类就是没有名字的内部类,是内部类的一种特殊状况。?????????  这句话对吗???

前端时间在写.net项目中,一直错将.cs里的两个class看成内部类,原来是一个文件里的两个类而已,这让我想起了Java中的内部类,比较内部类,那么还有两个类,那就是匿名类和匿名内部类。今天我想就Java中的这三种类进行个比较。

咱们知道在Java语言规范中能够作不少事,例如一个类或一个接口中能够声明一个类或接口,在一个方法中能够声明一个类,类与接口声明能够嵌套任意深度等。

 

匿名类:

      一、new <类或接口><类的主体>,匿名类的声明是在编译时进行的,实例化是在运行时进行的,因此在for循环中一个new语句会建立相同匿名类的几个实例,而不是建立几个不一样匿名类的一个实例。

      二、若是要执行的对象须要一个对象,但却不值得建立全新的对象(多是由于该对象只在一个方法内部使用),在这个时候使用匿名类就会很是合适,因此说,匿名类通常会在swing程序中快速建立事件处理程序。

Java代码  收藏代码

  1. firstButton.addActionListener(new ActionListener() {  

  2.         @Override  

  3.         public void actionPerformed(ActionEvent e) {  

  4.             getTxtValue().setText("第一个按钮触发的事件!");  

  5.         }  

  6.     });   

       三、从技术上说,匿名类能够被看做非静态的内部类,因此他们具备方法内部声明的非静态内部类相同的权限和限制。

 

 

内部类:

内部类顾名思义就是在一个类的内部还有一个类

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo {  

  9.     public static void main(String[] args) {  

  10.         new Outer().fun();  

  11.     }  

  12. }  

  13.   

  14. class Outer {  

  15.   

  16.     private String name = "Hello 内部类";  

  17.   

  18.     class Inner {  

  19.         public void print() {  

  20.             System.out.println("name = " + name);  

  21.   

  22.         }  

  23.     };  

  24.   

  25.     public void fun() {  

  26.         new Inner().print();  

  27.     }  

  28. }  

 

 内部类生成的.class文件名为:Outer$Inner.class,从上面的结构发现内部类的的缺点是“结构很是的混乱”。

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo02 {  

  9.     public static void main(String[] args) {  

  10.         new Outer02().fun();  

  11.     }  

  12. }  

  13.   

  14. class Outer02 {  

  15.   

  16.     private String name = "Hello 内部类";  

  17.   

  18.     public void fun() {  

  19.         new Inner02(this).print();  

  20.     }  

  21.   

  22.     public String getName() {  

  23.   

  24.         return this.name;  

  25.     }  

  26. };  

  27.   

  28. class Inner02 {  

  29.     private Outer02 out;  

  30.   

  31.     public Inner02(Outer02 out) {  

  32.         this.out = out;  

  33.     }  

  34.   

  35.     public void print() {  

  36.         System.out.println("name = " + this.out.getName());  

  37.   

  38.     }  

  39. };  

 从上能够看出内部类的优势是“能够方便的访问外部类中的私有成员”;

若是要在外部直接使用内部类的实例化对象:

      外部类.内部类 内部类对象 = 外部类实例.new 内部类实例();

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang  2012-1-11 

  5.  * 

  6.  *  Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo03 {  

  9.     public static void main(String[] args) {  

  10.         Outer03 out = new Outer03();//外部类实例  

  11.         Outer03.Inner inner = out.new Inner();//实例化内部类对象  

  12.         inner.print();  

  13.     }  

  14. }  

  15. class Outer03{  

  16.     private String name = "Hello 内部类";  

  17.     class Inner {  

  18.         public void print() {  

  19.             System.out.println("name = " + name);  

  20.         }  

  21.     }  

  22. }  

 

 一个内部类若是使用static关键字声明的话,则此内部类就将成为外部类,能够直接经过外部类.内部类的形式访问

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo04 {  

  9.     public static void main(String[] args) {  

  10.         Outer04.Inner inner = new Outer04.Inner();// 实例化内部类对象  

  11.         inner.print();  

  12.     }  

  13. }  

  14.   

  15. class Outer04 {  

  16.     private static String name = "Hello 内部类";  

  17.   

  18.     static class Inner {  

  19.         public void print() {  

  20.             System.out.println("name = " + name);  

  21.         }  

  22.     }  

  23. }  

 

 内部类能够在任意的地方使用,例如方法中声明

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo05 {  

  9.     public static void main(String[] args) {  

  10.         new Outer05().fun();  

  11.     }  

  12. }  

  13.   

  14. class Outer05 {  

  15.     private static String name = "Hello 内部类";  

  16.   

  17.     public void fun() {  

  18.         class Inner {  

  19.             public void print() {  

  20.                 System.out.println("name = " + name);  

  21.             }  

  22.         }  

  23.         new Inner().print();  

  24.     }  

  25. }  

 

 在方法中定义的内部类,能够直接访问外部类中的各个成员,可是若是要访问方法中的参数,则须要在参数上加上final关键字声明;

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo06 {  

  9.     public static void main(String[] args) {  

  10.         new Outer06().fun(20);  

  11.     }  

  12. }  

  13.   

  14. class Outer06 {  

  15.     private static String name = "Hello 内部类";  

  16.   

  17.     public void fun(final int temp) {  

  18.         class Inner {  

  19.             public void print() {  

  20.                 System.out.println("temp = " + temp);  

  21.                 System.out.println("name = " + name);  

  22.             }  

  23.         }  

  24.         new Inner().print();  

  25.     }  

  26. }  

 匿名类与内部的联系与区别:

按所在位置能够分为两大类:

      一、在类的方法中

                     特色:

                              a、能够访问宿主类的全部元素 ;

                              b、保存宿主类对象的引用,建立对象时必须有宿主类对象;

                              c、 不能有静态数据;

继续划分:

                             A、本地内部类;

                             B、匿名内部类

 二者的区别在于本地内部类有构造方法,而匿名内部类只能实例初始化;

      二、在类或接口做用域中;

                     继续划分:

                            A、普通内部类

                            B、静态内部类

 

 

匿名内部类:

匿名内部类是在抽象类和接口的基础之上发展起来的。

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class NoNameClass01 {  

  9.     public static void main(String[] args) {  

  10.         new X().fun2();  

  11.     }  

  12. }  

  13.   

  14. interface A {  

  15.     public void fun();  

  16. }  

  17.   

  18. class B implements A {  

  19.     public void fun() {  

  20.   

  21.         System.out.println("Hello 准备匿名内部类");  

  22.     }  

  23. }  

  24.   

  25. class X {  

  26.     public void fun1(A a) {  

  27.         a.fun();  

  28.     }  

  29.   

  30.     public void fun2() {  

  31.         this.fun1(new B());  

  32.     }  

  33. }  

 经过上面的Demo,若是如今假设B类只使用一次,那么还有必要将其定义成一个单独的类么?

 呵呵,此时就可使用匿名内部类:

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class NoNameClass02 {  

  9.   

  10.     public static void main(String[] args) {  

  11.         new XX().fun2();  

  12.     }  

  13. }  

  14.   

  15. interface AA {  

  16.     public void fun();  

  17. }  

  18.   

  19. class XX {  

  20.     public void fun1(AA a) {  

  21.         a.fun();  

  22.     }  

  23.     public void fun2() {  

  24.         this.fun1(new AA() {  

  25.             public void fun() {  

  26.                 System.out.println("Hello 准备匿名内部类");  

  27.             }  

  28.         });  

  29.     }  

  30. }  

 其实在真正的项目开发中匿名内部类使用的很是之少,通常在Java的图形界面和如今的Android中使用的比较多点。

 

 最后给一个内部类实现的简单链表:

Java代码  收藏代码

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class LinkDemo {  

  9.     public static void main(String args[]) {  

  10.         Link link = new Link();  

  11.         link.add("A");  

  12.         link.add("B");  

  13.         link.add("C");  

  14.         link.add("D");  

  15.         link.add("E");  

  16.         link.print();  

  17.     }  

  18. };  

  19.   

  20. class Link {  

  21.     class Node {  

  22.         private String name;  

  23.         private Node next; // 单向链表,每一个节点指向下一个节点  

  24.   

  25.         public Node(String name) {  

  26.             this.name = name; // 经过构造方法为name属性赋值  

  27.         }  

  28.   

  29.         public void addNode(Node newNode) { // 增长节点  

  30.             if (this.next == null) {  

  31.                 this.next = newNode; // 保存节点  

  32.             } else {  

  33.                 this.next.addNode(newNode); // 继续向下查找  

  34.             }  

  35.         }  

  36.   

  37.         public void printNode() { // 输出节点  

  38.             System.out.println(this.name);  

  39.             if (this.next != null) { // 此节点以后还存在其余的节点  

  40.                 this.next.printNode();  

  41.             }  

  42.         }  

  43.     };  

  44.   

  45.     private Node root; // 链表的头  

  46.   

  47.     public void add(String name) { // 增长节点  

  48.         Node newNode = new Node(name); // 定义一个新的节点  

  49.         /* 

  50.          * 若是是第一个节点,则确定是根节点, 若是是第二个节点,则确定放在根节点next中 若是是第三个节点,则确定放在第二个节点的next中 

  51.          */  

  52.         if (this.root == null) {  

  53.             this.root = newNode; // 将第一个节点设置成根节点  

  54.         } else {  

  55.             // 确定要放在最后一个节点以后  

  56.             // 经过节点.next来不断的判断  

  57.             this.root.addNode(newNode);  

  58.         }  

  59.     }  

  60.   

  61.     public void print() {  

  62.         if (this.root != null) { // 若是根节点为空了,则没有任何内容  

  63.             this.root.printNode();  

  64.         }  

  65.     }  

  66. };  

相关文章
相关标签/搜索