内部类(inner class)的简单介绍

本文主要介绍内部类(inner class)的一些基本应用,将从内部类的分类角度,首先对每一个具体内部类进行介绍。主要包括普通的内部类【common inner class】、局部内部类[local inner class]、嵌套内部类【nested innner class】、匿名内部类【anonymous inner class】、然后比较一下局部内部类[local inner class]和匿名内部类【anonymous inner class ]的区别,进而知道在具体情况下该选择内部类,即到底用local inner class还是anonymous inner class。最后介绍内部类的应用

一:首先对每一个具体内部类进行介绍

1.普通的内部类【common inner class】

定义:在一个类里面直接定义一个类:

一些详细情况看代码:

 1 package com.qls.comonInnerClass;
 2 
 3 public class A {
 4     /**
 5      * 从B C D E 这四个普通内部类中可以看出类前面的修饰符可以是
 6      * private  protected default(也就是什么修饰符没有的D) public.  而在局部内部类中修饰类的只能是:
 7      * abstract 或final 或者什么修饰符都没有。
 8      * 注意的问题如下:
 9      * 1.通常情况下:外部类会有一个返回内部类引用的一个方法如getB()这个方法。
10      * 2.如何在内部类中用this指代外部类引用?【答:外部类名.this 参考第19行代码。】
11      * 以及如何创建内部类的一个实例?【答:x.new B() 其中x是外部类的一个实例,B为一个内部类。
12      * 若是直接写new B()会报错。参考第38、39两行代码。】
13      * 上述两个注意点对其他的内部类也适用。
14      * @author 秦林森
15      *
16      */
17     private  class B {
18         public A outer(){
19             return A.this;//A.this是指代A的一个引用。
20         }
21     }
22     protected class C{
23         
24     }
25     class D{
26         
27     }
28     public class E{
29         
30     }
31     /**
32      * 返回内部类的引用:
33      */
34     B getB(){
35         return new B();
36     }
37     public static void main(String[] args) {
38         A a = new A();
39         B b = a.new B();
40     }
41 }

局部内部类【local innner class】

定义:把类定义在方法里面,或者是方法中的某一个区域中。

代码如下:

 1 package com.qls.localInnerClass2;
 2 /**
 3  * 定义:the creation of an entire class within the scope of a method,or Nesting a class within 
 4  * a scope of a method.
 5  * This is called a local inner class.
 6  * 注意情况如下:
 7  * 1.局部内部类【local inner class】如果想要修饰的话,只有abstract 和final可以,
 8  * 其余的如(public protected)等都不可以。
 9  * 2.在局部内部类中只能访问包含该内部类的范围(enclosing scope)的final变量。若不是则会报错。
10  * 
11  * @author 秦林森
12  *
13  */
14 public class A {
15     public void ouyangfeng(){
16         //把类D定义在方法ouyangfeng()的某个区域中。
17         if(3>2){
18             class D{
19                 
20             }
21         }
22         final class B{
23             
24         }
25     }
26     
27     public void  sixi(final String s){
28         int e=1;
29         final int c=8;
30         class C{
31             /**
32              * 在局部内部类或者匿名内部类中只能访问包含该内部类的范围(enclosing scope)的final变量。
33              * 若不是则会报错。
34              * 如int f=e;编译器报错。
35              */
36             String str=s;
37             int d=c;
38 //            int f=e;//编译器报错。
39         }
40     }
41     public static void main(String[] args) {
42         // TODO Auto-generated method stub
43 
44     }
45 
46 }

匿名内部类:没有名字的内部类。

下面的代码介绍了以下的内容:

1.匿名内部类实现一个接口,

2.匿名内部类实现一个没有默认构造方法的抽象类

3.匿名内部类和局部内部类一样把参数定义成final,完成字段初始化

4.匿名内部类用普通代码块{}完成初始化,弥补了匿名内部类没有构造方法的缺陷。

