对象(七)
一、内部类(inner class)的概述
内部类,顾名思义就是定义在一个类中的一个类。如:
1 class OuterClass{ 2 3 class InnerClass{ 4 5 } 6 }
接下来,我们就来谈谈为什么要使用内部类,以及他有什么特点,如何使用等等。
1.为什么要使用内部类呢?
- 内部类方法可以访问该类定义所在的作用域数据,包括私有数据。
- 内部类可以对同一个包中的其他类隐藏起来。
- 当你想定义一个回调函数不想编写大量代码是,使用匿名内部类比较便捷。[1]
2.内部类访问特点以及如何使用
- 使用原因其实也就是其特点之一:可以访问该类定义所在的作用域数据,包括私有数据。
- 外部类访问内部类成员,则必须要创建对象。
见代码:
1 public class Test_InnerClass { 2 public static void main(String[] args){ 3 //外部类名.内部类名 对象名 = 外部类对象.内部类对象; 4 OuterClass.InnerClass oi = new OuterClass().new InnerClass(); 5 //调用方法 6 oi.method(); 7 } 8 } 9 10 class OuterClass{ 11 private int num = 10; 12 class InnerClass{ 13 public void method(){ 14 System.out.println(num); //可以直接访问外部类的成员变量 15 System.out.println("感谢关注~"); 16 } 17 } 18 }
结果:
二、成员内部类私有(private) & 静态成员内部类(static)
1.成员内部类私有
所谓成员内部类私有也就是把内部类加个private,变成私有的。如:
1 class OuterClass{ 2 private class InnerClass{ 3 public void method(){ 4 System.out.println("感谢关注~"); 5 } 6 } 7 }
InnerClass前面加个private关键字,没错,就是这样。
那么如何使用呢?
talk is cheap,show me the code.来:
1 class OuterClass{
2
3 private class InnerClass{//成员内部类被私有了
4 public void method(){
5 System.out.println("感谢关注~");
6 }
7 }
8
9 //通过在外部类当中写一个方法实例化内部类,调用其方法
10 public void invokeMethod(){
11 InnerClass innerClass = new InnerClass();
12 innerClass.method();
13 }
14
15 }
如果想要调用,那么就在通过在外部类当中写一个方法实例化内部类,调用其方法。
2.静态成员内部类
静态成员内部类,在内部类加static。如:
1 public class Test_InnerClass { 2 public static void main(String[] args){ 3 //外部类名.内部类名 对象名 = 外部类名.内部类对象; 4 OuterClass.InnerClass o = new OuterClass.InnerClass(); 5 o.method(); 6 } 7 } 8 9 class OuterClass{ 10 static class InnerClass{ 11 public void method(){ 12 System.out.println("Hello World"); 13 } 14 } 15 }
结果:
可见,通过外部类名.内部类名 对象名 = 外部类名.内部类对象,进行调用。
可能到这里,有一点会产生混淆。就是单纯内部类调用时和静态内部类调用时。
因此做个比较:
普通内部类调用 |
外部类名.内部类名 对象名 = 外部类对象.内部类对象
|
静态内部类调用 |
外部类名.内部类名 对象名 = 外部类名.内部类对象 OuterClass.InnerClass o = new OuterClass.InnerClass();
|
普通内部类以及静态内部类,了解即可。哈哈
接下来看看这个题目:(要求控制台输出 30,20,10)
1 class Outer { 2 public int num = 10; 3 class Inner { 4 public int num = 20; 5 public void show() { 6 int num = 30; 7 System.out.println(A); 8 System.out.println(B); 9 System.out.println(C); 10 } 11 } 12 } 13 class TestInnerClass{ 14 public static void main(String[] args) { 15 Outer.Inner oi = new Outer().new Inner(); 16 oi.show(); 17 } 18 }
A B C如何填呢?
内部类之所以能获取到外部类的成员,是因为他能获取到外部类的引用。外部类.this,进而获取到他的值。
三、局部内部类(方法里面的内部类)
所谓局部内部类,其实就是方法里面的内部类。如:
1 public class Test_InnerClass { 2 public static void main(String[] args) { 3 OuterClass outerClass = new OuterClass(); 4 outerClass.method(); 5 } 6 } 7 8 class OuterClass { 9 10 public void method() { 11 class InnerClass { //局部内部类 12 13 public void playChiJi(){ 14 System.out.println("大吉大利,今晚吃鸡~"); 15 } 16 } 17 //只能在方法里进行实例化并访问吃鸡方法 18 InnerClass innerClass = new InnerClass(); 19 innerClass.playChiJi(); 20 } 21 22 /* 23 这种方法行不通,因为作用域的问题,内部类只存在于方法内,因此在外部类里实例化不了InnerClass 24 public void invoke(){ 25 InnerClass innerClass = new InnerClass(); 26 innerClass.playChiJi(); 27 } 28 */ 29 }
结果:
那局部内部类访问局部变量呢?
1 public class Test_InnerClass { 2 public static void main(String[] args) { 3 OuterClass outerClass = new OuterClass(); 4 outerClass.method(); 5 } 6 } 7 8 class OuterClass { 9 public void method() { 10 final int num = 10; 11 class InnerClass { //局部内部类 12 13 public void playChiJi(){ 14 System.out.println(num);//局部内部类访问局部成员方法 15 } 16 } 17 //只能在方法里进行实例化并访问吃鸡方法 18 InnerClass innerClass = new InnerClass(); 19 innerClass.playChiJi(); 20 } 21 22 }
结果:输出10.
在jdk1.8之前,局部变量前面必须加final修饰,因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用。简而言之,就是加了final就延长了局部变量的生命周期,方法弹栈可以继续访问。
但是,jdk1.8以后可以不加final。其实是默认替你添加上了。
四、匿名内部类(没有名字的类?)
对,其实就是没有名字的类。哈哈。
实际上是对内部类的一种简写,适合哪种只调用一次方法的情形。
(非匿名内部类)
1 public class Test_InnerClass { 2 public static void main(String[] args) { 3 OuterClass outerClass = new OuterClass(); 4 outerClass.method(); 5 } 6 } 7 8 //定义一个接口 9 interface NoNameInter { 10 void playLOL(); 11 } 12 13 class OuterClass { 14 15 class InnerClass implements NoNameInter { 16 //重写方法 17 @Override 18 public void playLOL() { 19 System.out.println("晚上一起开黑~"); 20 } 21 } 22 23 //这个是有名字的内部类 24 public void method(){ 25 InnerClass innerClass = new InnerClass(); 26 innerClass.playLOL();; 27 } 28 }
(匿名内部类)
1 public class Test_InnerClass { 2 public static void main(String[] args) { 3 OuterClass outerClass = new OuterClass(); 4 outerClass.method(); 5 } 6 } 7 8 //定义一个接口 9 interface NoNameInter { 10 void playLOL(); 11 } 12 13 class OuterClass { 14 15 public void method(){ 16 17 new NoNameInter(){//匿名内部类 18 //重写方法 19 @Override 20 public void playLOL() { 21 System.out.println("晚上一起开黑~"); 22 } 23 }.playLOL(); 24 } 25 26 }
咱们得一个一个进行解释,首先匿名内部类书写的格式是:
new 类名或者接口名(){
重写方法;
}
前提:存在一个类或者接口
这里的类可以是具体类也可以是抽象类,正如代码中的按个NoNameInter接口。
他的本质是继承了该类或者实现了该类接口的子类匿名对象。我去,好绕口。就是,
这就是匿名内部类的书写方式,以及用法。
如有错误之处,欢迎指正。