java内部类的使用

为什么使用内部类?

原因:

  1. 每一个内部类都可以独立的实现一个接口,不论外部类是否实现了这个接口,都对内部类没有影响
  2. 它能够非常好的解决多重继承问题

内部类特性:
(1)、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
(2)、在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
(3)、创建内部类对象的时刻并不依赖于外部类对象的创建。
(4)、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
(5)、内部类提供了更好的封装,除了该外部类,其他类都不能访问。

静态内部类

静态内部类是不需要依赖外部类的,它和类的静态成员属性类似

  1. 不可以直接访问外部的非静态资源,但可以通过 new 外部类().成员 的方式访问
  2. 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;
    如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员
  3. 可以有public static abstract class Demo
  4. 创建方式
    内部类 对象 = 内部类()//与main方法在同一文件中
    外部类.内部类 对象 = new 外部类.内部类()//与main方法不在同一文件中
public class Outter {
    private int age = 9;
    static String name = "小光";

    public static class Inner {
        String name = "小夏";
        public void show() {
            System.out.println("Outter的静态name:"+Outter.name);
            System.out.println("static Inner的name:"+name);
        }
    }
	//静态抽象内部类
    public static abstract class Demo{
        String name = "小刚";
        public void show() {
            System.out.println("Outter的静态name:"+Outter.name);
            System.out.println("static abstract Inner的name:"+name);
        }
    }

    public static void main(String[] args) {
        Inner i = new Inner();
        i.show();
        //创建静态抽象内部类
        Demo d = new Demo() {
            @Override
            public void show() {
                super.show();
            }
        };
        d.show();
    }
}

运行结果:

Outter的静态name:小光
static Inner的name:小夏
Outter的静态name:小光
static abstract Inner的name:小刚

成员内部类

  1. 可以无条件访问外部所有资源(包括private成员和静态成员),但本身内部不可有静态属性(因为本身就需要依靠外部类实例化)
  2. 如果要访问外部类的同名成员需要以下面的方式进行访问
    1. 外部类.this.成员变量
    2. 外部类.this.成员方法
  3. 外部类要访问成员内部类成员,需要想创建一个成员内部类对象,通过对象来访问
    要创建一个成员内部类对象,前提是必须存在一个外部类对象
    1. 方式一:Outter outter = new Outter(); Outter.Inner inner = outter.new Inner();
    2. 方式二:在外部类中定义一个获取内部类的方法getInnerClass()
    Outter outter = new Outter(); Outter.Inner inner = outter.getInnerClass();
    3. 上面两种方式main与内部类在同一文件中,两者不在同一个文件中需要使用外部类.内部类 内部类引用Outter.Inner in
  4. 内部类可以拥有public 、protected 、包权限 、private 来修饰
public class Outter {
    private int age = 1;
    public static final String name = "abc";

    public class Inner {
        String name = "Jayden";
        //show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性age 
        public void show() {
            System.out.println("Outter的final name:"+Outter.this.name);
            System.out.println("Inner的name:"+name);
            System.out.println("Outter的private age:"+age);
        }
    }
	//自定义方法获取内部类对象
    public Inner getInnerClass() {
    	//此处解释一下问什么在自定义方法中可以直接new,不用先创建外部类对象:
    	//因为这个方法本身就属于外部类对象,使用这个方法时是外部类对象.方法名  等价于  外部类对象.new Inner()
        return new Inner();//可以直接new内部类对象
    }

    public static void main(String[] args) {
        Outter o = new Outter();
//        Inner in = new Outter().new Inner();//这种创建方式也是可以的
        Inner in = o.new Inner();	//通过方式一创建对象
        Inner in2 = o.getInnerClass();	//通过方式二创建对象
        in.show();
        System.out.println();
        in2.show();
    }
}

运行结果:

Outter的final name:abc
Inner的name:Jayden
Outter的private age:1

Outter的final name:abc
Inner的name:Jayden
Outter的private age:1

编译上面的程序后,会发现产生了两个 .class 文件: Outer.class,Outer$Inner.class{}
成员内部类中不能存在任何 static 的变量和方法,可以定义常量:
(1).因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关,
简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过;
非静态内部类的作用域是实例级别
(2).常量是在编译器就确定的,放到所谓的常量池了

局部内部类(方法内部类)

  1. 出现在方法内部,类似于方法中的局部变量,不可被访问修饰符和static修饰,只能访问final变量和形参 。
  2. 作用域仅限于方法内部,方法外部不能访问
  3. 局部静态内部类:在外部类静态方法中。局部内部类:在外部类非静态方法中
  4. 只能访问方法类型中的定义的final修饰的局部变量
public class Outter {
    public void Show() {
        final int a = 25;
        int b = 13;
        class Inner {
            int c = 2;
            public void print() {
                System.out.println("访问外部类:" + a);
                System.out.println("访问内部类:" + c);
            }
        }
        Inner i = new Inner();
        i.print();
    }

    public static void main(String[] args) {
        Outter o = new Outter();
        o.Show();
    }
}

运行结果

访问外部类:25
访问内部类:2

注意:在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了Effectively final 功能
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的

匿名内部类

  1. 唯一一个没有构造器的内部类,没有静态资源
  2. 无法被访问修饰符、static修饰
  3. 只能创建匿名内部类的一个实例,创建的时候一定是在new后面
  4. 匿名内部类的使用存在一个缺陷,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用;
  5. 匿名内部类不能是抽象的,使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口
  6. 匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果
  7. 一般使用匿名内部类的方法来编写监听事件的代码
public class Outter {
    public InnerClass getInnerClass() {
        return new InnerClass() {
            public String getNumber() {
                return "通过自定义方法的方式创建匿名内部类";
            }
        };
    }

    public static void main(String[] args) {
        Outter out = new Outter();
        InnerClass inner = out.getInnerClass();
        InnerClass innerClass = new InnerClass() {
            @Override
            public String getNumber() {
                return "在new后面创建匿名内部类";
            }
        };
        System.out.println(inner.getNumber());
        System.out.println(innerClass.getNumber());
    }
}

interface InnerClass {
    String getNumber();
}

运行结果

通过自定义方法的方式创建匿名内部类
在new后面创建匿名内部类

为什么局部内部类和匿名内部类只能访问局部final变量?

当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量;
==>使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期。可以防止被篡改数据,而导致内部类得到的值不一致
局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部作为自己的属性
自己内部的方法调用的实际是自己的属性而不是外部类方法的参数;

以main线程与某个Thread对象为例

  1. 背景:当main方法执行完毕后,方法中的变量a 的生命周期就结束了,而Thread的生命周期很可能还没有结束,它的run方法再访问a时,找不到了,但是有需要变量a,这咋办?java采用复制的方式解决这个问题。
  2. 方案:如果局部变量的值在编译期间就能确定,那么就在匿名内部类里创建一个拷贝。如果不能确定,那么就通过构造器传参的方式来对拷贝初始化赋值(这个拷贝就是传进来的参数,将这个拷贝作为内部类的属性)
  3. 问题:如果在run方法中改变a的值,会造成数据的不一致性,怎么解决?
  4. 解决:限定使用的变量是final修饰的就行了(回到正题)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值