本次记录内部类,内部类我感觉挺特别的,既有类的感觉,又有方法和变量的感觉。内部类是定义在类里的,所以我们通常把内部类之外的类,称为外部类。
成员内部类
我们都知道,在类定义的变量称为成员变量,内部类也一样,定义在类里的类,就是成员内部类。
1 | class A |
上面就是成员内部类的表示,那怎么使用呢。先想想,类,我们一开始使用时,如果它使用的都是普通方法,要先new对不对。如果是静态方法,则可以引入这个类,直接调用。是不是有感觉了。是类,要先new,是静态,可以直接使用,是不是内部类也有这样的属性呢,对,没错。
1 | public class innerClass { |
都如期打印相应的print()方法,我们也看得出来,我们在使用内部类的时候,都要先new父类的对象,如果内部类是静态,直接 . 使用,否则还要new内部类的对象。
当然,这里如图补充一句,平时我们写java代码,编译器都会给我们的代码编译成.class的字节码,方便虚拟机在任何平台运行,而上图也看得出来,我们的代码虽然在同一个java文件,但是编译器会把它以类的形式分开,而且,如果是内部类,则会有一个$符号,表示它是谁的内部类。
还有,你也可以不停的写内部类里写内部类,内部类里的内部类写内部类里的内部类的内部类……有点像递归啦。下面则是一个例子。而它的.class也就生成了 A$C$D.class 这样,会一直延伸下去。
1 | public class innerClass { |
上面的代码里有个this,this指向当前对象。谁的当前对象,是C的。当前C的print()方法。所以这里先后打印了我是D和我是C。等下就讲外部类使用内部类的属性方法,内部类如何使用外部类的属性方法。
局部内部类
局部内部类就像局部变量一样,出了相应的范围就不能使用。所以我们只能在方法里使用局部内部类,它的外部类是不能调用的。
1 | public class innerClass { |
外部类和内部类的互相使用
先看一看外部类如何使用内部类的属性和方法吧。
1 | public class innerClass { |
看到很多有意思的东西,我们把内部类B私有化,这样内部类B就是外部类A独享的moment,所以它不能被其他类所访问,我们可以在外部类中,使用方法去新建内部类,使用它的方法,属性。而我们也看到,内部类中的z是私有的,但是我们可以在外部类中使用,看到z被赋值啦。
注意啦,外部类使用内部类可以在方法里调用。外部类也可以使用内部类私有的属性和方法。
下面则是内部类使用外部类的方法和属性。
1 | public class innerClass { |
可以看得出来,内部类在使用外部类属性方法时,也同样在方法里使用,但可以直接使用。如果内部类和外部类有相同的变量名,可以用this来指向外部类的变量。而且,也同样,内部类也可以使用外部类的私有属性方法。
当然,这就有一点要注意的,上面两个代码,内部类都是非静态内部类。我们在前面的学习可以知道,在我们运行代码时,虚拟机会提前把静态的,常量,方法名加载到内存中,如果内部类为静态的呢,会怎么样。
1 | public class innerClass { |
在上面的代码中,注释的都是报错的代码,而这些代码则是静态内部类使用外部类的属性方法。而外部类,则可以使用静态内部类的方法属性。为什么呢,还是和虚拟机运行机制有关。静态先加载出来,所以一开始静态内部类就比外部类先出现在内存上,而静态内部类要使用外部类的方法属性时。编译器找不到外部类,因为它没加载到内存上,所以报错。在外部类为什么能使用呢,也很简单,当我们使用外部类的时候,一定是把这个类先new出来了,虽然内部类提前加载到内存上,但new出了外部类,自然也就能使用静态内部类的方法属性。
以上是内部类像普通变量一样,有静态的,私有的,公共的,成员或局部。当然,内部类也可以定义为final修饰的,但,那就和私有差不多,只能外部类使用,而且比私有更恐怖的就是不能更改,毕竟final修饰。
抽象内部类
上面说完了内部类像变量一样的使用,而我们的类,除了普通的类,还是抽象类和接口对不对。所以内部类也有这样的特征,但也有不一样的地方。
1 | public class innerClass { |
上面就是抽象内部类的两种使用,当然,第一种肯定是不推荐使用的那种,方法全写在main方法里了,占空间,不好看。推荐下面的那种写法,和普通抽象类一样的继承使用。
内部接口
1 | public class innerClass { |
和抽象内部类使用方法差不多,也没啥好说的,毕竟接口就是比抽象类更抽象的类。
匿名内部类
匿名类就是没有变量名的类,之间new一个类使用它的方法。比如下面的类,直接使用,当然,这种类就是一次性的,因为没有名字。
1 | public class innerClass { |
那内部类的匿名怎么使用呢?
1 | public class innerClass { |
如上使用,在内部类把抽象类或接口的方法实现,然后调用相应的方法,可以看到最后有个.print()。我调用了这个方法。匿名内部类的要点就是要实现抽象类或接口的方法,而这些方法可能只用一次。