您的位置:首页 > 编程语言 > Java开发

Java内部类学习总结

2015-11-23 16:49 351 查看
内部类即在一个类的内部编写额外的class。编写完以后会生成OutterClassName$InnerClassName(匿名内部类用数字递增)的文件。外部类只能使用public,final,默认修饰符。但是内部类还可以使用private,static,protected等等修饰符。

内部类也是一种编程方式,为什么要使用内部类呢?

*把相互有关联的对象组织到一起,而且外部用不到的对象又可以完全对外隐藏细节。看看java的集合对象源码吧,HashMap的内部结构,你一下就会明白这样写的好处。

*每个内部类独立的继承或实现,不依赖外部类继承的类或实现的接口,这样使多态更完善。同样看java的集合包源码,iterator等。

*结合回调写法使用,常用在监听器,模板实现等,可以写出清晰简洁的代码,易于阅读和维护。和回调的结合可以参考另外一篇博文Java回调的概念

内部类的规则比较复杂,重在理解其本质,这样如果在面试时遇到问题,就不需要硬背而是可以推理出来了:

普通内部类:

依赖于外部类而存在,必须先有外部类实例。外部类要访问时,要用new 【外部类对象】【内部类对象】.属性/方法。

即使是private,也可以随意使用外部类的变量和方法。如果要为什么可以,那就是编译器其实偷偷的在初始化的时候给内部类设置了一个隐藏的外部类对象的引用。

语法上不能有static成员变量和方法(所以也不能有main函数),这是因为依赖外部类实例,和static是矛盾的。

静态内部类,又叫嵌套内部类(。。。这是什么鸟名字啊):

不依赖于外部类对象存在,可以直接使用【内部类名】.静态的属性/方法,如果要使用非静态的属性/方法,也需要new,因为非静态是和对象一个级别初始化的。静态是和类一个级别初始化的。

static内部类只能访问外部类的static变量和方法,可以有自己的main函数。

个人理解静态内部类,并不是说为了使这个类是静态的,而目的是为了使用里面的静态变量和方法。

*局部内部类是指定义在方法中或作用域中,其可使用的变量和方法,当然也局限于方法和作用域中了。局部内部类,就相当于方法的局部变量,是不能有修饰符的。

*匿名内部类,同样不能有修饰符。匿名内部类不能有自己的构建器,如果想要初始化这个内部类时设置其中对象的值,则需要从外部传递一个变量进来,这个变量必须是final的否则报错。怎么传递?作为方法参数,在方法体内写匿名内部类。

内部类的继承与被继承

内部类可以实现别的地方的接口,可以继承别的地方的抽象类。如果把这个内部类设为private,在外部其他类使用这个有内部类的类提供的get方法时,可以通过upcasting获得那个接口或者抽象类的引用。但是却永远不可能获得内部类,因为是Private的所以你连内部类的名字都没有机会知道。 这样这个内部类是非常安全的,不可能被downcasting,这是一种编码策略。可以说内部类和upcasting的思想经常是联系在一起使用的。

可以从一个别的class A去继承一个类的内部类,继承的语法必须是extends Outer.Inner。并且你必须写一个构造函数,把outer作为参数传递给这个构造函数,并调用Outer.super()。为什么是super呢?Super()表示,要找到这个类继承树的最上层,从那个地方的构造函数开始,把树上的每个类逐一初始化一直初始化到内部类,这样才能保证这个class A能够正确的初始化。注意和super关键字的区别。

内部类是否可以被重写?一个继承Outer的类,是没有办法重写Outer里的内部类的,可以试着这么理解(不一定对):.class文件是Outer$Inner,他们本来就不存在什么关联,何来覆盖呢?当然java要提供这种机制是可以的,但事实是java不提供这种机制。

重写内部类,其实实际是为了重写里面的方法吧。所以我们可以这么做(静态内部类不能):首先Outer继承Outer,然后用一个内部类去继承Outer的内部类,并且也不需要像2说的一样必须把Outer作为参数写构造函数,为什么不用呢?因为Outer在继承Outer的时候已经做了这些工作了。这也是为什么静态内部类不能这么做的原因。

内部接口,在有没有static修饰时,都可以直接由别的类去implements Outer.interface,内部接口的目的也是为了给类提供规范的数据形式。参见Map中的Entry,这样HashMap在实现entrySet方法时,就必须遵循Entry接口,而Entry也对外隐藏了起来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 内部类