Java——内部类(InnerClass)

package InnerClass;

public class InnerClassTest {    //主类
    public static void main(String[] args) {
        OuterClass outer = new OuterClass(true);
    }
}
package InnerClass;

public class OuterClass {    //外部类
    private boolean a;
    OuterClass(boolean a){
        this.a = a;
        System.out.println("我是外部类!");
        InnerClass inner = new InnerClass();
    }
    public class InnerClass{    //内部类
        InnerClass(){
            if(a) {
                System.out.println("我是内部类!a:"+a);
            }
        }
    }
}

1. 内部类的特殊语法规则:↓

外部类引用的正确语法:OuterClass.this
例如:

if(OuterClass.this.a) {
    System.out.println("我是内部类!a:"+a);
}

反过来,也可以new内部类的构造器
正确语法:outerObject.new InnerClass();
例如:

OuterClass(boolean a){
    this.a = a;
    System.out.println("我是外部类!");
    InnerClass inner = new InnerClass();    //←这里
}

外部类作用域外这样引用内部类:OuterClass.InnerClass
例如:

OuterClass.InnerClass inner = outer.new InnerClass();

2. 内部类是否有用、必要和安全
内部类是一种编译现象,虚拟机无关。编译器将会把内部类翻译成$(美元符号)分隔外部类名与内部类名的常规类文件。

3. 局部内部类
仔细看最上面的代码会发现InnerClass这个类只在OuterClass构造器中引用了一次
这种情况可以在一个构造函数(方法也可以)中定义一个局部类
例如:

OuterClass(boolean a){
    this.a = a;
    System.out.println("我是外部类!");
    InnerClass inner = new InnerClass();
    class LocalClass{
        LocalClass(){
            System.out.println("我是局部内部类");
        }
    }
    LocalClass local = new LocalClass();
}

4. 外部方法访问变量
与其他类相比较,局部类还有一个优点。它不仅能访问包含它们的外部类,还能访问局部变量。不过那些局部变量都必须事实上为Final。这说明它们一旦赋值就不会改变。
这个一个b()方法:

public void b(boolean a) {
    class LocalClass{
        LocalClass(){
            System.out.println("我是局部内部类"+**a**);
        }
    }
    a = true;
    LocalClass local = new LocalClass();
}

这个方法看着没什么问题,但是是错误的,局部类在访问a参数时提示了一个错误:

Local variable a defined in an enclosing scope must be final or effectively final

谷歌翻译:在封闭范围中定义的局部变量a必须是最终的或有效的最终
提示说局部变量a要是最终的或有效的最终,也就是变量a(其实a是b()方法的参数)不能改变,这也就说明了局部内部类访问的变量(参数)要设置为final。
正确的代码:

public void b(final boolean a) {
        class LocalClass{
            LocalClass(){
                System.out.println("我是局部内部类"+a);
            }
        }
//        a = true;    a参数设置为final就不能有这句代码
        LocalClass local = new LocalClass();
    }

5. 匿名内部类

假如只创建这个类的一个对象,就不必命名了。这种类被称为匿名内部类(anonymous inner class)。

interface AnonymousInnerClass {        //定义一个接口
    void anonymous();
}
public void anonymousInnerClass() {        //方法
    AnonymousInnerClass a = new AnonymousInnerClass() {    //方法中的匿名内部类
        @Override
        public void anonymous() {
            System.out.println("匿名内部类");
        }
    };
    a.anonymous();
}

通常格式为:

new SuperType(construction parameters){
    inner class methods data
}

Supertype可以是一个接口也可以是一个类,于是内部类就要扩展它
由于构造器名必须与类名一致,而匿名内部类没有类名,所以匿名内部类没有构造函数。
取而代之的是,将构造器参数传递给超类构造器,尤其是在内部了实现接口时候,不能有任何构造参数。
多年来,java程序员习惯的做法是用匿名内部类实现事件监听和其他回调。如今最好还是用Lambdab表达式。

技巧:
双括号初始化,利用内部类语法
假如需要构造一个泛型类数组列表,并且传递到一份方法

ArrayList list = new ArrayList();
list.add("Hello");
list.add("World");
invite(list);

如果不在需要这个数组列表,最好让它作为一个匿名列表。
方法如下:

invite(new ArrayList() {{add("Hello");add("World");}});

6. 静态内部类
有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类对象。为此,可以将内部类声明为static,以便取消产生的引用。
静态内部类-比较两个数的大小:

package InnerClass;

public class StaticInnerClass {
    public static void main(String[] args) {
        ArrayAlg.minMax(15, 6);
    }
}
class ArrayAlg{
    public static class Pair{
        Pair(int a,int b){
            System.out.println("Max:"+(a>b?a:b));
            System.out.println("Min:"+(a

你可能感兴趣的:(JAVA)