java内部类学习与总结

我们经常会看到诸如此类的代码:

class A {
    double i = 0;

    public Circle(double radius) {
        this.i = i;
    }

    class B {     //内部类
        public void print() {
            System.out.println("这是内部类");
        }
    }
}

在java中,我们称它为内部类,顾名思义就是在一个类的内部再写一个类的形式,内部类是一种非常有用的特性,它允许你把一些逻辑相关的组织在一起,并控制位于内部类的可视性。

内部类的分类:

  1. 常规内部类
  2. 静态内部类
  3. 匿名内部类
  4. 局部内部类

我们先从最简单的常规内部类说起介绍起吧~

常规内部类

代码如下所示:


public class Outter {
    class Inner{
        int i;
        public Inner() {
            i=1;
            System.out.println("Inner内部类产生了");
        }

    }
    public Outter() {
        System.out.println("Outter外部类产生了");
    }
}

********
Outter outter=new Outter();
Outter.Inner inner=outter.new Inner();
//Outter.Inner in=new Outter().new Inner()也可以实现上述相同的效果

输出结果:
这里写图片描述

这里进行说明:当我们需要去掉用常规内部类的时候,我们需要通过如下的格式去调用:OutterClassName.InnerClassName,好了,用法介绍完毕了,但是你可能会问为什么要用内部类,我在外部类中不一样也可以实现内部类的功能么?

考虑这样的一种情况,当我的一个类要实现接口的时候,我又不想把这个接口公开出来,那该怎么做呢?这时候我们就可以使用内部类进行处理,看代码:

//接口
public interface PrivateMethod {
    void cout();
}
*****
public class Outter {
    class Inner implements PrivateMethod{
        int i;
        public Inner() {
            i=1;
            System.out.println("Inner内部类产生了");
        }
        @Override
        public void cout() {
            System.out.println("我不想让别人知道Outter实现PrivateMethod接口");

        }

    }
    public Outter() {
        System.out.println("Outter外部类产生了");
    }
}
****
{
        Outter outter=new Outter();
        Outter.Inner inner=outter.new Inner();
        inner.cout();
}

结果如下图所示:
这里写图片描述

这里我们可以看到,我们隐藏了PrivateMethod这个接口对于Outter的实现细节,相当于private修饰符的作用,保证了我们代码不对外公开,只提供实现,很好的保护了代码的安全性。

注意:普通的类(非内部),不能声明为private或者protected,他们只可以被赋予public或者默认包的访问权限。

匿名内部类

代码如下图所示:

public PrivateMethod newInstance(){
        return new PrivateMethod() {

            @Override
            public void cout() {
                System.out.println("我是匿名内部类");

            }
        };
    }
*****main中的代码
        Outter outter=new Outter();
//      Outter.Inner inner=outter.new Inner();
//      inner.cout();
        outter.newInstance();

我们可以看到结果显示:
这里写图片描述

在这里我们通过一个方法(其返回值是接口类型),返回了一个接口实现,但是我们可以看到,在其中我们并没有定义一个变量,而是直接通过new PrivateMethod的形式去实现。关于匿名内部类,在android中,我们经常可以看到:

 iv.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

这就是一个比较常规的实现,关于匿名类,就介绍道这里。

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

一般而言(除了静态内部类),内部类都会保存一个”隐藏”的应用去指向外部类,如果我们不需要引用,也就是内部类的实现与外部类无关,我们可以定义成static class,定义完后就意味着:
1.要创建嵌套类,并不需要其外部类的对象
2.不能从嵌套类的对象中访问非静态的外围类对象

嵌套类还跟常规内部类有一个区别,常规类的字段与方法中,不能放在嵌套类中,反之,也成立。

Outter.class

public static  void say(){
            System.out.println("静态内部类");
        }
    }
******
Outter.staticMethod.say();

我们在Outter.class添加上述代码,在主方法中直接调用Outter.staticMethod.say(),就产生如下的结果:
这里写图片描述

局部内部类

典型的局部内部类是在一个方法体中创建,局部内部类不能有访问说明符,因为他不是外部类的一部分,但是它可以访问当前代码块的常量以及外围类的所有成员:

//接口类
public interface MyInterFace {
    void getJuBu();
}

//外部类

public class Outter2 {
    MyInterFace getInstance(){
        class InnerJuBu implements MyInterFace{
            @Override
            public void getJuBu() {
            System.out.println("这是局部内部类的实现");   
            }
        }
        return new InnerJuBu();
    }
}
//主方法
Outter2 outter2=new Outter2();
outter2.getInstance();

实现结果:
这里写图片描述

我们在getInstance()方法中实现了一个返回值为InnerJuBu的内部类,最终向外传递这个内部类,实现类局部内部类的调用。


关于内部类的继承:
因为内部类的构造器必须连接到指向其外部类对象的引用,所以在继承内部类的时候,事情会变得有些复杂,主要在于,必须要让秘密的引用初始化,详细的代码如下图所示:


public class Outter2 {
    class Inner{

    }
}

public class InnerExtends extends Outter2.Inner {
    public InnerExtends(Outter2 outter) {
        outter.super();
    }

}

我们看到如果要继承一个内部类,必须要首先继承Outter2.Inner这个内部类,然后我们在其构造函数中调用outter.super()方法,这样就可提供内部类必要的引用,程序才会编译通过。

内部类是否被覆盖:

class Out{
     protected class In{
     }
}

class Demo extends Out{
     public class In{
     }
}

如同上述代码,即是我们在Demo中写了In类,java会认为这是一个全新的类,并不认为这是从父类,也就是Out这个类中继承过来的,如果要继承,应该通过如下的方式:

class Out{
     protected class In{
     }
}

class Demo extends Out {
     public class In extends Out.In{
     }
}

通过继承的方式,我们去重载相关方法实现覆盖。

内部类标识符:
由于每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息(此信息产生一个”meta-class”,叫做class对象),内部类也必须产生一个.class文件包含他们的class信息,这些类文件有严格的规则:外部类的名字,加上”$”,再加上内部类的名字如:

class Out{
     protected class In{
     }
}

编译过后则会产生一个Out.class文件以及一个Out$In.class文件,如果内部类是匿名的,则会简单的产生一个数字作为标识符,如Out$1.class


为什么需要内部类:
一般来说,内部类继承了某个类或实现某个接口,内部类操作外部类的对象,所以可以认为是内部类提供了某种进入外围类的窗口。
内部类最重要的原因是:

每个内部类都能独立继承一个(接口的)实现,无论外围伦是否已经继承了某个(接口的)实现,对于内部类来说都没有影响。

我们可以借助内部类实现多重继承(若拥有的是抽象或者具体的类,而不是接口)
如:

class D{}
abstract class E{}

class Z extends D{
     E makeE(){
         return new E();
     }

参考文献及资料:
1.《java编程思想》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值