Java内部类

一、内部类是什么

将一个类的定义放在另一个类的内部,这就是内部类。

/**
 * 外部类
 */
public class Outer {
    /**
     * 内部类
     */
    class inner{

    }
}

二、为什么要使用内部类

  使用内部类最吸引人的原因是:每个类都能够独立的继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对内部类都没有影响。

  内部类拥有类的基本特征(可以继承父类,实现接口),在实际问题中我们会遇到一些接口无法解决或难以解决的问题,此时我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。

注:内部类可以嵌套内部类,但是这极大的破坏了代码的结构,这里不推荐使用。

除了上面的优点之外还有如下几点:

  • 内部类可以用多个实例,每个实例都有自己的状态信息,并且于其他外围对象的信息相互独立。

  • 内部类并没有令人迷惑的"is-a"关系,他就是一个独立的个体。

  • 内部类提供了更好的封装,除了外围类,其他类都不能访问。

  • 创建内部类对象的时刻并不依赖与外围类对象的创建。

  具体来说,内部类信息(属性、方法)可以和外部类重名;内部类是具有类的基本特征的独立实体;可以利用访问修饰符隐藏内部类的实施细节,提供了更好的封装;静态内部类使用时可以直接使用,不需先创造外部类。

三、内部类的共性

  1. 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。

  1. 内部类不能用普通的方式访问,内部类是外部类的一个成员,因此内部类可以自由访问外部类的成员变量,无论是否是private的。

  2. 内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量。

四、使用内部类

(一)、成员内部类

public class Outer {
    int id = 1;
    /**
     * 成员内部类
     */
    class Inner{
        private int id = 2;
        public void say(){
            // 访问的是内部类的变量
            System.out.println(id); // 2
            // 访问外部类的变量
            System.out.println(Outer.this.id); // 1
            System.out.println("Inner.say");
        }
    }

    public void show() {
        // 外部类访问内部类的成员需要先创建一个成员内部类的对象
        Inner inner = new Inner();
        System.out.println(inner.id);
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        // 访问类的成员
        System.out.println(outer.id);
        // 创建内部类的实例,需要外部类的实例
        Outer.Inner1 inner1 = new Outer().new Inner();
        inner1.say();
    }
}

  当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员,如果要访问外部类的同名成员,需要以下形式进行访问:

外部类.this.成员变量
外部类.this.成员方法

  虽然成员内部类可以无条件的访问外部类的成员,但是外部类想要访问成员内部类,就不可以直接访问了,需要先创建一个成员内部类的对象,在通过指向这个对象的引用来访问。

  在其他类使用成员内部类有两种方式:

方式一:
Outer.Inner inner = new Outer().new Inner();

方式二:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

(二)、静态内部类(静态嵌套类)

public class Outer {
    int id = 1;
    static int id2 = 2;

    /**
     * 静态成员内部类
     */
    static class Inner{
        public void say(){
            System.out.println("Inner.say");
            // 只能访问外部类的静态信息(成员变量和方法)
            System.out.println("Outer.id2=" + id2);
        }
        public static void show() {
            System.out.println("Inner.show");
        }
    }
    
    public static void main(String[] args) {
        // 创建静态内部类实例
        Outer.Inner inner = new Outer.Inner();
        inner.say();
        // 访问静态内部类的静态方法,Inner类被加载,此时外部类未被加载,独立存在,通过类名.方法即可访问。
        Outer.Inner.show();
    }
}

  静态内部类也是定义在类里面的类,在类前面多了一个static关键字,内部类可以独立存在,不依赖与其他外围类,它不能使用外部类的非静态成员变量或方法。

(三)、方法内部类

public class Outer {
    int id = 1;

    public void work(){
        final int id1=1;
        int id2 = 2;
        /**
         * 方法内部类,只能在方法内部使用
         */
        class Inner{
            public Inner(){
                System.out.println(id1);
                // 报错,Variable 'id2' is accessed from within inner class, needs to be declared final
                // 变量'id2'是从内部类中访问的,需要声明为final
//                System.out.println(id2);
                System.out.println("method work Inner created");
            }
            void work(){
                System.out.println("method Inner.work");
            }
        }
        // 方法内部类只能在方法中使用,在方法中创建实例并调用内部类的方法
        Inner inner = new Inner();
        inner.work();
    }
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.work();
    }
}

方法内部类的限制:

  • 类前不能有访问修饰符。

  • 仅在此方法中使用。

  • 无法创造静态信息。

  • 只能访问final变量和形参

(四)、匿名内部类

public class Outer {
    int id = 1;

    /**
     * 匿名内部类,一个没有名称的实现了IAnimal接口的类
     */
    IAnimal animal = new IAnimal() {
        @Override
        public void say() {
            System.out.println("匿名内部类的say方法");
        }
    };

    public static void main(String[] args) {
        Outer outer = new Outer();
        
        // animal是Outer类的一个成员,这个成员是匿名内部的实例
        outer.animal.say();
    }
}

  在使用匿名内部类时,这个new之后的类首先是要存在的,其次我们要重写new后的类的某个或某些方法。匿名内部类没有构造方法。

  使用匿名内部类有一个前提条件:必须继承一个父类或实现一个接口,但最多只能继承一个父类或实现一个接口,new之后的类就是匿名内部类要继承的父类或实现的接口;匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建内部类的对象。因此不允许将匿名内部类定义成抽象类。

posted @ 2021-03-14 14:04  逍遥客灬  阅读(98)  评论(0编辑  收藏  举报