java 内部类( inner class )

内部类(inner class )

1.      定义

是定义在另一个类中的类。

也可以在接口中定义,内部类可以继承某类或实现某接口;

内部类是一种编译时的语法,编译后生成的两个类是独立的两个类。内部类配合接口使用,来强制做到弱耦合(局部内部类,或私有成员内部类)。

注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。这是唯一一种必须使用内部类的情况。
用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。

Ø        枚举和接口可以在类的内部定义,但不能在方法内部定义

2.      意义和特性

Ø        内部类方法可以访问该外部类定义所在的作用域中的数据,包括私有的数据;

但外部类不能直接访问内部类的成员;

Ø        可以对同一包中的其他类隐藏起来;封装类型:把标准公开,把标准的实现者作为内部类隐藏起来

Ø       当想要定义一个回调函数而不想编写大量代码时,实用匿名内部类比较便捷;

注:所有使用内部类的地方都可以不使用内部类;使用内部类可以使程序更加的简洁(但牺牲可读性),便于命名规范和划分层次结构。

Ø        内部类和外部类在编译时是不同的两个类,内部类对外部类没有任何依赖;

编译后文件Outer.class 和Outer$Inner.class

Ø        内部类可用 static、protected 和 private 修饰;

而外部类只能使用 public 和 default;

3.    分类:

包括:成员内部类、局部内部类、静态内部类、匿名内部类 ;

注意:前三种内部类与变量类似,可以对照参考变量;

3.1  成员内部类(实例内部类):

作为外部类的一个成员存在,与外部类的属性、方法并列;可看作外部类的实例变量。示例:Outer

/**

 * 内部类示例:成员内部类(实例内部类)

 */

public class Outer {

    private String name;

   

    public Outer(String name) {

       this.name = name;

    }

    //私有内部类

    private class Inner {

       public void hello(){

           //引用外部类对象

           System.out.println("直接引用:" + name);

           System.out.println("this引用:" + Outer.this.name);

       }

    }

    public void start(){

       Inner o = this.new Inner();

       o.hello();

    }

}

示例:

    public static void main(String[] args) {

       Outer outer = new Outer("张三");

       outer.start();

    }

结果:

直接引用:张三

This引用:张三

 

Ø      隐式引用:内部类的对象有个隐式引用,它引用了实例化该内部对象的外围对象,通过这个指针,可以访问外围对象的全部状态;

编译后:finalOuter this$0   – 引用外围对象 , 可使用 this 直接引用外围类对象

●内部类中访问实例变量:this.属性 或 直接引用 属性

● 在内部类访问外部类的实例变量:外部类名.this.属性。【Outer.this.属性】

编译上面的Inner类,命令:javap –privateOuter$Inner

Ø      不可以有静态属性和方法(final 的除外),因为static 在加载类的时候创建,这时内部类还没被创建

Ø      在创建成员内部类的实例时,外部类的实例必须存在:

Ø      在外部类的内部可以直接使用Inner inner = new Inner();  因为外部类知道 inner 是哪个类。

Ø      而在外部类的外部,要生成一个内部类对象,需要通过外部类对象生成。

Outer outer = new Outer();

Outer.Inner inner = outer.new Inner();

或 Outer.Inner inner = new Outer().new Inner();

错误的定义:Outer.Innerinner = new Outer.Inner();

 

3.2  静态内部类

在内部类不需要访问外围类对象时,应该使用静态内部类,内部类声明为static;

Ø      静态内部类定义在类中,在任何方法外,用 static 定义;

Ø      静态内部类能直接访问外部类的静态成员;

Ø      不能直接访问外部类的实例成员;

Ø      静态内部类里面可以定义静态成员(其他内部类不可以)。

Ø      生成(new)一个静态内部类不需要外部类成员,这是静态内部类和成员内部类的区别。
静态内部类的对象可以直接生成: Outer.Inner in = new Outer.Inner();
对比成员内部类:Outer.Innerin = outer.new Inner();

Ø      静态内部类不可用 private 来进行定义

Ø      声明在接口中的内部类自动成为 static 和 public

3.3  局部内部类

在方法中定义的内部类称为局部内部类。

Ø      不能用 public、protected 和private 进行声明,其范围为定义它的代码块;

Ø       可以访问外部类的所有成员;

Ø       可以访问局部变量(含参数),但局部变量必须被声明为final

Ø       在类外不可直接生成局部内部类,保证局部内部类对外是不可见的,即对外部是完全隐藏的;

Ø       在方法中才能调用其局部内部类;

Ø       局部内部类不能声明接口和枚举;

3.4  匿名内部类

Ø        由于构造器的名字必须和类名相同,而匿名类没有类名,所以,匿名内部类不能有构造器,将构造器参数传递给超类构造器,尤其是在内部类实现接口的时候,不能有任何构造参数;

Ø        用于构造对象的任何参数都要被放在超类后面的()内,语法为

new SuperType (construction parameters){

    inner class methods and data

}

Ø        通过匿名类实现接口,大部分情况都是为了实现接口的回调;

new InterfaceType(){

    inner class methods and data

}

Ø        匿名内部类在编译的时候由系统自动起名Outer$1.class

Ø        其为特殊局部内部类,所以局部内部类的所有限制都对其生效。

4.      其他

4.1  内部接口:

Ø        在一个类中也可以定义内部接口;

Ø        在接口中可以定义静态内部类,此时静态内部类位于接口的命名空间中。

Ø        在接口中还可以定义接口,这种接口默认也是public static 的

如Map.Entry就是这种接口

Ø        接口里面还可以定义多重接口和类。

示例:OutInterface

package core.z6.inner.test3;

 

/**                                     

 * 接口中可以定义 接口 和 类,-- 默认为public 和 static

 * 如: innerInterFace 、 InnerAbstractClass 、InnerClass

 * 也可以定义抽象的内部类,

 * 如InnerAbstractClass

 * 类也可以继承或实现其他类或接口       

 * 如:InnerClass

 */

public interface OutInterface {

    void hello(String name);

    /** 定义内部内部接口 */

    interface InnerInterFace {

       void hello(String name);

    };

    /** 定义抽象内部类 */

    abstract class InnerAbstractClass implements InnerInterFace{

    }

    /** 内部类也可以继承或实现其他类或接口 */

    class InnerClass implements InnerInterFace{

       public void hello(String name) {

            System.out.println(this.getClass().getName() + ": Hello " + name);

       }

    }

}

示例:OutClass

package core.z6.inner.test3;

 

public class OutClass implements OutInterface {

    public void hello(String name) {

       System.out.println(this.getClass().getName() +  ": Hello " + name);

    }

}

示例:Test2

package core.z6.inner.test3;

import core.z6.inner.test1.OutInterface.InnerClass;

public class Test3 {

    public static void main(String[] args) {

       OutInterface obj = new OutClass();

       obj.hello("李四");    //外部接口的hello()方法

       OutInterface.InnerInterFace o = new InnerClass();

       o.hello("张三");      //内部部接口的hello()方法

    }

}

结果

core.z6.inner.test1.OutClass: Hello 李四

core.z6.inner.test1.OutInterface$InnerClass: Hello 张三

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值