Java中的内部类

java中内部类

一、内部类

内部类分为四种:成员内部类、静态内部类、局部(方法)内部类、匿名内部类。

public class Outer{
	
	class Inner{
	//内部类
	}
}

我们在这里先简单介绍一下各个内部类的特点

  1. 非静态内部类(成员内部类)
    作为类的成员,存在于某个类的内部。
    成员内部类可以调用外部类的所有成员,但只有在创建了外部类的对象后,才能调用外部的成员, 外部类如果需要访问非静态内部类的实例成员,必须先创建非静态内部类。
    如果需要访问非静态内部类的话,必须先创建外部类。

  2. 静态内部类
    作为类的静态成员,存在于某个类的内部。
    静态内部类虽然是外部类的成员,但是在未创建外部类的对象的情况下,可以直接创建静态内部类的对象。静态内部类可以引用外部类的静态成员变量和静态方法,但不能引用外部类的普通成员。

  3. 局部内部类
    存在于某个方法的内部。
    局部内部类只能在方法内部中使用,一旦方法执行完毕,局部内部类就会从内存中删除。
    必须注意:如果局部内部类中要使用他所在方法中的局部变量,那么就需要将这个局部变量定义为final的。

  4. 匿名内部类
    存在于某个类的内部,但是无类名的类。
    匿名内部类的定义与对象的创建合并在一起,匿名内部类一般通过如下形式定义,并且在定义的同时进行对象的实例化。
    new 类或者接口的名字(){
    匿名内部类的主体,大括号中是匿名内部类的主体,这个主体就是类或者接口的实现,如果是类,那么匿名内部类是该类的子类,如果是接口,匿名内部类需要完成接口的实现。
    }

二、为什么要使用内部类

  1. 每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
  2. 内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
  3. 内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
  4. 内部类提供了更好的封装,除了该外围类,其他类都不能访问。
  5. 创建内部类对象的时刻并不依赖于外围类对象的创建。

三、如何使用内部类

内部类的描述
图片转自Java新生代。

(一)非静态内部类(成员内部类)


public class Outer {

    private String outerVariable = "外部类的实例变量";
    private String commonVariable = "同名变量(外部类)";
    private static String outerStaticVariable = "外部静态(类)的类变量";

    
    public void outerMethod() {
        System.out.println("我是外部类的实例方法");
    }

    
    public static void outerStaticMethod() {
        System.out.println("我是外部类的静态方法");
    }

    /**
     * 内部类
     */
    public class Inner {

        private String commonVariable = "同名变量(内部类)";


        public Inner() {
            System.out.println("内部类的构造器");
        }

        public void innerShow() {
            //当和外部类冲突时,直接引用属性名,是内部类的成员属性
            System.out.println( commonVariable);
            //内部类访问外部属性
            System.out.println( outerVariable);
            System.out.println(outerStaticVariable);
            //当和外部类属性名重叠时,可通过外部类名.this.属性名
            System.out.println(Outer.this.commonVariable);
            //访问外部类的方法
            outerMethod();
            outerStaticMethod();
        }
    }

    /**
     *	外部类访问内部类信息
     */
    public void test(){
        Inner in=new Inner();
        in.innerShow();
    }

}

---------------------------------------------------------------------

其他类使用成员内部类
public class Other {
    
    public static void main(String[] args) {
        //创建外部类实例
        Outer outer = new Outer();
        //通过外部类实例和new来调用内部类构造器创建非静态内部类实例
        Outer.Inner in;
        in = Outer.new in();

        //可总结为
        Outer.Inner in = new Outer().new Inner();
}

输出为:

外部类构造器
内部类的构造器
同名变量(内部类)
外部类的实例变量
外部静态的类变量
同名变量(外部类)
我是外部类的实例方法
我是外部类的静态方法

如果需要在外部类以外的地方创建非静态内部类的子类,则尤其要注意上面的规则:非静态内部类的构造器必须通过其外部类的对象来调用。
当创建一个子类时,子类构造器总是会调用父类构造器。例如以下程序:

public class SubClass extends Outer.Inner
    {
        public  SubClass(Outer out)
        {
            //通过传入Outer对象显式调用Inner的构造器
            out.super();//输出内部类的构造器
        }
    }

如果有非静态内部类子类的对象存在,则一定存在与子对应的外部类对象。

小结
  1. 可以是任何的访问修饰符。
  2. 内部类的内部不能有静态信息。
  3. 内部类也是类,该继承继承,该重写重写,该重载重载,this和super随便用。
  4. 外部类如何访问内部类信息,必须new之后打点访问。
  5. 内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突,调用外部类.this.属性或者方法。

(2)静态内部类

package com.company;

public class Outer {

