将一个类的定义放在另外一个类的内部,这就是内部类。内部类是Java一种很是有用的特征,由于他容许你把一些逻辑相关的数据组织在一块儿,并控制它的可见性。java
咱们都知道类的建立语法(简略)以下 闭包
[public |...] class 类名 [implements|....]{ 定义属性(注意不一样的修饰符(如public ....)) 定义方法语法(构造方法或普通方法) }
而内部类的建立就是把该类放在外部类的 同属性的位置或方法(包括构造方法)内 定义例下(但愿你们能够看懂)eclipse
public class OutClass{
public OutClass(){ //构造方法内建立内部类
class C{}
} (修饰符)class A{} #局部内部类(同属性的位置) public B getB(){ #简称方法内部类(方法的内部) class B{}
return new B(); } }
####在次都忽略了修饰符,若是加上了修饰符如(static | public |private),会影响内部类的可见范围或和外围类的关系(如static),详细信息可参考修饰
符(和修饰符的用法及其相识)的讲解,和下文,由于篇幅有限不可能全面讲到。
内部类的建立方式有两种
方法一:在外围类环境下(),直接经过new 关键字和普通类同样建立
方法二:经过外围类实例建立,具体细节以下
public class Parcel2 { class Contents{ private int i = 11; public int values() { return i; } } public Contents contents() { return new Contents(); #在外部类环境内建立(方法一) } public static void main(String[] args) { Parcel2 parcel2 = new Parcel2(); #注意这是两种建立内部类的方法 Contents contents = parcel2.contents(); #在外部类环境内直接建立 Contents contents = parcel2.new Contents();#经过外部类对象和关键字new建立内部类 (方法二) } }
备注:其它不少博客对内部类作了分类,这些分类也不外乎就是定义内部时用的修饰符和内部类定义位置的不一样给内部起的名字而已。例如ide
成员内部类:同属性同样定义(修饰符通常是public或private)。测试
匿名内部类:即一个方法接受一个接口(interfaceA)类型的类。在其它类中调用这个方法,直接经过new interfaceA()这个接口并实现了该接口的全部方法,new interfaceA就是匿名内部了。this
方法内部类:就是定义在外类普通方法内的内部类。spa
局部内部类:就是定义在构造方法内的内部类。code
嵌套内部类:就是把定义内部了时用static关键字修饰的内部类。这个类我想多说点,普通内部类对象隐式的保存了一个外部类对象的引用,然而内部类经过static修饰就不同了,该内部类就和外部类彻底分离了,即不须要经过外部类对象建立内部类,内部了没有关联的外部类引用了。对象
接口内部类:外部类不是一个类,而是一个接口,接口内定义了一个内部类,该内部类能够实现本身,案例如五 接口内部了blog
4.1 new 的用法已经介绍过(经过外部类实例建立内部类实例)
4.2 this 经过OutClass.this 方式可访问建立自本身的的外部类实例(很是重要注意理解,有助于帮助咱们理解为何外部类对象的属性(包括private)彻底报漏给内部类,检验以下
public class OutClass { void print() { System.out.println("id:"+ this.hashCode()+"我是外部类的方法"); } class InnerClass{ void print() { System.out.println("我是内部类的方法"); System.out.println("___________"); OutClass.this.print();//内部类内访问建立它的外部类实例,并调用外部类的方法 } } public static void main(String[] args) { OutClass outClass = new OutClass(); System.out.println("id:" + outClass.hashCode()); InnerClass innerClass = outClass.new InnerClass(); innerClass.print(); } } 结果: id:865113938 我是内部类的方法 ___________ id:865113938我是外部类的方法
分析结果,咱们发现打印的hashCode()值相同,可知两次打印都是同一个对象的引用地址。
正常状况下,不能在接口内放置任何代码,但嵌套类能够做为接口的一部分,你放入接口中的任何类都自动转化为public和static,由于类是static,只是将
嵌套类置于接口的命名空间内,这并不违反接口规则。你能够在内部类中实现外围接口以下
public interface ClassInInterface {
void howdy(); class Test implements ClassInInterface{ @Override public void howdy() { System.out.println("我是接口内部类接口"); }; public static void main(String[] args) { new Test().howdy(); } } }
注意:在编译器内(eclipse),没法直接运行该main方法,可经过Javac编译代码,而后用Java命令运行
备注:若是你想建立某些公共代码,只想让默些特定类(实现了该接口的类)拥有。就可用该接口内部了特性。
测试:ClassInInterface
public class ClassInInterfaceImpl implements ClassInInterface{
@Override
public void howdy() {
new Test().howdy();
System.out.println("我本身的方法");
}
public static void main(String[] args) {
ClassInInterfaceImpl classInInterfaceImpl = new ClassInInterfaceImpl();
classInInterfaceImpl.howdy();
}
}
结果:
我是接口内部类接口
我本身的方法
6.1:解决了java多重继承的问题。好比有个类须要继承其它两个类,然而Java只支持单继承,故咱们能够经过编写一个内部类来继承另外一个类的咱们须要的类(固然咱们也能够经过组合的方式来完成相识功能)
6.2:封装一些功能,只让特定的类拥有该方法。例如接口内部类,只有实现了该接口的类才拥有使用特定功能。
6.3:一个类中要实现一个接口方法的不一样功能。
什么时候(什么状况下)使用内部类?请注意这个问题(引用ThinkInJava),若是只是须要一个接口的引用,为何不经过外围类实现那个接口呢?答案是:若是这能知足需求,那么就行该这样作(即不用内部类)
同时,由于内部类引用了外部类的对象的地址,致使外部类始终有一个对象在引用他,若是不刻意手动清空内部类,就会致使内存泄漏。以下
public class Clear { @Override protected void finalize() throws Throwable { // TODO Auto-generated method stub super.finalize(); System.out.println("垃圾回收器要清理我"); } public static void main(String[] args) { Clear clear = new Clear(); 代码1.//InnerClass innerClass = clear.new InnerClass(); 代码2.//innerClass = null
代码3.//new Clear().new InnerClass()
clear = null;//
System.gc();
} class InnerClass{ } }
结果:垃圾回收器要清理我
若是咱们把代码1注射打开,就不会执行finalize()方法,必须同时把代码2也要打开。若是是代码3的写法?那么垃圾怎么回收外部类呢??(就致使了内存泄漏)
备注:在thinkInJava中内部类这一节讲到了闭包的概念,他是这样定义闭包的:闭包是一个可调用的对象,它记录了一些信息(即外部类对象的一些信息,这些信息并无显现的展现给内部了对象,而是以一种特殊的形式OutClass_name.this的形式展现给了本身),这些信息来自建立它的做用域。经过这个定义,能够看出内部类是面向对象的闭包(即内部类就是java中一种闭包),它不只包含外围类对象的信息,还自动拥有一个指向外部类的引用,在此做用域内,内部类能够有权操做全部成员,包括private成员。