代码如下:

package com.qls.anonymouseInnerClass;
/**
 * 匿名内部类(anonymous inner class)一般用在return 语句中。
 * 注意情况如下:
 * 匿名内部类由于没有名字,自然而然也就没有构造方法,其他三种内部类都有构造方法。
 * 没有构造方法怎么给对象赋值进行初始化呢?【答:用普通的代码块{},在这个代码块里面实行初始化。】
 * @author 秦林森
 *
 */
interface B{
    void ouyangfeng();
}
abstract class C{
    private int i;
    public C(int i) {
        this.i=i;
    }
    public abstract int value();
    
}
public class A {
    public B getB(){
        //new B(){};就是匿名内部类:用默认的构造方法
        return new B() {
            
            @Override
            public void ouyangfeng() {
                // TODO Auto-generated method stub
                System.out.println("ouyangfeng is chief village of sixi ");
            }
        };
    }
    public C getC(final int i){
        //匿名内部类用一个带参数的构造方法
        return new C(i) {
            //用普通代码块实现初始化:
            {
                //这里写两个输出语句作为演示。
                System.out.println("泗溪");
                System.out.println("ouyangfeng");
                System.out.println(value());//输出value的值
            }
            @Override
            public int value() {
                // TODO Auto-generated method stub
                return i;//从这里可以看出要想引用i,必须把i定义成final。这和局部内部类一样。
            }
        };
        
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new A().getC(4);//输出泗溪、ouyangfeng、4
        
    }

}

 嵌套内部类:

 1 package com.qls.nestedClass;
 2 /**
 3  * 如果你不想让内部类的对象和外部类的对象有如何联系的话,你就可以把内部类定义成static
 4  * 嵌套内部类(Nested inner class)的定义:类中关键词static修饰的内部类。
 5  * 注意情况如下:
 6  * 1.在嵌套内部类中不能访问外部类的非静态变量。
 7  * 2.创建内部类变量时,你不想通过创建外部类变量才能创建内部类变量时,你可以把这个内部类定义成static
 8  * 即嵌套内部类。
 9  * 3.在接口interface中定义的内部类默认都是public static 的,所以在接口中的内部类必是嵌套内部类。
10  * @author 秦林森
11  *
12  */
13 interface D{
14     void hello();
15     class Test implements D{
16 
17         @Override
18         public void hello() {
19             // TODO Auto-generated method stub
20             System.out.println("hello");
21         }
22         public static void main(String[] args) {
23             /**
24              * 由于Test类默认是public static 的,所以创建Test对象时,不需要通过外部类D,
25              * 所以直接new Test()即可创建Test类中的一个对象。
26              * 话又说回来了,如果在接口中的类不是public static 的那么这个内部类也就是普通的内部类
27              * 在创建Test的对象时,也就需要外部类的对象。关键D是接口,你怎么new 呢?
28              * 所以在的类只能是static 的。
29              */
30             new Test().hello();//输出hello
31         }
32     }
33 }
34 public class A {
35     int a=9;
36     public static  class B{
37 //        int b=a;编译报错
38          void f(){
39             System.out.println("f()");
40         }
41     }
42     public static void main(String[] args) {
43         /**
44          * 从这里你看到了,可以对B直接new ,访问B中的函数f().
45          * 但是如果B没有static这个关键字,即B是普通内部类时,必须这样才能访问到f()
46          * new A().new B().f();
47          */
48         new B().f();
49     }
50 }

 二:比较一下局部内部类[local inner class]和匿名内部类【anonymous inner class ]的区别

1.匿名内部类没有构造犯法,二局部内部类有构造方法。

2.如果在一个外部类有两个或两个以上的方法,返回的都是某个接口或者抽象类的引用,建议把写一个局部内部类。若写成匿名内部类时,代码会显得特别冗长。反之如果一个时,建议用匿名内部类。

