JAVA基础知识——什么是内部类_欢迎访问起点编程官网
欢迎访问起点编程官网
0519-86288177
13921547554

JAVA基础知识——什么是内部类

发布日期:2021-05-27 23:02:05 浏览次数:

基本概念:


JAVA基础知识——什么是内部类(图1)


所谓内部类就是在一个类的内部再申明一个类。

凡是申明在类的成员位置的就是成员内部类,凡是申明在方法或者代码块中的类都是局部内部类。

成员内部类

非静态成员内部类

基本写法

案例:

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午9:16:28 */public class Outer {
    private String name;
    public void method() {
        System.out.println("这是外部类的非静态成员方法");
    };
    public static void stMethod() {
        System.out.println("外部内的静态成员方法");
    }

    //非静态成员内部类    public class Inner{
        private int age;
        public void innerMethod() {
            System.out.println("内部类的非静态成员方法");
        }
        //非静态内部类中不能申明静态方法//      public static void innerStMethod() {//          System.out.println();//      }    }}

非静态成员内部类的对象创建。

如果要创建内部类的对象,则必须先有外部类对象。

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午9:21:29 */public class Test {
    public static void main(String[] args) {
        //首先创建外部内对象        Outer outer = new Outer();
        //使用外部内对象创建内部类对象        Outer.Inner inner = outer.new Inner();
        //使用匿名对象        Inner inner1 = new Outer().new Inner();
        inner.innerMethod();
    }}

tips:

在非静态内部类中不能申明静态方法。 在非静态的内部类中不能申明静态的成员变量,但是可以申明常量。

内部类的一些特征

编译:所有的成员内部类都会被编译成一个独立的字节码文件,文件的名称为“外部类的类名$内部类类名.class”。


JAVA基础知识——什么是内部类(图2)


访问权限问题

成员的内部类可以使用任何访问修饰符,表现的状态和其他成员一样。

在内部类中可以访问外部类的所有成员 在非静态成员内部类中可以调用所有的外部类方法 在非静态成员内部类中使用外部类的this的时候,语法是:外部类类名.this。


JAVA基础知识——什么是内部类(图3)



静态成员内部类

案例:

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午9:39:34 */public class Outter {
    //静态成员内部类    public static class Inner{
        private String name;
        public void method() {
            System.out.println("内部类的非静态方法");
        }
        public static void stMethod() {
            System.out.println("内部类的静态方法");
        }
    }}/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午9:40:56 */public class Test {
    public static void main(String[] args) {
        //创建静态内部类对象不需要外部类对象        Outter.Inner inner = new Outter.Inner();
        inner.method();
        //直接调用静态成员内部类的静态方法        Outter.Inner.stMethod();
    }}
静态内部类中可以申明静态和非静态的方法和成员变量。
静态内部类中可以调用外部类的任何静态的成员变量和方法,但是不能调用任何非静态的方法和变量,更不能使用外部类的this对象。


JAVA基础知识——什么是内部类(图4)



局部内部类

申明在类的代码块中的类就是局部内部类。

案例:

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:03:28 */public class Outter {

    public void method() {
        System.out.println("外部类的成员方法");
        class Inner{
            private String name;
            public void method() {
                System.out.println("局部内部类的方法");
            }
        }
        //局部内部类的使用访问就是这个方法        Inner inner = new Inner();
        inner.method();
    }
    public static void main(String[] args) {
        Outter outer = new Outter();
        outer.method();
    }}
局部内部类的使用范围就是局部范围,就是申明的范围内。 局部内部类无法使用任何访问修饰符修饰,也不能修饰为static

局部内部类访问外部类中的成员或者局部变量。

在局部内部类中可以访问外部了的任何成员。可以使用外部类的this对象等等。 在局部内部类中如果要使用外部类的局部变量,如果jdk是1.7之前,则局部变量必须是final修饰的,1.7之后就不需要了,其实就是默认就是final。


JAVA基础知识——什么是内部类(图5)


局部内部类在方法执行结束之后,内对象依然存在的情况:

public class A {
    public void show() {

    }}/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:19:08 */public class Outter {
    public A getA() {
        int x = 10;
        class B extends A{
            public void show() {
                System.out.println(x);
            }
        }
        B b = new B();
        return b;
    }

    public static void main(String[] args) {
        A a = new Outter().getA();
        System.out.println(a);
        a.show();
    }}

局部内部类的编译情况:

源代码:

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:25:00 */public class Outter {
    public void methoda() {
        class Inner{}
    }
    public void methodb() {
        class Inner{}
    }}

编译后的情况:


