【JAVA提升】- 内部类

1. 内部类

1.1 【特点】:

  1. 普通内部类中不能有static修饰的成员变量和方法

  2. 使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。利用内部类可以间接实现多继承。 (利用多个内部类实现继承过个类,思想是组合)。

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

  4. 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类

  5. 创建内部类对象的时刻并不依赖于外围类对象的创建。

  6. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

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

1.2 【使用.this与.new】

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

    /**省略getter和setter方法**/
    
    public class InnerClass{
        public InnerClass(){
            name = "chenssy";
            age = 23;
        }
        
        public void display(){
            System.out.println("name:" + getName() +"   ;age:" + getAge());
        }
    }
    
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.display();
    }
}
--------------
Output:
name:chenssy   ;age:23

引用内部类我们需要指明这个对象的类型:OuterClasName.InnerClassName。同时如果我们需要创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类: OuterClass.InnerClass innerClass = outerClass.new InnerClass();

如果我们需要生成对外部类对象的引用,可以使用OuterClassName.this

public class OuterClass {
    public void display(){
        System.out.println("OuterClass...");
    }
    
    public class InnerClass{
        public OuterClass getOuterClass(){
            return OuterClass.this;
        }
    }
    
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.getOuterClass().display();
    }
}
-------------
Output:
OuterClass...

1.3 内部类分类

1.3.1 成员内部类

成员内部类也是最普通的内部类,它是外围类的一个成员

【特点】:

  1. 成员内部类中不能存在任何static的变量和方法;
  2. 成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类

1.3.2 局部内部类

在方法和属性内部定义的类,作用域在方法和属性内部

1.3.3 匿名内部类

比较常见

public class OuterClass {
    public InnerClass getInnerClass(final int num,String str2){
        return new InnerClass(){
            int number = num + 3;
            public int getNumber(){
                return number;
            }
        };        /* 注意:分号不能省 */
    }
    
    public static void main(String[] args) {
        OuterClass out = new OuterClass();
        InnerClass inner = out.getInnerClass(2, "chenssy");
        System.out.println(inner.getNumber());
    }
}

interface InnerClass {
    int getNumber();
}

----------------
Output:
5

【特点】:

  1. 匿名内部类是没有访问修饰符的。
  2. new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。
  3. 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
  4. 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。
  5. 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
  6. 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法

1.3.3.1 使用的形参为何要final

内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上时自己的属性而不是外部方法传递进来的参数

在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。

1.3.3.2 匿名内部类初始化

没有构造方法,所以使用构造代码块来创建达到构造方法的效果

public class OuterClass {

    private int id;

    private InnerClass getInnerClass(final String name, final int age) {
        return new InnerClass() {

            String innerName;
            int innerAge;
            // 构造代码块初始化
            {
                innerName = name;
                innerAge = age;
            }

            @Override
            public String getInnerName() {
                return innerName;
            }

            @Override
            public int getInnerAge() {
                return innerAge;
            }
        };
    }

    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();

        InnerClass innerClass = outerClass.getInnerClass("fun",26);
        System.out.println(innerClass.getInnerName());

        InnerClass innerClass2 = outerClass.getInnerClass("BruceLee",26);
        System.out.println(innerClass2.getInnerName());
    }
}

interface InnerClass{
    String getInnerName();
    int getInnerAge();
}

1.3.4 静态内部类

使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类

静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。

所以有以下【特点】:

  1. 它的创建是不需要依赖于外围类的。
  2. 它不能使用任何外围类的非static成员变量和方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容