    private String outerVariable = "外部类实例变量";

    private String commonVariable = "同名变量(外部类)";

    private static String outerStaticVariable = "外部类静态变量";

    {
        System.out.println("外部类的构造块被执行了");
    }

    static {
        System.out.println("外部类的静态块被执行了");
    }

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


    public static void outerStaticMethod() {
        System.out.println("我是外部类的静态方法");
    }


    public static class Inner {

        private String innerVariable = "内部类实例变量";
        private String commonVariable = "同名变量(内部类)";
        private static String innerStaticVariable = "内部类的静态变量";

        {
            System.out.println("内部类的构造块执行了");
        }
        static {
            System.out.println("内部类的静态块执行了");
        }
        
        public void innerShow() {
            System.out.println(innerVariable);
            System.out.println(commonVariable);
            System.out.println(outerStaticVariable);
            outerStaticMethod();
        }


        public static void innerStaticShow() {
            outerStaticMethod();
            System.out.println(outerStaticVariable);
        }
    }

    /**
     * 外部类的内部如何和内部类打交道
     */
    public static void callInner() {
        System.out.println(Inner.innerStaticVariable);
        Inner.innerStaticShow();
    }

    public static void main(String[] args) {
        Outer.Inner in=new Outer.Inner();
        in.innerShow();
    }
}

其他类使用成员内部类
public class Other {

    public static void main(String[] args) {
        //访问静态内部类的静态方法,内部类被加载,此时外部类未被加载,独立存在,不依赖于外围类。
        Outer.Inner.innerStaticShow();
        //访问静态内部类的成员方法
        Outer.Inner in = new Outer.Inner();
        in.innerShow();
    }
}

输出为

内部类的静态块执行了
外部类的静态块被执行了
我是外部类的静态方法

外部类静态变量
内部类的构造块执行了
内部类实例变量
同名变量(内部类)
外部类静态变量
我是外部类的静态方法
小结
  1. 内部可以包含任意的信息。
  2. 静态内部类的方法只能访问外部类的static关联的信息。
  3. 利用 外部类.内部类 引用=new 外部类.内部类(); 然后利用引用.成员信息(属性、方法)调用。
  4. 访问内部类的静态信息,直接外部类.内部类.静态信息就可以了。
  5. 静态内部类可以独立存在,不依赖于其他外围类。
  6. 访问静态内部类的静态方法,内部类被加载,此时外部类未被加载,独立存在,不依赖于外围类。
(三)局部内部类
public class Outer {

    public static void main(String[] args) {
        //定义局部内部类
        class Inner
        {
            int a;
        }

        class Innersub extends Inner
        {
            int b;
        }
        
        //创建局部内部类的对象
        var is =new Innersub();
        is.a=5;
        is.b=6;
        System.out.println("a="+is.a+","+"b="+is.b);
    }
}

输出结果

a=5,b=6
小结
  1. 因为局部类仅在方法里有效,所以局部内部类也不能使用访问控制符和static修饰符修饰。
  2. 局部成员的作用域是在所在方法。
  3. 局部内部类引用所在方法内被赋值却未改变的变量会报错。
  4. 可以随意的访问外部类的任何信息。
(四)匿名内部类

interface Product
{
    double getPrice();
    String getName();
}
public class Test {

    public void test(Product p) {
        System.out.println("购买了" + p.getName() + ",花了" + p.getPrice());
    }

    public static void main(String[] args) {
        var ta = new Test();
        //此处传入其匿名实现类的实例
        ta.test(new Product() {

                    {
                        System.out.println("匿名内部类的构造块");
                    }

                    public double getPrice() {
                        return 100;
                    }

                    public String getName() {
                        return "键盘";
                    }
                }
        );
    }
}

输出为:

匿名内部类的构造块
购买了键盘,花了100.0
小结
  1. 匿名内部类不能是抽象类,系统在创建匿名内部类时,会立即创建匿名内部类的对象。所以无法定义为抽象类。
  2. 匿名内部类不能定义构造器。因为匿名内部类没有类名,所以无法定义。
  3. 可以定义初始化块。
  4. 匿名内部类是方便某些只用使用一次的接口实现类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值