代码如下:

 1 package com.qls.anonymouseInnerClass;
 2 interface Six{
 3     void six();
 4 }
 5 public class Ouyangfeng {
 6     private class SixTest implements Six{
 7 
 8         @Override
 9         public void six() {
10             // TODO Auto-generated method stub
11             
12         }
13         
14     }
15     public Six f(){
16         return new SixTest();
17     }
18     public Six g(){
19         return new SixTest();
20     }
21 }

三:内部类的应用:

用内部类实现java的多重继承。

 1 package com.qls.anonymouseInnerClass;
 2 class D{
 3     
 4 }
 5 abstract class E{
 6     
 7 }
 8 class F extends D{
 9     //这是实现多重继承的核心代码。这里是用一个匿名内部类实现
10     E makeE(){
11         return new E() {
12         };
13     }
14 }
15 public class MultipleInherit {
16     public static void takesD(D d){
17         
18     }
19     public static void takesE(E d){
20         
21     }
22     public static void main(String[] args) {
23         // TODO Auto-generated method stub
24         F d = new F();
25         takesD(d);
26         takesE(d.makeE());
27     }
28 
29 }

最后简要介绍一下让一个类继承另一个类中的内部类?以及怎么让一个类中的内部类继承另一个类的内部类呢?

首先是:让一个类继承另一个类中的内部类

 代码如下:

 1 package com.qls.anonymouseInnerClass;
 2 
 3 import com.qls.anonymouseInnerClass.WithInner.Inner;
 4 
 5 class WithInner{
 6     class Inner{
 7         private int a;
 8         public Inner(int a) {
 9             this.a=a;
10         }
11         public Inner() {
12             // TODO Auto-generated constructor stub
13         }
14     }
15 }
16 public class InheritInner extends Inner{
17     public InheritInner(WithInner withInner) {
18         // TODO Auto-generated constructor stub
19         /**
20          * 这句话必须要写。否则编译器会报错。即:外部类的一个对象.super().
21          * 这里的super(),比奥斯Inner的一个默认构造方法。
22          * 如果Inner中比如有这样一个构造方法:public Inner(int a) 
23          * 你现在也可以写成:把withInner.super();改为withInner.super(1);编译器是不会报错的。
24          * 如果没有默认构造方法public Inner() 则这题必须写成:withInner.super(1);的形式。
25          */
26         
27         withInner.super();
28     }
29     public static void main(String[] args) {
30         // TODO Auto-generated method stub
31         WithInner withInner = new WithInner();
32         InheritInner inheritInner = new InheritInner(withInner);
33     }
34 
35 }

 让一个类中的内部类继承另一个类的内部类

代码如下:

 1 package com.qls.anonymouseInnerClass;
 2 /**
 3  * 朱元璋家住凤阳,刘伯温家住青田
 4  * @author 秦林森
 5  *
 6  */
 7 class ZhuYuanZhang{
 8     class FengYang{
 9         private String location;
10 
11         public FengYang(String location) {
12             this.location = location;
13         }
14         
15     }
16 }
17 class LiuBoWei{
18     class QingTian extends ZhuYuanZhang.FengYang{
19         private String location;
20         public QingTian(ZhuYuanZhang zhuYuanZhang, String location) {
21             zhuYuanZhang.super(location);//这句话必须要写。或者会报错,
22             this.location=location;
23         }
24         public void accurate(){
25             System.out.println("一统江山刘伯温 ,家在"+location);
26         }
27     }
28 }
29 public class Test {
30 
31     public static void main(String[] args) {
32         // TODO Auto-generated method stub
33         new LiuBoWei().new QingTian(new ZhuYuanZhang(), "青田").accurate();
34     }
35 
36 }/*Output:
37 一统江山刘伯温 ,家在青田*///:~

 

posted @ 2016-12-30 18:21  技术让世界更精彩  阅读(4157)  评论(0编辑  收藏  举报