Java基本概念:内部类


一、简介

描述:

  • 很多时候我们创建类的对象的时候并不需要使用很多次,每次只使用一次,这个时候我们就可以使用内部类了。
  • 内部类不是在一个java源文件中编写两个平行的类,而是在一个类的内部再定义另外一个类。 我们可以把外边的类称为外部类,在其内部编写的类称为内部类。

分类:

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

内部类通用用法:

  • 要想访问内部类中的内容,必须通过外部类或外部类对象
  • 内部类可以访问外部类的所有访问权限的属性和方法,包括私有的成员变量、方法。原理就是在通过外部类对象实例化内部类对象时,外部类对象把自己的引用传进了内部类,使内部类可以用通过'外部类名.this'去调用外部类的属性和方法。一般都是隐式调用了,但是当内部类中有属性或者方法名和外部类中的属性或方法名相同的时候,就需要通过显式调用'外部类名.this.外部类属性名'了。




二、成员内部类

描述:

  • 成员内部类又叫实例内部类、非静态内部类。
  • 一个类在另一个类的内部,那么想要使用这个内部类,就必须先要有外部类的一个实例对象,然后在通过该对象去使用内部类

注意:

  • 成员内部类中可以访问外部类的所有属性和方法,包括私有的成员变量、方法。
  • 成员内部类中不能写静态的属性和方法
  • 实例化内部类,首先需要实例化外部类,通过外部类去调用内部类
  • 如果内部类中的变量名和外部类的成员变量名一样,在内部类中,要通过'外部类名.this.外部类属性名'来访问外部类属性,通过'this.内部类属性名'来访问内部类属性

示例:

class Outer {
    private int id;
    private String name = "outer";

    public void out() {
        System.out.println("这是外部类方法");
    }

    class Inner {
        private int id = 8;

        public void in() {
            System.out.println("这是内部类方法");
        }

        public void test() {
            System.out.print(name + " " + Outer.this.id + " " + id);
        }
    }
}

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




三、静态内部类

描述:

  • 使用'static'修饰的内部类就叫静态内部类
  • 静态内部类是外部类的静态成员,从属于外部类,不从属于外部类对象。

特点:

  • 静态内部类能够直接被外部类给实例化,不需要使用外部类对象。
  • 静态内部类中可以声明静态方法和静态变量
  • 静态内部类中没有外部类对象的引用,所以不能使用外部类的非静态属性和方法

示例:

public class Test {
    private String name;
    private static int age;

    public void run() {
    }

    public static void go() {
    }

    private static class StaticInnerClass {
        private String name;
        private static int age;

        public void test1(String name) {
            System.out.println(name + " " + this.name + " " + StaticInnerClass.age + " " + Test.age);
            /*
                静态内部类不能访问外部类非静态属性
                System.out.println(Test.this.name);
            */
            Test.go();
            /*
                静态类不能访问非静态方法
                Test.this.run();
            */
        }

        public static void test2(String name) {
            /* 内部类的静态方法只能访问自己和外部类的静态属性和方法 */
            System.out.print(name + " " + StaticInnerClass.age + " " + Test.age);
            /*
                内部类的静态方法不能访问外部类的非静态属性
                System.out.println(Test.this.name);
            */
            /*
                内部类的静态方法里面连自己类的非静态属性都不能访问
                System.out.println(this.name);
            */
            Test.go();
            /*
                内部类的静态方法不能访问非静态方法
                Test.this.run();
            */
        }
    }

    /* 外部类访问静态内部类 */
    public static void main(String[] args) {
        /* 静态的内部类不需要依赖外部类,所以不用new外部类对象 */
        StaticInnerClass sic = new StaticInnerClass();
        /* 内部类对象调用内部类成员变量和成员方法 */
        sic.name = "张三";
        sic.test1("李四");//李四 张三 0 0
        /* 内部类调用内部类静态变量和静态方法 */
        StaticInnerClass.age = 10;
        StaticInnerClass.test2("王五");//王五 10 0
    }
}




四、局部内部类

描述:

  • 局部内部类是在方法内部声明的类
  • 局部内部类只能在所在的方法中使用,生命周期相当于一个局部变量,只能在方法体里。
  • 局部内部类的作用跟在成员内部类差不多,也可以访问所在外部类的成员变量及方法。

注意:

  • 局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。
  • 局部内部类中如果要访问该内部类所在方法中的局部变量,那么这个局部变量就必须是'final'修饰的。'final'修饰的变量会变为常量,在常量池中放着。如果不变为常量,当局部内部类被实例化后,方法弹栈,局部变量随着跟着消失,这个时候局部内部类对象想去调用该局部变量,就会出错,因为该局部变量已经没了。当局部变量变为常量后,就会将其加入常量池中,即使方法弹栈了,该局部变量还在常量池中呆着,局部内部类也就是够调用。所以局部内部类想要调用局部变量时,需要使用'final'修饰,不使用,编译都通不过。

示例:

public class Test {
    private String name;
    private static int age;

    public void run() {
    }

    public static void go() {
    }

    public void test() {
        final String myName = "王五";
        /* 局部内部类要定义在方法中 */
        class LocalInnerClass {
            private String name;
            /*
             不能定义静态属性
             private static int age;
            */
            public void test(String name) {
                System.out.println(name + " " + this.name + " " + myName + " " + Test.this.name);
                Test.this.run();
                Test.go();
            }
        }

        LocalInnerClass lic = new LocalInnerClass();
        lic.name = "张三";
        lic.test("李四");//李四 张三 王五 null
    }

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




五、匿名内部类

描述:

  • 匿名内部类是最常用的一种内部类。
  • 匿名内部类是只会使用一次的类。那么就不需要先定义一个类,而是等到需要用的时候,再临时实现并使用这个类。
  • 匿名内部类需要依托于其他类或者接口来创建。如果依托的是类,那么创建出来的匿名内部类就默认是这个类的子类;如果依托的是接口,那么创建出来的匿名内部类就默认是这个接口的实现类。
  • 匿名内部类的声明必须是在使用'new'关键字的时候。匿名内部类的声明及创建对象必须一气呵成,并且之后不能反复使用,因为没有名字。

注意:

  • 匿名内部类除了依托的类或接口之外,不能指定继承或者实现其他类或接口,同时也不能被其他类所继承,因为没有名字。
  • 匿名内部类中,我们不能写出其构造器,因为没有名字。
  • 匿名内部类中,除了重写或实现依托的类或接口的方法外,一般不会再写其他独有的方法,因为从外部不能直接调用到(间接是调用到的)。

语法:

new Class(){
    /* 重写类里的方法,或者实现类或接口中的抽象方法。 */
}

示例:

interface Person {
    public void say();
}

public class Test {
    public static void main(String[] args) {
        /*
            new Class(){}的作用就是将接口给实现了,只不过这里实现该接口的是一个匿名类,也就是说这个类没名字,只能使用这一次。
            我们知道了这是一个类,将其new出来,就能获得一个实现了Person接口的类的实例对象,通过该实例对象,就能调用该类中的方法了。
            因为该匿名类是在一个类中实现的,所以叫其匿名内部类。
        */
        new Person() {
            public void say() {
                System.out.println("实现了Person接口的方法");
            }
        }.say();//实现了Person接口的方法
    }
}




posted @ 2020-11-29 15:37  conyoo  阅读(267)  评论(0编辑  收藏  举报