Java内部类

在java中,可以在一个类内部定义另外一个类,也就是我们所说的内部类,内部类个人感觉最大的功能是为java多继承提供了支持(java类最多只能继承一个基类,不允许多继承)。

java内部类有四种,分别是成员内部类、局部内部类、匿名内部类和静态内部类(也称嵌套内部类),下面分别讲一下这四种内部类。

成员内部类

成员内部类位于外部类的内部,看起来就像一个成员变量一样,下面是一个成员内部类的实例:

class A{}
class B{}
interface C{}
interface D{}

class Outter extends A implements C{        //外部类
    private int i = 0;

    public class Inner extends B implements C,D{        //内部类
        int i = 1;
        void test(){
            System.out.println(i);  //1,内部类的i
            System.out.println(Outter.this.i);//0,外部类的i
        }
    }
}   
  • 成员内部类的访问修饰符可以是public,protected,private和缺省。而器外部类只能是public,缺省或者定义为abstract。

  • 上面的例子可以看到,内部类可以访问外部类的成员,如果成员名字有冲突时,默认是内部类自己的成员,这种情况下要想访问外部类的成员,需要使用this

  • 外部类继承了B,而内部类继承了C,这样就实现了java的多继承。

  • 这里我们可以看到,内部类和外部类都同时实现了C接口,这也是允许的。内部类和外部类可以以不同方法实现同一个接口。

创建成员内部类对象

    public static void main(String[] args) {
        Outter outter = new Outter();   //必须要创建外部类对象
        Outter.Inner inner = outter.new Inner();
    }
  • 必须先创建外部类的对象。有兴趣的同志可以去反编译一个内部类的字节码,就可以发现其实它的构造函数接受了一个外部类的对象作为参数,所以创建内部类对象必须要有一个外部类的对象。
  • 用outter.new的方法去创建内部类对象。

局部内部类

局部内部类定义在外部类成员方法内部。

class Outter extends A implements C { // 外部类
    private int i = 0;

    public B test() {
        class Inner extends B implements C, D { // 内部类

        }
        return new Inner();
    }
  • 局部内部类因为不会在其他地方被实例化,所以权限修饰符对于它来说就没有意义了,所以局部内部类没有权限修饰符。
  • 通常是返回一个实例化对象。这里就引出了一个问题,test()方法执行完return后其生命周期就结束了,但是返回的内部类对象其生命周期并没有结束,所以如果内部类使用到外部方法的局部变量怎么办?答案是内部类只能访问外部类和外部类外部方法的final变量,我们看下面的代码:
class Outter extends A implements C { // 外部类
    private String s = "Outer";

    public B test(final int k) {
        int i = 0;
        final int j = 0;
        class Inner extends B implements C, D { // 内部类
            String s = "Inner";
            void f() {
                String s = "Inner.f";
                System.out.println(s); //Inner.f 
                System.out.println(this.s);//Inner
                System.out.println(Outter.this.s);//Outer
                //Cannot refer to the non-final local variable j defined in an enclosing scope
//              System.out.println(i);//error
                System.out.println(k);//0
                System.out.println(j);//0
            }
        }
        return new Inner();
    }

    public static void main(String[] args) {
        Outter outter = new Outter(); // 必须要创建外部类对象 
        B b = outter.test(0);
        b.f();
    }
}
  • 试图访问非final变量i会提示错误。访问外部方法的非final变量是不允许的,因为前面说过了,外部函数生命周期结束的时候,内部类对象还是活着的,所以访问不到。
  • 但是为什么final变量又可以呢?因为内部类将要访问的final变量作为参数传递给了自己的构造函数(这个可以通过反编译字节码看到)。
  • 从上面我们可以看到,如果内部类变量名和外部类变量名一样,默认使用的是内部类的变量,要访问外部类的s变量时,我们要用Outter.this.s

匿名内部类

匿名内部类非常常见,如果某个类只需要在一个外部类内部实例化一次的话,我们就可以使用匿名内部类。匿名内部类在安卓的时间监听器中应用比较多。在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。下面这段代码是一段Android事件监听代码:

bt.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });
  • 匿名内部类和局部内部类一样,都没有访问修饰符
  • 匿名内部类也不能用static修饰,这个因为如果是静态的话,没有名字我们都访问不到它
  • 匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。

上面的代码等价于下面的代码:

private void setListener()
{
    bt.setOnClickListener(new Listener());       
}

class Listener implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub

    }
}

静态内部类(嵌套内部类)

静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,所以基本来说静态内部类仅仅是在外部类内部定义的类,不受限与外部类,和普通静态类没什么区别。

class Outter {  //  外部类
    static class Inner {    //静态内部类
    }
}
  • 静态内部类不能访问外部类的非静态成员
  • 静态内部类不依赖于外部类具体对象

什么时候需要使用内部类

  1. 每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整(最重要的特点)

  2. 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

  3. 方便编写事件驱动程序

  4. 方便编写线程代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值