JAVA基础知识——什么是内部类(图6)


局部内部类编译后的类名是:外部类类名$index内部类类名.class 。 这里的index是编译器根据方法的编译前后顺序给的索引。

抽象内部类和内部接口

[1]内部类能不能申明为抽象类?

成员非静态内部类可以是抽象类,但是只能被内部类继承


JAVA基础知识——什么是内部类(图7)


[2]成员静态内部类可以被申明为抽象类.

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:34:10 */public class Outter {
    public abstract static class Inner{
    }
    //继承内部抽象类    class B extends Inner{
    }}//外部的其他类可以继承抽象静态内部类class A extends Outter.Inner{}

[3]局部内部类,局部内部类可以申明为抽象的。

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:34:10 */public class Outter {

    public void method() {
        abstract class Inner{

        }
        //继承局部的抽象内部类        class A extends Inner{

        }
    }}

[4]接口内部申明内部接口

接口中可以申明:内部接口,成员内部类,局部内部类。

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:42:06 */public interface IOutter {
    //内部接口    public interface IInner{

    }
    //内部类    public class AInner {

    }
    //静态成员内部类    public static class SAInner{

    }
    default void method() {
        //局部内部类        class Inner{

        }
    }}

测试:

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午10:47:37 */public class Test {
    public static void main(String[] args) {
        //创建接口中的非静态成员内部类对象        IOutter outter = new St();
        IOutter.AInner ainner = new AInner();
        //创建接口的静态成员内部类对象        IOutter.SAInner sainner = new SAInner();
        //创建内部接口对象        IOutter.IInner iinner = new Geek();
    }}//实现外部接口class St implements IOutter{}//实现内部接口class Geek implements IOutter.IInner{}
接口中的静态方法:jdk8的新特性

匿名内部类

所谓匿名内部类就和匿名对象一样,没有名字。

常用来直接继承抽象类,或者实现接口。

匿名内部类只能使用一次,不能使用第二次。

案例:使用匿名内部类实现一个线程。

/** * @author 戴着假发的程序员 * @TODO 匿名内部类 * @organization 飞虎队 2020年8月31日 上午11:07:06 */public class Main {
    public static void main(String[] args) {
        new Main().mt();
    }

    public void mt() {
        // 开启一个线程 线程类:继承Thread,实现Runnable接口        // 使用匿名内部类继承Thread类        new Thread() {
            public void run() {
                System.out.println("匿名内部类继承Thread类实现一个线程类");
                method();
            }

            public void method() {
                System.out.println("匿名内部类自定义的方法");
            }
        }.start();
        // 使用匿名内部类实现Runnable接口        new Thread(new Runnable() {
            private String name = "runnable";

            public void run() {
                System.out.println("匿名内部类实现Runnable接口实现一个线程类");
                System.out.println(name);
                m();//调用外部类的其他成员            }
        }).start();
    }

    public void m() {
        System.out.println("外部类的成员方法");
    }}

匿名内部类就是使用{}来实现或者继承某一个类。

常见的方式:

类名/接口  对象名 = new 类名/接口(){实现接口或者继承父类的重写的方法}//匿名内部类继承Thread        Thread ta = new Thread() {
            public void run() {
                System.out.println("一个线程");
            } 
        };
        ta.start();

使用场景:

当一个接口或者一个父类申明的抽象方法非常有限,而我们只需要这个类对象一次,这时就使用匿名内部类创建对象。

// 使用匿名内部类实现Runnable接口        new Thread(new Runnable() {
            private String name = "runnable";
            public void run() {
                System.out.println("匿名内部类实现Runnable接口实现一个线程类");
                System.out.println(name);
                m();//调用外部类的其他成员            }
        }).start();

匿名内部类中同样可以使用外部类的任何成员。

匿名内部类谈不上任何修饰符。

匿名内部类的编译:

匿名内部类也会被独立的编译成一个字节码文件,命名为 ”外部类类名$index.class”。 index就是编译器给所有的内部类给的索引。


JAVA基础知识——什么是内部类(图8)



静态内部类的单利中的使用

/** * @author 戴着假发的程序员 * @TODO 
 * @organization 飞虎队 * 2020年8月31日 上午11:25:50 */public class Singleton {
    //申明静态的私有的当前类对象成员//  private static Singleton instance;    //使用静态内部类实例化对象    private static class Inner{
        //在类加载的创建        private static Singleton instance = new Singleton();
    }
    //构造方法私有化    private Singleton() {
    }
    //静态public的获取当前类对象的方法    public static Singleton getInstance() {
        //加载内部类        return Inner.instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2);
    }}