Java内部类以及使用场景

5,761 阅读3分钟
原文链接: www.cnblogs.com

所谓内部类,即定义在另一个类中的类。那么,为什么会有内部类这个概念,他的使用场景又是什么呢?首先,来看一下内部类的特点:

1. 它体现了一种代码的隐藏机制和访问控制机制,内部类与所在外部类有一定的关系,往往只有该外部类调用此内部类,所以没有必要专门用一个Java文件存放这个类。

public class Outer {
  private int num; 
  private class Inner {
    private int num;
  }
}

一般的类是不允许用private修饰符的,但是内部类却可以,该实例中,类Inner只对Outer可见,其他的类无法访问的到Inner类。

注意,这里有个例外,如果内部类的访问修饰符被设定为public,那么它是可以被其他类使用的,但是必须经由外部类来实例化内部类。

public class Outer {
    private int num = 1;

    public class Inner {
        private int num = 2;
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        System.out.println(inner.num);
    }
}

2. 它包含有一个对外部类的this指针,从而可以访问外部类的所有元素,包括所有public/private的成员和方法

public class Outer {
    private int num = 1;

    public class Inner {
        private int num = 2;
        private void func () {
            System.out.println(Outer.this.num);
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        inner.func();
    }
}

另一方面,反向的,外部类对内部类的所有元素也都有访问权,包括内部类的私有成员和方法:

public class Outer {
    private int num = 1;

    public class Inner {
        private int num = 2;
    }

    public void func () {
        Inner inner = new Inner();
        System.out.println(inner.num);
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.func();    // 2
    }
}

 

分类:

一、成员内部类

当某个类除了他的外部类,不会被其他类使用时,使用成员内部类。这种情况下,内部类依附于外部类而存在,原因可能有: 1. 不可能有其他类使用该内部类。 2. 该内部类不能被其他类使用,可能会导致错误。这是内部类使用比较多的一个场景。

1) 外部类可以直接访问内部类的成员和方法,但是必须先创建一个内部类的对象,再通过该对象使用其成员和方法。

2) 内部类可以访问外部类的成员和方法,但是要注意,当内部类拥有和外部类相同的成员或方法时,会发生隐藏现象,默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式访问:外部类.this.成员变量/方法

3) 内部类只是一个编译时的概念,一旦编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类,编译完后会生成Outer.class和Outer$Inner.class两个类

4) 成员内部类与普通的成员没什么区别,可以与普通成员一样进行修饰和限制

public class Outer {
    private int num = 1;
    private int num1 = 10;

    public class Inner {
        private int num = 2;
        public void func () {
            System.out.println(Outer.this.num);
            System.out.println(num1);
        }
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
        inner.func();
    }
}

 

二、局部内部类

 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。局部内部类就像方法里面的局部变量一样,是不能有public、protected、private及static修饰符的。

public class Outer {
    private int num = 1;
    private int num1 = 10;

    public void func () {
        class Inner {
            private int num = 2;
        }
        Inner inner = new Inner();
        System.out.println(inner.num);
    }


    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.func();
    }
}

 

三、静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,它不持有指向外部类对象的引用this,并且它不能使用外部类的非static成员或方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体对象。它唯一的作用就是随着类的加载(而不是随着对象的产生)而产生。

public class Outer {

    static class Inner {
        public Inner () {

        }
    }

    public static void main(String[] args) {
        Outer.Inner innner = new Outer.Inner();
    }
}

 

 

四、匿名内部类

匿名内部类应该是平时我们编写代码时用的最多的,在编写事件监听的代码时匿名内部类不但方便,而且使代码更加容易维护。匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outer$1.class。一般来说,匿名内部类用于集成其他类或者实现接口,并不需要增加额外的方法,只是对集成方法的实现或是重写。

public class Outer {

    public void func () {
        System.out.println("1");
    }


    public static void main(String[] args) {
        Outer inner = new Outer() {
            public void func () {
                System.out.println("2");
            }
        };
        inner.func();
    }
}


总结:

1. 每个内部类都能独立的集成一个接口的实现,所以无论外部类是否已经集成了某个(接口)实现,对于内部类都没有影响。内部类使得多重集成的解决方案变得完整。

2. 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

3. 方便编写时间驱动程序。

4. 方便编写线程代码。