java 内部类

类都对应于一个独立的Java源文件,但一个类还可以放在另一个类的内部,称之为内部类,相对而言,包含它的类称之为外部类。

内部类与包含它的外部类有比较密切的关系,而与其他类关系不大,定义在类内部,可以实现对外部完全隐藏,可以有更好的封装性,代码实现上也往往更为简洁。

内部类只是Java编译器的概念,对于Java虚拟机而言,它是不知道内部类这回事的,每个内部类最后都会被编译为一个独立的类,生成一个独立的字节码文件。

在Java中,根据定义的位置和方式不同,主要有4种内部类。   

▪静态内部类。   

▪成员内部类。   

▪方法内部类。 

▪匿名内部类。

其中,方法内部类是在一个方法内定义和使用的;匿名内部类使用范围更小,它们都不能在外部使用;成员内部类和静态内部类可以被外部使用,不过它们都可以被声明为private,这样,外部就不能使用了。

静态内部类

public class Outer {

    private static int shared = 100;

    public static class StaticInner {//静态内部类

        public void innerMethod() {
            System.out.println("inner " + shared);
        }
    }

    public void test() {
        StaticInner si = new StaticInner();
        si.innerMethod();
    }
}

class Test {
    public static void main(String[] args) {
        Outer.StaticInner si = new Outer.StaticInner();//通过“外部类.静态内部类”的方式使用
        si.innerMethod();
    }
}

静态内部类与静态变量和静态方法定义的位置一样,也带有static关键字,只是它定义的是类

静态内部类的使用场景是很多的,如果它与外部类关系密切,且不依赖于外部类实例,则可以考虑定义为静态内部类。

也可以看一些在Java API中使用静态内部类的例子:   

▪Integer类内部有一个私有静态内部类IntegerCache,用于支持整数的自动装箱。   

▪表示链表的LinkedList类内部有一个私有静态内部类Node,表示链表中的每个节点。   

▪Character类内部有一个public静态内部类UnicodeBlock,用于表示一个Unicode block。

 

成员内部类

与静态内部类相比,成员内部类没有static修饰符,少了一个static修饰符,含义有很大不同

public class Outer {
    private int a = 100;

    private void action() {
        System.out.println("action");
    }

    public void test() {
        Inner inner = new Inner();
        inner.innerMethod();
    }

    public class Inner {
        public void innerMethod() {
            System.out.println("outer a " + a);//直接访问外部类私有实例变量a
            Outer.this.action();//通过“外部类.this.xxx”的方式引用外部类的实例变量和方法
        }
    }
}

class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();//创建内部类对象的语法是“外部类对象.new内部类()”
        inner.innerMethod();
    }
}

成员内部类有哪些应用场景呢?如果内部类与外部类关系密切,需要访问外部类的实例变量或方法,则可以考虑定义为成员内部类。外部类的一些方法的返回值可能是某个接口,为了返回这个接口,外部类方法可能使用内部类实现这个接口,这个内部类可以被设为private,对外完全隐藏。

比如,在Java API的类LinkedList中,它的两个方法listIterator和descendingIterator的返回值都是接口Iterator,调用者可以通过Iterator接口对链表遍历,listIterator和descend-ingIterator内部分别使用了成员内部类ListItr和DescendingIterator,这两个内部类都实现了接口Iterator。

 

方法内部类

内部类还可以定义在一个方法体中。

public class Outer {
    private int a = 100;

    public void test(final int param) {
        final String str = "hello";
        final String[] str2 = new String[]{"hello"};
        class Inner {
            public void innerMethod() {
                System.out.println("outer a " + a);//直接访问了外部私有实例变量a
                System.out.println("param " + param);
                System.out.println("local var " + str);
                str2[0] = "hello world";
            }
        }
        Inner inner = new Inner();
        inner.innerMethod();
        System.out.println(str2[0]);
    }
}

class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.test(1);
    }
}

方法内部类可以用成员内部类代替,至于方法参数,也可以作为参数传递给成员内部类。不过,如果类只在某个方法内被使用,使用方法内部类,可以实现更好的封装。

 

匿名内部类

匿名内部类没有单独的类定义,它在创建对象的同时定义类,语法如下:

new 父类(参数列表) {   

  //匿名内部类实现部分

}

或者

new 父接口() {   

  //匿名内部类实现部分

}

匿名内部类是与new关联的,在创建对象的时候定义类,new后面是父类或者父接口,然后是圆括号(),里面可以是传递给父类构造方法的参数,最后是大括号{},里面是类的定义。

匿名内部类跟详细的介绍: https://www.cnblogs.com/ooo0/p/12582296.html

匿名内部类能做的,方法内部类都能做。但如果对象只会创建一次,且不需要构造方法来接受参数,则可以使用匿名内部类,这样代码书写上更为简洁。

 

文章参考来源:java编程的逻辑

 

posted @ 2020-04-16 13:47  草木物语  阅读(174)  评论(0编辑  收藏  举报