第十章 内部类

概要

在平时的编程中,用的最多的内部类就是点击事件和Handler的使用。这个点,已经没心思遍题记这种废话了。直接切入主题上重点笔记吧:
1.当生成一个内部类对象的时候(静态类除外),此对象与制造它的外围对象之间就有了一种联系,所以它能够访问外围类的成员,而且不需要任何特殊条件。此外,内部类还拥有其外围成员的所有元素的访问权限,外围类也是可以直接访问内部类的private和protected修饰的变量和方法。
2.如何创建一个内部类?具体代码如下:

 class OuterClass{//外围类
 class InnerClass{//内部类

}
OuterClass out = new OuterClass();
OuterClass.InnerClass = out.new InnerClass();//我们需要先初始化外围对象,然后再out.new InnerClass();初始化新的对象。
}

通过上面的代码我们可以知道在创建内部类的时候(静态类除外),我们必须持有一个外围类对象,这是因为我们的内部类能够访问外围类的方法与变量。

3.如果一个内部类是静态的(这时候这个内部类叫嵌套类),它是不需要外围类引用的,因为这个静态内部类类是跟外围类关联的 ,而不是跟外围类的对象关联的。我们在创建静态内部类的时候,就不需要外围类的对象了。
4.我们可以覆盖父类的内部类。
5.在方法和作用域中也可以创建内部类。他们的理由是:

  • 你实现了某个类型的接口,于是可以创建并返回对其的引用。
  • 你要解决一个复杂的问题,先创建一个辅助你的解决办法,但是又不希望这个类是可以公用的。

6.下面将介绍几种内部类:

  • 在方法中定义的类:
    在方法中创建的类,他编译也会产生一个class文件,格式是A 1MethodClass.class+ ’号+方法编号+内部类的方式。值得注意的是在Point 1处我们有一个if判断语句,表面上看,我们的MethodClass可能用不到,所以它不会编译,但实际上,方法中和作用域的内部类在一开始就编译了。
class A{
public void display(){
if(true){// point 1
class MethodClass{//我们在方法中创建了一个类

}
}
}
}
  • 匿名内部类:
    所谓的匿名内部类,其实也就是在方法或者作用域内创建一个没有名字的类,因为匿名内部类不能有构造函数,所以匿名内部类的重点部分是数据的初始化,我们将分为几个版本来介绍。具体代码如下:
<b>第一个版本,接口的匿名内部类</b>
interface Contents{
    int value();
}
public class Paracel{
public Contents contents(){
   return new Contents(){//我们直接new一个接口就行了
   private int i = 11;//值得注意的是,我们可以直接在内种定义并且初始变量
   public void int value(){return i;}
}
}
}
<b>第二个版本,没有默认构造器的类的匿名内部类</b>
public class Wrapping{
   private int i;
   public Wrapping(int x){//我们的这个类只有一个带参数的构造函数
         i = x;
  }
  public int value(){return i;}
}
public class Paracel{
public Wrapping wrapping(int x,final y){
return new Wrapping(x){
{print("Inside instance initializer");//我们可以用这种方式充当匿名内部类
}
    private String yValue = y;//我们也可以初始化值,但是值得注意的是,从匿名内部类引入外部的值,必须是final的,如果是构造器函数的,就不需要了。这是因为这个方法的生命周期比匿名内部类要短,方法返回后,堆栈的值就清空的,所以传入的这个值实际上是重新复制了一遍到匿名内部类中,为了不要让其值被修改而产生误会,所以使用了fianl这种方式。但对于构造器的传值,他并不会在匿名内部类内部被直接使用。
     public int value(){
         return super.value;
}
}
}
}
  • 匿名内部类只能实现一个接口或者一个类。
  • 嵌套类就是static修饰的内部类,他不会持有外部类的引用,所以我们不能访问外围内的非静态变量或者方法,嵌套类的private方法和字段是可以被外围类访问的。普通内部类和外围类有一个区别就是:普通的内部类不能持有static数据和方法,但是嵌套类是可以持有static方法和变量的。为什么普通内部类不能持有静态变量或者方法:
