浅谈Java内部类(inner class)

浅谈Java内部类(inner class)

Java的内部类可以分为四种:成员内部类(“regular” inner class),静态内部类(static nested class),局部内部类(method-local inner class)和匿名内部类(anonymous inner class)。下面我举几个小例子来看看这些内部类都有什么特点:


成员内部类(”regular” inner class)
首先我们先看下面这段代码:

public class MyOuter {
    String outer = "Myouter!";
    public void outerMethod(){
        System.out.println("Outer!");
    }
    class MyInner{
        String inner = "MyInner!";
        public void inner(){
            System.out.println("inner!");
        }
    }
}

上面的代码中,类MyInner定义在了类Myouter的里面,像MyInner这样的类就是内部类了。同时,我们称类MyOuter为外部类。MyInner类可以看成外部类MyOuter的一个成员,与外部类的其它成员变量和方法并列。定义好了内部类,下面我们来研究研究这个内部类与外部类到底有什么联系。**
首先要知道,要创建一个内部类的实例,必须先拥有一个对外部类的实例去帮助我们进一步访问内部类。
1.在外部类的内部访问内部类:

        MyInner inner = new MyInner();/*创建了一个内部类实例*/
        inner.innerMethod();/*访问内部类实例*/

2.在外部类之外访问内部类
在外部类的外面,我们没有一个能访问到外部类的实例,此时的内部类名字前面要加上外部类的名字,因此我们要像下面这样:

    public static void main(String args[]){
        MyOuter mo = new MyOuter();
        MyOuter.MyInner inner= mo.new MyInner();
        inner.innerMethod();
    }

也可以像下面这样,虽然这样看起来可能有些奇怪:

    public static void main(String args[]){
        MyOuter.MyInner inner=new MyOuter().new MyInner();
        inner.innerMethod();
    }

上面两段代码中,main()函数既可以在外部类MyOuter里,也可以在其他的别的类中。
成员内部类可以直接访问外部类里的成员,即使它们是private的。

public class MyOuter {
    static int a = 8;
    int b = 0;
    private int c = 5;
    class MyInner{
        int b = 2;
        public void innerMethod(){
            //直接访问外部类的静态变量
            System.out.println("这是外部类的静态变量:"+a);
            //内部类与外部类有同名变量,不加外部类的引用,就是访问自己的
            System.out.println("这是我自己的变量:"+b);
            //加上外部类的引用,就是访问外部类的变量
            System.out.println("这是外部类的变量:"+MyOuter.this.b);
            //内部类直接访问外部类私有变量
            System.out.println("这是外部类私有变量:"+c);
        }
    }

    public static void main(String args[]){
        MyOuter.MyInner inner=new MyOuter().new MyInner();
        inner.innerMethod();
    }
}
结果:
这是外部类的静态变量:8
这是我自己的变量:2
这是外部类的私有变量:0
这是外部类私有变量:5

局部内部类(”regular” inner class)
这类内部类是定义在方法里的,只能在一个方法里定义使用,而且,在方法里实例化局部内部类时,实例化的语句一定要放在内部类声明语句的后面!

public class MyOuter {
    int a = 1;
    static int d = 5;
    public void outMethod(){
        int b = 0;
        final int c = 2;
        //MyInner inner = new MyInner();编译器还不认识MyInner呢
        class MyInner{
            public void innerMethod(){
                //可以访问外部类的变量!
                System.out.println(a);
                //可以访问外部类的静态变量!
                System.out.println(d);
                //不可以方位包含在自己外面的方法的非终态变量
                //System.out.println(b);
                //c是final的,直接访问!
                System.out.println(c);
            }
        }
        MyInner inner = new MyInner();
        inner.innerMethod();
    }
    public static void main(String args[]){
        MyOuter outer = new MyOuter();
        //调用外部类的方法,方法里会创建局部内部类的实例。
        outer.outMethod();
    }
}

局部内部类不可以访问相定义它的方法里的非final变量!为什么呢?Sun Ceritified Programmer for Java 6 Study Guide中是这样解释的(截取部分):Think about it,The local variables of the method live on the stack,and exist only for the lifetime of the method.When the method ends,the stack frame is blown away and the variable is history.But even after the method completes,the inner class object created within it might still be alive on the heap.即,该方法的局部变量在堆栈中存在,并且只存在于方法的生命期,当方法结束时,堆栈帧清空,但即使在该方法完成之后,内部类对象在其内部创建的对象仍然可以在堆中生存。如果此时还可以访问它们的话,显然是不正确的。

静态内部类( static nested class)
简单点说,就是内部类的前面加上了static关键字:

public class MyOuter {
    int a = 1;
    static int d = 5;
    static class MyInner{
        int c = 0;
        public void innerMethod(){
            //System.out.println(a);不可以访问外部非静态变量!
            //访问自己类里的非静态变量是允许的!
            System.out.println(c);
            System.out.println(d);
        }
    }
    public static void main(String args[]){
        //不用new MyOuter.new MyInner()了,因为MyInner此时是静态的
        MyOuter.MyInner inner = new MyOuter.MyInner();
        inner.innerMethod();
    }
}

为什么静态内部类不能访问外部的非静态的变量啊?很简单,因为static关键字表示它没有this!在这里可以把静态内部类看成是外部类的一个静态成员。

匿名内部类(anonymous inner class)
匿名内部类没有名字,也不使用class,extends,implements关键字,但是却可以继承一个父类或者实现一个接口,甚至作为一个方法的参数!(不能同时继承一个父类并实现一个接口,也不可以实现多个接口,更不能继承多个父类)。
匿名内部类实现一个接口,这样去看起来有些别扭,但确实是符合语法的:

interface Food{
    public void foodMessage();
}
class Cucumber{
    Food cucumber = new Food(){
        public void foodMessage(){
            System.out.println("Cucumber!");
        }
    };  //用匿名内部类实现了一个接口
    public void showMessage(){
        cucumber.foodMessage();
    }   
}

public class test {
    public static void main(String args[]){
        Cucumber c = new Cucumber();
        c.showMessage();
    }
}
结果:Cucumber!

还可以用匿名内部类实现Thread类:

public class test {
    public static void main(String args[]){
        Thread t = new Thread(){
            public void run(){
                System.out.println("线程开始!");
                for(int i = 1;i < 5;i++)
                    System.out.println(i);
            }
        };
        t.start();
    }
}
结果:
线程开始!
1
2
3
4

匿名内部类作为参数:

class Food{
    public void showMessage(){
        System.out.println("Cucumber!");
    }
}

class MyFood{
    public void foodMessage(Food food){
        food.showMessage();
    }
}

public class test {
    public static void main(String args[]){
        MyFood myFood = new MyFood();
        myFood.foodMessage(new Food());
        //加上花括号和去掉,结果一样!
        myFood.foodMessage(new Food(){});
        myFood.foodMessage(new Food(){
            public void showMessage(){//重写了一下Food中的方法
                System.out.println("Apple!");
            }
        }); 
    }
}
结果:
Cucumber!
Cucumber!
Apple!

以上是个人对内部类的理解,由于个人水平有限,难免有疏忽和不妥的地方,欢迎大家指正!
参考资料:Sun Ceritified Programmer for Java 6 Study Guide
Thinking in java(第三版)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值