首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

【转】java匿名内部类二

2012-09-09 
【转】java匿名内部类2匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条

【转】java匿名内部类2

匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
?只用到类的一个实例。??
?类在定义后马上用到。??
?类非常小(SUN推荐是在4行代码以下)??
?给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
?匿名内部类不能有构造方法。??
?匿名内部类不能定义任何静态成员、方法和类。??
?匿名内部类不能是public,protected,private,static。??
?只能创建匿名内部类的一个实例。
?一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。??
?因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。??

?

内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到。

?

java里没有多重继承,所以为了解决多重继承的问题,你可以在外围类里面实现很多接口,但是程序看起来并不美观,
那么内部类可以独立的继承一个接口,并且实现它,使用内部类实现了多重继承。
并且外围类不能多重继承类和抽象类,但是使用内部类可以在一个类内部多次继承类和抽象类。
内部类还可以多次实现同一个接口或者继承同一个类,但是实现方法不同,这是外部类不能实现的。
??

匿名内部类可以实现接口,也可以继承类么?

完全可以,看下边的例子,摘自Think ? in ? Java,The ? 2nd ? Edition.

先定义一个接口:
interface ? Contents ? {
? ? int ? value();
}

再定义一个类(构造函数不是默认的):
public ? class ? Wrapping ? {
? ? private ? int ? i;
? ? public ? Wrapping(int ? x) ? { ? i ? = ? x; ? }
? ? public ? int ? value() ? { ? return ? i; ? }
}

先实现接口:
public ? class ? Parcel6 ? {
? ? public ? Contents ? cont() ? {
? ? ? ? return ? new ? Contents() ? {
? ? ? ? ? ? private ? int ? i ? = ? 11;
? ? ? ? ? ? public ? int ? value() ? { ? return ? i; ? }
? ? ? ? }; ? // ? Semicolon ? required ? in ? this ? case
? ? }
? ? public ? static ? void ? main(String[] ? args) ? {
? ? ? ? Parcel6 ? p ? = ? new ? Parcel6();
? ? ? ? Contents ? c ? = ? p.cont();
? ? }
}

再继承类:
public ? class ? Parcel7 ? {
? ? public ? Wrapping ? wrap(int ? x) ? {
? ? ? ? // ? Base ? constructor ? call:
? ? ? ? return ? new ? Wrapping(x) ? { ?
? ? ? ? ? ? public ? int ? value() ? {
? ? ? ? ? ? ? ? return ? super.value() ? * ? 47;
? ? ? ? ? ? }
? ? ? ? }; ? // ? Semicolon ? required
? ? }
? ? public ? static ? void ? main(String[] ? args) ? {
? ? ? ? Parcel7 ? p ? = ? new ? Parcel7();
? ? ? ? Wrapping ? w ? = ? p.wrap(10);
? ? }
} ?


下面的例子看起来有点奇怪:
//在方法中返回一个匿名内部类
public class Parcel6 {
??????? public Contents cont() {
??????????????? return new Contents() {
???????????????????? private int i = 11;
??
???????????????????? public int value() {
??????????????????????????? return i;
???????????????????? }
????????????? }; // 在这里需要一个分号
??????? }
??
??????? public static void main(String[] args) {
??????????????? Parcel6 p = new Parcel6();
??????????????? Contents c = p.cont();
??????? }
}
cont()方法将下面两个动作合并在一起:返回值的生成,与表示这个返回值的类的定义!进一步说,这个类是匿名的,它没有名字。更糟的是,看起来是你正要创建一个Contents对象:
return new Contents()
但是,在到达语句结束的分号之前,你却说:“等一等,我想在这里插入一个类的定义”:
return new Contents() {
private int i = 11;
public int value() { return i; }
};
这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象。”通过new 表达式返回的引用被自动向上转型为对Contents的引用。匿名内部类的语法是下面例子的简略形式:
class MyContents implements Contents {
private int i = 11;
public int value() { return i; }
??? }
return new MyContents();
在这个匿名内部类中,使用了缺省的构造器来生成Contents。下面的代码展示的是,如果你的基类需要一个有参数的构造器,应该怎么办:
public class Parcel7 {
public Wrapping wrap(int x) {
// Base constructor call:
return new Wrapping(x) { // Pass constructor argument.
public int value() {
return super.value() * 47;
??????????? }
}; // Semicolon required
??? }
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Wrapping w = p.wrap(10);
??? }
}
只需简单地传递合适的参数给基类的构造器即可,这里是将x 传进new Wrapping(x)。在匿名内部类末尾的分号,并不是用来标记此内部类结束 (C++中是那样)。实际上,它标记的是表达式的结束,只不过这个表达式正巧包含了内部类罢了。因此,这与别的地方使用的分号是一致的。
??
如果在匿名类中定义成员变量,你同样能够对其执行初始化操作:
public class Parcel8 {
// Argument must be final to use inside
// anonymous inner class:
public Destination dest(final String dest) {
return new Destination() {
private String label = dest;
public String readLabel() { return label; }
};
??? }
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Destination d = p.dest("Tanzania");
??? }
}??
如 果你有一个匿名内部类,它要使用一个在它的外部定义的对象,编译器会要求其参数引用是final 型的,就像dest()中的参数。如果你忘记了,会得到 一个编译期错误信息。如果只是简单地给一个成员变量赋值,那么此例中的方法就可以了。但是,如果你想做一些类似构造器的行为,该怎么办呢?在匿名类中不可 能有已命名的构造器(因为它根本没名字!),但通过实例初始化,你就能够达到为匿名内部类“制作”一个构造器的效果。像这样做:
abstract class Base {
public Base(int i) {
System.out.println("Base constructor, i = " + i);
??? }
public abstract void f();
}
??
public class AnonymousConstructor {
public static Base getBase(int i) {
return new Base(i) {
??????????? {
System.out.println("Inside instance initializer");
??????????? }
public void f() {
System.out.println("In anonymous f()");
??????????? }
};
??? }
public static void main(String[] args) {
Base base = getBase(47);
base.f();
??? }
}??
在此例中,不要求变量i 一定是final 的。因为i 被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。下例是带实例初始化的“parcel”形式。注意dest()的参数必须是final,因为它们是在匿名类内被使用的。
public class Parcel9 {
public Destinationdest(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;
public String readLabel() { return label; }
};
??? }
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.dest("Tanzania", 101.395F);
??? }
}
在实例初始化的部分,你可以看到有一段代码,那原本是不能作为成员变量初始化的一部分而执行的(就是if 语句)。所以对于匿名类而言,实例初始化的实际效果就是构造器。当然它受到了限制:你不能重载实例初始化,所以你只能有一个构造器。

热点排行