静态变量是要占用内存的,在编译时只要是定义为静态变量了,系统就会自动分配内存给他,而内部类是在宿主类编译完编译的,也就是说,必须有宿主类存在后才能有内部类,这也就和编译时就为静态变量分配内存产生了冲突,因为系统执行:运行宿主类->静态变量内存分配->内部类,而此时内部类的静态变量先于内部类生成,这显然是不可能的,所以不能定义静态变量!

7.接口中的内部类:如果你想要创建某些公用代码,是的他们可以被某个接口的所有不同实现所共同,那么使用内部的嵌套类会显得很方便。值得注意的是,我们放在接口中的任何类都强制成为public static类型的。接口中定义类的示例代码如下:

interface A{
    class Test{//注意这里强制成为public static类型的
          public void display(){

}
}
}

8.内部类的存在,让我们有效的实现了多重继承。
9.闭包是一个可调用的对象,它记录了一些信息,这些信息来源于创建它的作用域。我们的内部类就是典型的闭包:内部类持有当前作用域外围对象的方法访问和变量访问权限。下面是示例代码:

public class Main {

    public static void main(String[] args) {
        OuterClass1 outerClass1 = new OuterClass1();
        OuterClass1.InnerClass innerClass = outerClass1.new InnerClass();
        innerClass.show();//我们通过内部类,能调用它外围类的接口。记得我们闭包的定义:一个对象记录了一些信息,这些信息来源于创建它的作用于,这个作用于就是外围类的方法和变量了。
    }
}

class OuterClass1 {
    void display() {

    }

    class InnerClass {
        void show() {//这就是闭包的使用了,这个内部类能调用外围类的变量和方法
            display();
        }
    }
}

10.继承一个内部类,必须在构造器中指明外围类对象,但如果一个类中的内部类继承了父类的内部类,那么它的方法调用和构造函数的写法跟正常继承是一样的,在构造函数并不用传入外围类对象,这是因为这个内部类的外围类已经持有了继承内部类父类的对象了(继承关系,子类会持有父类的一个对象)。具体代码示例如下:

//这种情况下描述的是内部类继承非外围类父类的内部类。
class WithInner{
      class Inner{}
}
public class InheritInner extends WithInner.Inner{
       IheritInner(WithInner wi){//这里我们的构造器必须有外围类对象这个参数
                  wi.super();//调用super方法
}
}
//这种情况下描述的是内部类继承外围类父类的内部类
class OuterClass1 {
    void display() {

    }

    class InnerClass {
        void show() {
            display();
        }
    }
}
class OuterClass2 extends OuterClass1{
    class InnerClass1 extends OuterClass1.InnerClass{

    }

}

11.一个类如果重写一个跟父类内部类一模一样的类,它并不会覆盖这个类,他们两个类有各自的命名空间。
12.局部内部类是不能使用访问说明符的,我们使用局部内部类而不使用匿名内部类的唯一理由就是:需要不止一个该类的内部类。
13.内部类生成class文件的命名规范:

  • Counter.class 外围类
  • LocalInnerClass$1.class匿名内部类
  • LocalInnerClass$1LocalCounter.class 局部内部类

14.为什么需要内部类?实际上我们的接口也可以实现内部类的功能。内部类和接口一样,都是为了解决多重继承的问题,但是内部类能够处理的更加好一些。在某些情况下,我们必须是要用内部类才能完成多重继承的:

interface A{}
interface B{}
//examples 1
Class CA implements A,B{//我们可以通过直接继承实现内部类

}
//examples 2
Class InnerA implements A{
    B getB(){//在这里,我们通过内部类实现多重继承
    return new B(){};
}
}
//然而,如果出现这种情况,没有内部类我们是无能为力的:
abstract AA {}//这里有两个类,我们怎么多重继承?
class BB{}
Class InnerB extends AA{
    AA getAA(){
        return new AA(){};
    }
}

我们如何选择是使用接口还是内部类?一般情况下,能直接用继承多个接口解决的多重继承,我们就直接用接口。因为接口用起来简单

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值