能够把一个类的定义放在另外一个类的定义内部,这就是内部类。
Java最晦涩的部分之一。
内部类看起来就像是一种代码隐藏机制,将类只与其余类的内部。但远不止如此,内部类了解外部类,并能与之通讯。shell
建立内部类的方式就如同你想的同样——把类的定义置于外围类的里边设计模式
.this
。这样产生的引用自动地具备正确类型,这一点在编译期就被知晓并收到检查,所以没有任何运行开销。.new
建立内部类。public class Outer { void func() { System.out.println("Test"); } class Inner { void func() { System.out.println("Inner"); // .this语法 Outer.this.func(); } } public static void main(String[] args) { // .new语法 new Outer().new Inner().func(); } }
内部类的优势:能够更好的隐藏细节
特色:安全
static
域和方法。能够在一个方法或任意做用域内定义内部类,成为局部内部类。这么作的理由:闭包
public class Outer { public void func() { // 方法内部的内部类 class InnerMethod { void func() { System.out.println("class in method"); } } new InnerMethod().func(); } public void f() { if(true) { // 做用域内部的内部类 class InnerScope { void func() { System.out.println("class in scope"); } } new InnerScope().func(); } } public static void main(String[] args) { new Outer().func(); new Outer().f(); } }
InnerScope
类被嵌套到if
语句中,这并非说该类到建立是有条件的,他跟其余的类同样被编译过了。final
的局部变量。static
方法,则只能访问static
修饰的成员变量。final
或abstract
修饰。inner()
方法将返回值的生成与表示这个返回值的类定义结合在一块儿,并且这个类没有名字。public class Outer { private final String outerStr = "Outer"; class Inner { public Inner(String str) { System.out.println("Inner Constructor " + str); } public void func() { System.out.println("Inner"); } } public Inner inner() { return new Inner("Dota") { { // 跟构造方法同样初始化 str3 = "LOL"; } private String str1 = Outer.this.outerStr; private String str2 = outerStr; private String str3; @Override public void func() { System.out.println(str1); System.out.println(str2); System.out.println(str3); } }; } public static void main(String[] args) { new Outer().inner().func(); } }
Inner
的引用。new Inner()
中传递参数给基类的构造器。final
的。str1
和str2
是同样的str
不要求是final
的,由于str
是传递给基类的构造器的,匿名内部类没法使用。代码更加简洁框架
若是不须要内部类对象与其外围对象之间有联系,那么能够将内部类声明为static
。ide
static
域和static
方法,但嵌套类能够有。main
方法来实现调试。回调函数的定义:在计算机程序设计中,回调函数是指经过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计容许了底层代码调用在高层定义的子程序。
非回调函数的场景:一个程序B
有一个方法b()
,要调用程序A
中的另外一个方法a()
。这个很简单,只须要在程序B
的方法b()
中new A().a()
就能够了。
回调函数:跟上述同样,可是程序A
中的方法a()
在完成任务后,还会调用一个预约义好的回调函数;B
在方法b()
中,能够按照预约义好的回调函数接口实现相关逻辑,而后把这段逻辑传递给A
,这样在B.b()
调用A.a()
的时候,就会执行这段逻辑。函数
// A定义好的回调接口 interface Callback { void callback(); } // A定义 public class A { Callback callback; public A(Callback callback) { this.callback = callback; } public void a() { System.out.println("a"); callback.callback(); } } class B { public static void main(String[] args) { A a = new A(new Callback() { @Override public void callback() { System.out.println("callback"); } }); a.a(); } } // Output: a callback
控制框架是一类特殊的应用程序框架,他用来解决响应事件的需求。主要用来响应事件的系统被称为事件驱动系统。this
public class Test { private boolean light; private boolean water; class LightEvent extends SwitchEvent { @Override public void on() { light = true; } @Override public void off() { light = false; } } class WaterEvent extends SwitchEvent { @Override public void on() { water = true; } @Override public void off() { water = false; } } } abstract class SwitchEvent { public abstract void on(); public abstract void off(); }
上述代码描述了一个开关事件的抽象类,和两个继承该抽象类的内部类。这些内部类可以自由地访问Test
类中的字段,无需任何条件。设计
记得看!!!指针
public class Test extends Outer.Inner { // 若是没有下面的构造方法会编译失败 public Test(Outer outer) { outer.super(); } } class Outer { class Inner {} }
Test
只继承了内部类Inner
,而不是外部类。outer.super();
public class Test extends Outer { class Inner {} } class Outer { class Inner {} }
上述代码中:Test
继承了Outer
并“覆盖”了Inner
,但这没有用;这两个Inner
是彻底绝不相干但两个类,各自活在各自的命名空间里。
public class Test extends Outer { class Inner extends Outer.Inner { @Override void func() { System.out.println("Test.Inner.func()"); } } public Test() { setInner(new Inner()); } public static void main(String[] args) { new Test().getInner().func(); } } class Outer { private Inner inner; class Inner { void func() { System.out.println("Outer.Inner.func()"); } } public Inner getInner() { return inner; } public void setInner(Inner inner) { this.inner = inner; } }
上述代码中:Test
继承了Outer
,Test.Inner
继承了Outer.Inner
。此时若是覆盖Inner中的方法,当构造器调用setInner(new Inner());
的时候,是把Test.Inner
向上转型为Outer
中的引用inner
。
(见10.5)
前面提到过,能够在代码块里建立内部类,典型的方式是在方法体内。
局部内部类不能有访问说明符,由于他不是外部类的一部分。
局部内部类能够访问当前代码块内的常量,以及此外围类的成员。
每一个类都会产生一个.class文件,其中包含了如何建立该类的对象的所有信息(此信息产生一个“meta-class”,叫作Class;对象),内部类也是如此。
$
内部类名.class$
编译器分配的数字.class$
分割.class对于Unix shell而言,$
是一个元字符,因此在列出.class文件的时候,有时会有问题。
内部类涉及内容相对复杂,多花点时间吧~