Java学习笔记0:内部类

关于Java内部类

1.啥是内部类?

一个定义在别的类中的类

2.创建内部类

(1)把类的定义放在外部类里即可

(2)一个常见的用法是外部类里有一个方法,该方法返回指向内部类的引用

(3)如果想在外部类里创建一个内部类对象,直接使用”new 构造方法“即可

(4)如果在外部类外面,内部类名为“外部类名.内部类名"

3.链接外部类

(1)内部类最特别之处在于:当我们生成一个内部类对象时,他可以访问其外部类对象的所以成员

这必须要求一件事,就是内部类里隐式的存了一个外部类对象的引用

这又可以推断出一件事,内部类对象是基于外部类对象的,也就是说得先有外部类对象,才能生成内部类对象(非static 内部类)

由此引出了.new 与.this

(2).new与.this

通过“外部类名.this”我们可以得到外部类对象的引用

当我们有一个外部类对象时,我们想创建一个基于他的内部类对象时,使用“外部类对象.new 内部类构造方法”即可

(注意:我们不能在没有外部类对象的情况下创建非static内部类对象,这时因为内部类必须链接到外部类上)

例如:outerClass.innerClass myinner=new outerClass().new innerClass

等价于:outerClass myouter=new outerClass();outerClass.innerClass myinner=myouter.new innerClass;

4.内部类与向上转型

我们可以通过private内部类实现一个接口,这样做的好处是此接口的实现完全不可见,我们只能通过一个方法得到此接口的引用

(可以对比下直接在外部类里实现接口)

到此为止,我们展示的都是内部类的平凡用法,接下来我们会讲解一些内部类的复杂用法

例如:匿名类,嵌套类,定义在方法中的类(局部内部类)-->任意作用域里的类

 

5.匿名内部类

(1)直接给一个例子:

 

// innerclasses/Parcel7.java
// Returning an instance of an anonymous inner class
public class Parcel7 {
    public Contents contents() {
        return new Contents() { // Insert class definition
            private int i = 11;
          
            @Override
            public int value() { return i; }
        }; // Semicolon required
    }
  
    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Contents c = p.contents();
    }
}

 

我们可以看到,contents方法把返回值与定义结合在了一起,这得到了一个什么呢?

没错,我们在创建Contents类的对象时定义并创建了一个继承自Contents类的匿名类的对象(注意Contents可以是类,抽象类,接口)

(2)在定义内部类时,如果我们要使用一个外部类对象,编译器要求这个对象必须是final的,或者“effectively final”即虽然不加final 关键字,但是不能对其做修改

(3)匿名类的限制:不能重载初始化方法了,并且和正规继承相比,匿名类要么继承类,要么继承接口,并且都只能继承一个。

 

6.嵌套类

(1)嵌套类就是static的内部类,他和外部类没有啥联系:我不需要外部类对象就可以创建内部类对象;我们也不能通过内部类对象访问外部类非static对象

(2)嵌套类和普通内部类的另一个区别是,普通内部类是放在外部类层次上的,所以普通内部类不能有static字段(我的理解:static不基于任何对象而存在,类只是给了他一个命名空间,而内部类对象是基于外部类对象的,所以如果内部类里有static字段,这个字段得基于外部类对象,这显然是矛盾的),当然也不能包含嵌套类,但是嵌套类却可以。

(3)嵌套类对象可以在外部类中创建,那么怎么在外部类之外创建嵌套类对象呢?以下例子可以说明

public class test_of_innerclass {

   static class myinner{}

  myinner a=new myinner();

}

 

class test{

  test_of_innerclass.myinner tt=new test_of_innerclass.myinner();

}

(4)接口中的任何类都是嵌套类,注意到static类只是将这个类置于了外部类的命名空间中,其实他跟外部类没啥关系,所以一个很神奇的情况是:我们可以用接口里的嵌套类实现接口,如以下例子

// innerclasses/ClassInInterface.java
// {java ClassInInterface$Test}
public interface ClassInInterface {
    void howdy();
    class Test implements ClassInInterface {
        @Override
        public void howdy() {
            System.out.println("Howdy!");
        }
        public static void main(String[] args) {
            new Test().howdy();
        }
    }
}

如果你想让某些代码被某个接口的所有实现共用,使用嵌套类会比较方便

(5)考虑我们可能创建一个多重嵌套的内部类,他被嵌套多少层不重要,他能透明的访问他所嵌入的外部类的所以成员

7.为什么我们需要内部类?

内部类最大的用途是我们可以用每个内部类实现一个接口或继承一个抽象类,这解决了多继承问题!

回想一下,一个类最多只能继承一个抽象类,使用内部类我们可以继承多个内部类,并且用多个内部类

实现多个接口时比用一个外部类实现多接口要方便的多。甚至我们可以用多个内部类用不同的方式实现

接口。并且内部类可以有多个实例,每个实例都有自己的状态信息,还与其外部类对象的信息相互独立。

8.闭包与回调(这个概念我也不是很明白,只能讲下我的理解)

(1)闭包就是一个对象,他记录了创建他的作用域的一些信息,例如内部类就是面向外部类的闭包

(2)回调是指对象带回了一些信息,这些信息可以让他在之后的某个时刻调用初始的对象

(3)通过内部类我们可以实现回调

9.内部类的继承问题

(1)如果我们现在有一个类,他想只继承内部类而不继承外部类,我们该怎么做呢?

首先我们知道内部类的构造器必须链接一个外部类对象的引用,所以这个引用必须被初始化

所以我们可以向派生类的构造器传一个外部类引用,并且让这个引用调用外部类构造器,例子如下:

class WithInner {

 class Inner {}

}

class InheritInner extends WithInner.Inner {

 //- InheritInner() {} // Won't compile

 InheritInner(WithInner wi) {

     wi.super();

 }

 public static void main(String[] args) {

     WithInner wi = new WithInner();

     InheritInner ii = new InheritInner(wi);

 }

}

 只有提供了必要的引用,编译才会通过

(2)内部类可以被重写吗?

重写并不起作用,当继承了某个外部类时,他的内部类并不会发生什么变化,可以理解为这两个内部类是完全独立的,各自在自己的命名空间内

如果我们要创建一个内部类对象还是要使用“其外部类.内部类名 XXX=new 其外部类.new 内部类名”

10.局部内部类

(1)我们可以在代码块里创建内部类

最常见的是在方法里创建一个类,但这个内部类没有访问说明符(即我们不能在方法块之外创建这个类),因为他不是外部类的一部分,但是他可以访问当前代码块里的东西和外部类的所以成员

(2)局部内部类和匿名类的比较

局部内部类和匿名类相似之处在于他们都是匿名的,不过匿名类是绝对匿名,局部内部类是在方法外匿名

那么我们为什么不用匿名类替代局部内部类呢?

原因是局部内部类可以有一个有命名的构造器,那么有了构造器又能怎么样呢?

有了构造器我们可以创建多个该局部内部类的对象

11.内部类标识符

(1)非匿名类的class文件:外部类+“$”+内部类名

(2)匿名类的class文件 :用数字代替类名

Counter.class
LocalInnerClass$1.class
LocalInnerClass$1LocalCounter.class
LocalInnerClass.class
posted @ 2021-04-28 11:46  tzy_QaQ  阅读(81)  评论(0)    收藏  举报