Java内部类详解

1.何为内部类

在类Outer的内部定一个类Inner,我们把类Inner称作内部类,类Outer称作外部类。内部类可以分为成员内部类、静态内部类、局部内部类和匿名内部类

2.成员内部类

成员内部类定义在另一个类的内部。

public class Outer {
    // 定义一个成员内部类
    class Inner {
    }
}

成员内部类的特点:

1) Inner在编译之后以独立的class文件存在,class文件的命名方式为:Outer$Inner.class

2) Inner的实例对象不能单独存在,必须依附于Outer的实例对象。(Inner实例对象存在一个隐式引用,指向创建它的Outer类的实例对象)

3) Inner可以访问Outer中属性和方法,包括私有属性和私有方法。

4) Inner类具有默认的包访问权限,只有所在包的类可以访问。

5) Inner类中不能存在static修饰属性和方法(静态常量除外),是Java语法的一种约束。

代码示例:

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

public class Outer {
    private String name;
    private int age;

    private void sayHello() {
        System.out.println("Hello World");
    }

    class Inner {
        void test() {
            // 访问私有属性
            System.out.println(age);
            System.out.println(Outer.this.name);
            // 访问私有方法
            sayHello();
        }
    }
}

观察上述代码,要实例化一个Inner对象,我们必须首先实例化一个Outer对象,然后通过Outer的实例对象来实例化Inner对象。

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

这是因为Inner实例对象除了持有一个this指向自己,还隐式的持有一个Outer的实例对象,可以用Outer.this访问这个实例。

3.静态内部类

静态内部类定义在另一个类的内部,并用static关键字修饰。

静态内部类的特点:

1) StaticInner在编译之后以独立的class文件存在,class文件的命名方式为:Outer$StaticInner.class

2) StaticInner的实例对象可以独立存在,不再依附于Outer的实例对象。

3) StaticInner只能访问Outer中static修饰属性和方法,包括私有属性和私有方法。

4) StaticInner类具有默认的包访问权限,只有所在包的类可以访问。

5) StaticInner类中可以存在static修饰属性和方法。

代码示例:

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

public class Outer {
    private static String name;

    static class StaticInner {
        private static int age = 18;
        
        void test() {
            System.out.println(name);
        }
    }
}

观察上述代码,StaticInner类的实例对象可以独立存在,不再依赖于Outer类的实例对象。

4.局部内部类

局部内部类与成员内部类类似,但其定义在方法之中,作用范围仅限于该方法中。

局部内部类的特点:

1) LocalInner在编译之后以独立的class文件存在,class文件的命名方式为:Outer$1LocalInner.class

2) LocalInner实例对象存在一个隐式引用,指向创建它的Outer类的实例对象。

3) LocalInner除了可以访问Outer中属性和方法,包括私有属性和私有方法,还有访问所处方法中局部变量,但这些变量实际上是final修饰,不可再改变。

4) LocalInner只能在定义它的方法中访问

5) LocalInner类中不可以存在static修饰属性和方法,静态常量除外。

代码示例:

public class Outer {
    private String name;
    private int age;

    private void sayHello() {
        System.out.println("Hello World");
    }

    public void localInnerClass() {
        String localName = "localInnerClass";
        class LocalInner {
            public void test() {
                System.out.println(localName);
                System.out.println(name);
                System.out.println(Outer.this.age);
                sayHello();
            }
        }
        LocalInner localInner = new LocalInner();
        localInner.test();
    }
}

5.匿名内部类

为什么叫匿名内部类呢?因为匿名内部类不存在类名。之所以我们要定义匿名内部类,是因为我们在使用的时候通常不关系类名,可以省略掉定义类的过程。

匿名内部类的特点:

1) 匿名内部类在编译之后以独立的class文件存在,class文件的命名方式为:外部类名称$数字编号.class,编号从1开始,文中生成的class文件名为Outer$1.class

2) 匿名内部类实例对象存在一个隐式引用,指向创建它的Outer类的实例对象。

3) 匿名内部类可以访问Outer中属性和方法,包括私有属性和私有方法。

4) 匿名内部类类具有默认的包访问权限,只有所在包的类可以访问。

5) 匿名内部类类中不能存在static修饰属性和方法(静态常量除外),是Java语法的一种约束。

代码示例:

public class Test {
    public static void main(String[] args) {
        new Outer().sayHello();
    }
}

@FunctionalInterface
public interface Runnable {
    
    public abstract void run();
}

public class Outer {
    private String name;
    private int age;

    public void sayHello() {
        new Runnable() {
            private String anonymousName;

            private void test() {
                System.out.println(name);
                System.out.println(Outer.this.age);
            }

            @Override
            public void run() {
                System.out.println("我是一个匿名内部类");
            }
        }.run();
    }
}

观察上述代码,我们使用了并发编程常用的Runnable接口,接口是不能被实例化,我们想要得到一个Runnable接口的实例,但是又不想创建一个类来实现它,就可以采用匿名内部类的方式。

6.为什么需要内部类

  • 内部类可以访问外部类的属性和方法,包括私有属性和方法。
  • Java语言具有单继承的特性,内部类可以继承于其他类,达到类似于多继承的效果。
  • 将类隐藏起来,控制类的访问权限。外部类只能使用public和默认的访问权限,内部类除了可以使用外部类的访问权限,还可以使用private和protected。
  • 匿名内部类可以帮助我们减少定义类的步骤。

你可能感兴趣的:(java,java)