内部类的创建
把类创建在内内部, 使用起来跟正常的类没有区别, 也会有属性,构造函数什么的,如果想从外部类的非静态方法之外创建内部类的对象 ,需要具体的指明这个类的类型OuterClassName.InnerClassName
_
链接外部类
内部类出来隐藏名字和组织代码, 还有另一个能力, 就是内部类可以访问外部类的所有元素,而不需要任何访问权, 同时,内部类的对象也可以访问外部类对象的所有属性,就像外部类是内部类自己的一样
内部类为什么有这个能力?
当某个外部类创建内部类的对象时,此时内部类对象必会秘密的捕获一个指向外部类对象的引用,然后就可以通过这个引用来获得外部类对象的属性,你会发现内部类对象的创建都是与外部类对象关联时才能创建的(也就是说用外部类对象来创造内部类对象), 但是如果你创建的是嵌套类(静态内部类), 那么它就不需要对外部对象的引用
使用.this和.new
内部类对象加”.this”,就代表其外部类对象的引用,也就是那个关联的外部类对象
// innerclasses/DotThis.java
// Accessing the outer-class object
public class DotThis {
void f() { System.out.println("DotThis.f()"); }
public class Inner {
public DotThis outer() {
return DotThis.this;
// A plain "this" would be Inner's "this"
}
}
public Inner inner() { return new Inner(); }
public static void main(String[] args) {
DotThis dt = new DotThis();
DotThis.Inner dti = dt.inner();
dti.outer().f();
}
}
输出:DotThis.f()
有时候,想要告诉某些对象去创造某个内部类对象,就用”.new”
// innerclasses/DotNew.java
// Creating an inner class directly using .new syntax
public class DotNew {
public class Inner {}
public static void main(String[] args) {
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
}
}
内部类可以private或protected
正常的类(非内部类)只允许public或者packag修饰, 但是内部类可以有private或者protected,也就是说想访问它们就只能通过其外部类来访问或者继承(针对protected),甚至都访问不到其名字,完事实现了隐藏代码细节
内部类方法和作用域
创建内部类的目的:
1.你实现了某接口,可以创建并返回对其的引用
2.你要解决一个复杂的问题,想创建一个类来辅助设计方案, 但是又不想这个类被公开
局部内部类
在方法的作用域内创建一个类, 称作局部内部类
注意,在方法内创建的类并不属于它的外部类,而是属于它的方法,也就是说只有通过外部类的那个包含内部类的方法才能访问那个内部类
匿名内部类
public class Parcel7 {
public Contents contents() {
return new Contents() { // Insert class definition
private int i = 11;
@Override
public int value() { return i; }
}; // Semicolon required
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
方法contents()将返回值的生成与表示这个返回值的类的定义结合到一起, 这个类是没有名字的, 且看起来更像你正要new一个Contents()对象
这种语法是指”创建一个实现了contents接口的匿名实现类对象”,通过new 表达式返回引用自动向上转型为Contents的引用
该表达式不用匿名内部类的形式表示时是这样的
// innerclasses/Parcel7b.java
// Expanded version of Parcel7.java
public class Parcel7b {
class MyContents implements Contents {
private int i = 11;
@Override
public int value() { return i; }
}
public Contents contents() {
return new MyContents();
}
public static void main(String[] args) {
Parcel7b p = new Parcel7b();
Contents c = p.contents();
}
}
这个匿名内部类使用的是一个默认构造器,如果要使用带参的构造器的话 就在return new Contents() 的括号里加上参数,当然外部的方法也要加,匿名内部类本身是没有命名构造器的,因为没有名字
匿名内部类的传参必须是final(可省略,最好别省)修饰
public class Parcel10 {
public Destination
destination(final String dest, final float price) {
return new Destination() {
private int cost;
// Instance initialization for each object:
{
cost = Math.round(price);
if(cost > 100)
System.out.println("Over budget!");
}
private String label = dest;
@Override
public String readLabel() { return label; }
};
}
public static void main(String[] args) {
Parcel10 p = new Parcel10();
Destination d = p.destination("Tasmania", 101.395F);
}
}
这里{}那就是构造器, 只是非命名的而已
匿名内部类只能单继承, 单实现, 不能即实现接口又继承类
嵌套类
如果不需要内部类与外部类对象有联系,那么可以将内部类声明为static, 这种内部类叫嵌套类
要理解嵌套类的含义, 你就必须记住,普通的内部类是隐式的保存了一个引用,它指向了创建它的外部类的对象,而嵌套类则不是这样的
1.创建嵌套类对象并不需要外部类对象
2.不能从嵌套类访问非静态类的外部对象(原因可想而知, 没有了外部对象的引用,自然无权访问了)
3.普通类的属性跟方法的作用域仅仅是对应的内部类内部且不能包含static字段, 而嵌套类则相反
也就是说因为是静态的,就不需要依靠对象来调用方法了,直接就能用
接口内部的类
嵌套类可以作为接口的一部分, 你放到接口中的任何类都是默认public static的
// innerclasses/ClassInInterface.java
// {java ClassInInterface$Test}
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface {
@Override
public void howdy() {
System.out.println("Howdy!");
}
public static void main(String[] args) {
new Test().howdy();
}
}
}
输出为Howdy
如果你想创建一些公共代码,让它被每个类的实现类公用, 那么接口内部类是很好的选择,因为是静态的,跟随着接口走的,它的所有实现类都可以调用
为什么要使用内部类
最关键的地方是内部类能单独继承接口, 就算外部类不实现接口也并不影响内部类的工作, 内部类能变相的帮助外部类实现多继承
内部类还有以下优点
1:内部类可以有多个实例,每个实例与外部信息相互独立
2:在单个外部类中,可以让多个内部类以不同的方式实现同一个内部类,或继承同一个类
3:内部类没有领人迷惑的is-a 关系, 它是一个独立的个体
闭包与回调
闭包(closure)
闭包是一个可调用对象,它记录了一些信息,这些信息来自于创建它的作用域
通过这个定义可以看出内部类是一个闭包
内部类与控制框架
应用程序框架就是被设计用来解决特定问题的一个或者多个类, 要使用这个框架通常是集成一个类或者多个类,通过覆盖类的指令方法来解决你的问题.
控制框架
控制框架是一种特殊的应用程序框架,它被设计用来解决响应事件的需求,用来响应事件的系统被称为事件驱动系统
内部类标识符
编译后每个类都会产生一个.class文件, 其中包含了如何创建该类对象的全部信息(此信息产生一个mate-class,叫做class的对象)
内部类也必须生成一个.class文件以包含它的对象信息, 这类文件的命名有严格的规则: 外部类名&内部类名.class
如果是匿名内部类,则会生成一个数字作为内部类的标识符, 嵌套内部类则跟正常的内部类一样