前言

我们在描述事物的时候,事物的内部还有事物,这个内部事物还要访问外部事物中的内容时。那么,这个内部事物就可以用内部类来描述。内部类也叫内置类,嵌套类。

正文

一,内部类的形式以及对外访问的方式

顾名思义,内部类就是一个类嵌套在另一个类中。内部类可以在外部类的成员位置,也可以在外部类的局部位置,也就是成员函数中。

一般,我们在定义内部类时设置其访问权限为私有private,并在外部类中提供访问它的方法。下面来看例子:

package com.jimmy.basicInnerClass;

class OuterClass{ // 外部类

    private int num = 5;  // 外部类的成员变量

    private class InnerClass{ // 私有的内部类,定义在外部类的成员位置

        public void innerMethod() { // 内部类的成员方法
            System.out.println("你好啊,我是内部类的方法.."+num);  // 内部类可直接访问外部类的成员
        }
    }

    public void outerMethos() { // 外部类方法,实例化内部类对象,并调用其方法
        OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
        innerClass.innerMethod();
    }
}
public class InnerClassDemo1 {

    public static void main(String[] args) {

        OuterClass outerClass = new OuterClass();  
        outerClass.outerMethos(); // 通过外部类方法访问内部类成员,就像get方法访问私有成员变量一样。
    }   
}

上面代码的输出结果:

你好啊,我是内部类的方法..5

值得注意的是,外部类也是一个完整的类,在编译的时候也有class文件生成。上面这个文件就会产生3个class文件。内部类的名字比较特别,会标明所属的外部类名。

OuterClass.class
OuterClass$InnerClass.class
InnerClassDemo1.class

上面的代码中,我们直接在外部类的方法中创建了内部类对象,并调用了内部类的方法,这样就显得有点越俎代庖了。我们想自己拿到内部类的对象来调用内部类中的方法。但是,内部类是私有的,我们不能直接new出内部类的对象,虽然可以用“new Outer().new Inner()”来实例化内部类对象,但是却没有可用的对象名来接收它(因为内部类对外不可见)。怎么解决呢?我们知道,内部类也是类,同样具有类的继承特性,所以我们将内部类继承自外部的某个类,或者实现外部的某个接口,就可以通过多态来接收内部类对象了,代码如下:

package com.jimmy.basicInnerClass;

interface Inter{  // 外部接口
    public void innerMethod();
}

class Outer3{

    private int num = 5;  

    private class Inner implements Inter{  // 内部类实现接口,并实现其中的方法。

        @Override
        public void innerMethod() {
            System.out.println("你好啊,我是内部类的方法...."+num);
        }           
    }

    public Inner getInnerObject() {   // 外部类函数只返回内部类对象,并不越俎代庖去调用方法
        return new Inner();
    }

}
public class InnerClassDemo5 {
    public static void main(String[] args) {
        Outer3 outer3 = new Outer3();
        Inter innerObject = outer3.getInnerObject();  // 私有的内部类对象可以用多态性来接收
        innerObject.innerMethod();
    }
}

上述代码的输出结果如下:

你好啊,我是内部类的方法....5

这样一来,私有化的内部类对象就可以通过多态在外部被持有了,这也符合java中的“面向接口编程”的要求。

二,匿名内部类

从上面的代码可以看出,内部类在外部类的里面,并可以实现外部接口,然后实现接口中的方法。有的时候,外部接口中的有些实现只用到一次,也就没必要特意写一个类来实现接口,可以使用匿名内部类的形式来实现,匿名内部类在外部类的局部位置,即方法中。

匿名内部类必须继承一个父类或者实现一个接口。匿名内部类其实就是一个带有内容的子类对象,格式为:new 接口/父类(){子类内容}。这个格式比较新颖,一般来说,我们在”new Object();”后会以“;”结束。现在new Object(){}后面跟着的是一对“{}”,表示这是一个子类结构体,接口的实现就在这里面写。看个例子:

package com.jimmy.basicInnerClass;

interface InterInner{ // 外部接口以及方法
    void innerMethod1();
    void innerMethod2();
}

class Outer2{

    private int num = 1;

    public void outerMethod(){

        new InterInner() {  // 这就是匿名内部类,大括号里面是接口的实现
            @Override
            public void innerMethod1() {  // 实现方法1
                System.out.println("你好,我是匿名内部类的方法1..."+num);
            }

            @Override
            public void innerMethod2() {  // 实现方法2
                // TODO Auto-generated method stub
                System.out.println("你好,我是匿名内部类的方法2..."+num+1);
            }
        }.innerMethod1();  // new出对象,就能调用函数

    }
}

public class InnerClassDemo4 {
    public static void main(String[] args) {

        Outer2 outer2 = new Outer2();
        outer2.outerMethod();
    }
}

上面代码new出匿名内部类的对象后直接调用了实现后的方法。代码输出:

你好,我是匿名内部类的方法1...1

我们也可以提供匿名内部类的对象,并在外部调用匿名内部类的方法,代码如下:

package com.jimmy.basicInnerClass;

interface InterInner2{ // 外部接口以及方法
    void innerMethod1();
    void innerMethod2();
}

class Outer4{

    private int num = 1;

    public InterInner2 outerMethod(){

        InterInner2 inner2 = new InterInner2() {  // 接收匿名内部类对象,大括号里面是接口的实现
            @Override
            public void innerMethod1() {  // 实现方法1
                System.out.println("你好,我是匿名内部类的方法1..."+num);
            }

            @Override
            public void innerMethod2() {  // 实现方法2
                // TODO Auto-generated method stub
                System.out.println("你好,我是匿名内部类的方法2..."+(num+1));
            }
        };

        return inner2;
    }
}
public class InnerClassDemo4_1 {
    public static void main(String[] args) {
        Outer4 outer4 = new Outer4();
        InterInner2 inner2 = outer4.outerMethod();
        inner2.innerMethod1();
        inner2.innerMethod2();
    }
}

代码输出为:

你好,我是匿名内部类的方法1...1
你好,我是匿名内部类的方法2...2

三,匿名内部类的常见用法

匿名内部类只是对接口的一次实现和调用,用完就被回收了。其使用可以像上面那样,将匿名内部类放在外部类的方法中,在外面调用外部类的方法,得到内部类对象进而调用内部类的方法。如果内部类不需要访问外部类的成员变量,就可以直接将其放在main方法中。如下示例:

package com.jimmy.niMingInnerClass;

interface movable{
    public void run();
}

public class NimingInnerClassDemo1 {
    public static void main(String[] args) {

        new movable() { 
            @Override
            public void run() {
                System.out.println("i am running...");
            }
        }.run();
    }
}

输出结果:

i am running...

实际中使用匿名内部类有很多,常见的就是创建线程时使用匿名内部类,如下示例:

package com.jimmy.niming;

public class NiMingNeibuleiTest {
    public static void main(String[] args) {

        new Thread(new Runnable() { // 线程1  
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"..."+i);
                }
            }
        }).start();

        new Thread(new Runnable() { // 线程2      
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"..."+i);
                }
            }
        }).start();
    }
}

输出结果:

2个线程交替执行

总结

只学会了内部类的形式和对外调用方法,以及匿名内部类如何实现简化代码。并不是很理解内部类的好处,以后编程学习过程中慢慢体会。