回看基础--Java内部类详解

(一)、内部类的定义:定义在另一个类中的类。

(二)、内部类的特点

    1.内部类的方法可以访问 该内部类所在的 作用域中(类域或方法域)的数据,包括私有数据;

    2.内部类的对象之所以可以访问外部类对象中的数据域,是因为内部类对象中有一个 隐式的引用(但static内部类没有这种附加指针 ,它引用了实例化该内部对象的外部类对象。这个引用在内部类的定义中是不可见的;内部类对象对 外部类对象的引用是在构造函数中设置的, 编译器修改了所有内部类的构造函数,在构造函数中添加了一个外部类对象引用的参数;

    3.内部类可以对 同一个包中的其他类隐藏起来(可以防止命名冲突等);

    4.某些地方可以使用匿名内部类简化代码编写,如:回调函数中;

    5.只有内部类可以是私有的,只有内部类可以是static的;常规类,最多只能是public或默认包可见性的;

    6.内部类是一种 编译器现象,与虚拟机无关。编译器将会把内部类翻译成$(美元符号)分隔外部类名与内部类名的常规文件,而虚拟机对此一无所知。

(三)、内部类的特殊语法规则:

代码1:
  1.   
  1. package com.flan.learn;  
  2.   
  3. /** 
  4.  * 带有内部类的外部类 
  5.  * @author lynn 
  6.  */  
  7. public class OuterClass {  
  8.       
  9.     //静态域  
  10.     private static int age = 24;  
  11.     //实例域  
  12.     private String name ="out flan";  
  13.       
  14.     //外部类的方法中创建使用内部类  
  15.     public void useInnerClass(){  
  16.           
  17.         //此处可以加this,也可以省略  
  18.         InnerClass in = this.new InnerClass();    
  19.         in.ImInner();  
  20.           
  21.         //此处不能加this,因为static的属于类,而不属于某个对象  
  22.         StaticInnerClass sin = new StaticInnerClass();    
  23.         sin.ImStaticInner();  
  24.     }  
  25.       
  26.     //普通方法  
  27.     public void ImOuter(){  
  28.         System.out.println("OuterClass中的普通方法-- > "+name);  
  29.     }  
  30.       
  31.       
  32.       
  33.     /** 
  34.      * 普通内部类,编译器会修改其构造函数, 
  35.      * 将外部类的引用传递进来 
  36.      * 访问控制符同普通成员方法一样: 
  37.      * public   则所有包的任何类中都可以访问该类并创建对象 
  38.      * private  则除了外部类,其他任何类中都无法访问(只有内部类可以是私有的) 
  39.      * protected 则只有子类和外部类中可以访问并创建对象 
  40.      * 默认(不写)   则只有同包中的类,子类,外部类可以访问并创建对象 
  41.      * @author lynn 
  42.      */  
  43.     public class InnerClass{  
  44.           
  45.         private String inName = "in flan";  
  46.           
  47.         public void ImInner(){  
  48.             System.out.println("InnerClass 外部类数据域-- > "+name);  
  49.             System.out.println("InnerClass 内部 内数据域-- > "+inName);  
  50.         }  
  51.     }  
  52.       
  53.     /** 
  54.      * 静态内部类,编译器不会将外部类的引用传递进来(除此以外其他特性跟普通内部类一样) 
  55.      * 只有内部类可以是static的 
  56.      * 访问标号规则同普通内部类 
  57.      * @author lynn 
  58.      */  
  59.     public static class StaticInnerClass{  
  60.           
  61.         private String stName = "static in flan";  
  62.           
  63.         public void ImStaticInner(){  
  64.             //这里只能使用静态域中的数据  
  65.             System.out.println("StaticInnerClass 外部类静态域 -- > "+age);   
  66.             System.out.println("StaticInnerClass 内部类普通域-- > "+stName);     
  67.         }  
  68.     }  
  69.       
  70. }  

代码2:

  1. package com.flan.learn;  
  2.   
  3. /** 
  4.  * 测试类 
  5.  * 同包下 其他类中访问内部类 
  6.  * 内部类的访问控制符不能是private的 
  7.  * @author lynn 
  8.  */  
  9. public class OuterClassTest {  
  10.       
  11.     public static void main(String[] args) {  
  12.           
  13.         OuterClass out = new OuterClass();  
  14.         out.ImOuter();  
  15.         System.out.println("-------------------------------------");  
  16.           
  17.         out.useInnerClass();  
  18.         System.out.println("-------------------------------------");  
  19.           
  20.         //创建普通 内部类(注意new前的out对象)  
  21.         OuterClass.InnerClass in = out.new InnerClass();  
  22.         in.ImInner();  
  23.         System.out.println("-------------------------------------");  
  24.           
  25.         //创建静态内部类(这里不需要out对象)  
  26.         OuterClass.StaticInnerClass sin = new OuterClass.StaticInnerClass();  
  27.         sin.ImStaticInner();  
  28.         System.out.println("-------------------------------------");  
  29.           
  30.     }  
  31. }  

(四)、局部内部类:

    1.局部类一般定义在方法中。

    2. 局部类不能用public和private访问符进行声明。它的作用域被限定在声明这个局部类的块中。

    3.局部类有两个优势:①对外部世界可以完全地隐藏起来(外部类中也不可以访问局部类);②局部内部类不仅能够访问包含它的外部类,还可以访问局部变量(不过这些 局部变量必须声明为final);

    4.局部内部类中访问局部变量必须为final的,但有时候确实需要修改局部变量,因此会带来不便。补救办法是: 使用一个长度为1的final数组来保存对应的局部变量

    局部内部类访问的局部变量必须为final的原因(见代码3):

代码3:
  1. package com.flan.learn;  
  2.   
  3. /** 
  4.  * 测试类 
  5.  * @author lynn 
  6.  */  
  7. public class GeneralClassTest{  
  8.       
  9.     public static void main(String[] args) {  
  10.           
  11.         GeneralClass glc = new GeneralClass();  
  12.         //①注意,当该方法执行结束后,参数true(isRun)就会被释放,而在循环打印线程中的②处,还要使用isRun,因此会导致错误;  
  13.         //所以,语法要求将isRun参数设置为fianl的,这样编译器会将isRun作为参数,加入到局部内部类构成函数中,  
  14.         //且在局部内部类中增加一个对应的实例域,这样在局部内部类中就保存有对应参数的副本;  
  15.         glc.startPrint(true);  
  16.     }  
  17.       
  18. }  
  19.   
  20. /** 
  21.  * 含有局部内部类的  普通类 
  22.  * @author lynn 
  23.  */  
  24. class GeneralClass {  
  25.       
  26.     //普通类中的一个含有局部内部类的方法  
  27.     public void startPrint(final boolean isRun){  
  28.           
  29.         //局部内部类  
  30.         class LocalInnerClass{  
  31.               
  32.             //局部内部类中的一个普通方法,用来循环打印字符串  
  33.             public void cyclePrint(){  
  34.                   
  35.                 //这是一个匿名内部类,用来循环打印线程(暂时不用关注,后面会解释)  
  36.                 new Thread(){  
  37.                     @Override  
  38.                     public void run() {  
  39.                           
  40.                         //②注意这里的 isRun  
  41.                         //编译器会在本局部内部类中增加一个实例域,用于保存该变量  
  42.                         while (isRun) {  
  43.                         //③当方法产生中的局部变量不能设置为final时,可以用一个长度的数组来解决  
  44.                         //boolean[] run = new boolean[1];  
  45.                         //run[0] = isRun;  
  46.                         //while (run[0])  
  47.                             try {  
  48.                                 Thread.sleep(1000);  
  49.                             } catch (InterruptedException e) {  
  50.                                 e.printStackTrace();  
  51.                             }  
  52.                             System.out.println("我在循环 "+System.currentTimeMillis());  
  53.                         }  
  54.                     }  
  55.                 }.start();  
  56.             }  
  57.         }  
  58.           
  59.         //普通方法中的 逻辑,即调用内部类中的方法,来打印字符串  
  60.         LocalInnerClass lic = new LocalInnerClass();  
  61.         lic.cyclePrint();  
  62.     }  
  63. }  

(五)、匿名内部类:

    1.将局部内部类的使用再深入一步,即匿名内部类(匿名内部类一定是局部内部类);

    2.由于构造函数的名称必须与类名相同,而匿名内部类内没有类名,所以, 匿名内部类不能有构造函数

    3.匿名内部类一般有两种用法:①实现接口;②扩展超类中的方法(即重写超类中的方法);

    4.语法规则:
  1. <span style="white-space:pre">  </span>//①扩展超类  
  2.         //其中的构造函数中的参数必须是父类中有的  
  3.         new SuperType(construction param)  
  4.         {  
  5.             //内部类中的函数及实例域  
  6.         }  
  7.           
  8.         //②实现接口  
  9.         //小括号内不能有参数  
  10.         new InterfaceType()  
  11.         {  
  12.             //接口中需要实现的方法  
  13.             //可以使用方法的局部参数  
  14.         }  

代码4:
  1. package com.flan.learn;  
  2.   
  3. /** 
  4.  * 匿名内部类两种基本用法 
  5.  * @author lynn 
  6.  */  
  7. public class AnonymityInnerClass {  
  8.       
  9.     public static void main(String[] args) {  
  10.           
  11.         AnonymityInnerClass aic = new AnonymityInnerClass();  
  12.         aic.uperClass();  
  13.         aic.superInterfaceFirst();  
  14.     }  
  15.       
  16.     //扩展超类中的函数  
  17.     public void uperClass(){  
  18.           
  19.         //①扩展超类  
  20.         //可以选用带参数的Thread构造函数  
  21.         Thread t = new Thread()  
  22.         //花括号中的代码是匿名内部类的逻辑  
  23.         {     
  24.             @Override  
  25.             public void run() {  
  26.                 //在这里对超类Thread中的run方法添加逻辑  
  27.                 System.out.println("我扩展了超类中的方法 --> Thread");  
  28.             }  
  29.         };  
  30.           
  31.         t.start();  
  32.     }  
  33.       
  34.     //实现接口中的方法  
  35.     public void superInterfaceFirst(){  
  36.           
  37.         //②实现接口  
  38.         //小括号内不能有参数  
  39.         FirstInterface ff = new FirstInterface()   
  40.         //花括号中的代码是匿名内部类的逻辑  
  41.         {  
  42.             //接口中需要实现的方法  
  43.             @Override  
  44.             public void ImFirst(int first) {  
  45.                 System.out.println("我实现了接口中的方法 --> "+first);  
  46.             }  
  47.         };  
  48.           
  49.         ff.ImFirst(111111);  
  50.     }  
  51.       
  52. }  
  53.   
  54. /** 
  55.  * 普通接口 
  56.  * @author lynn 
  57.  */  
  58. interface FirstInterface {  
  59.       
  60.     public void ImFirst(final int first);  
  61.       
  62. }  

(六)、静态内部类

    1.如果使用内部类 只是为了把一个类隐藏在另一个类中,并不需要在内部类中引用外部类对象,就可以把内部类声明为static的。

    2.static的内部类不会有对外部类对象的引用。

    3.声明在 接口中的内部类,自动成为public和static。


声明:文章内容主要为读书笔记,理解错误地方欢迎大家拍砖,参考书为《JAVA 核心技术》第八版;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值