虽然从事java开发已经有些时间了,但是对于一些东西理解的还是不够透彻。今天在温习Thread、学习ThreadLocal时偶然发现匿名内部类的一些特殊用法,查阅资料,整理总结如下,以备查看。
内部类定义:
定义在一个类内部的类,被称为内部类。
内部类分类:
- 成员内部类
- 局部内部类(方法内部类)
- 匿名内部类
- 静态嵌套类
四种内部类的共性
- 内部类仍然是一个独立的类,在编译后内部类会被编译成独立的.class文件爱你,只是在前面加上外部类的类名和$符号(Perston$Student.class)。
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由访问外部类的成员变量和方法,无论是否为private。
- 内部类的this引用。内部类中同样可以使用this.成员变量,如要使用外部类的成员变量,则使用外部类名.this.成员变量。
四种内部类的区别
一、成员内部类:它相当于外部类的一个成员变量或方法,可用修饰符为 final、abstract、public、private、protected、strictfp和static 。如下:
- /外部类
- class Outer {
- //内部类
- class Inner {
- //内部类的方法
- public void myInner() {
- System.out.println(“Inner class”);
- }
- }
- //非静态方法访问内部类
- public void getInner() {
- Inner in = new Inner();
- in.myInner();
- }
- //外部访问内部类
- pulblic static void main(String args[]) {
- Outer out = new Outer();
- Outer.Inner in = out.new Inner();
- in.myInner();
- }
- }
二、局部内部类(方法内部类):在外部类的某个方法内定义的类,与成员内部类不同,它相当于外部类的一个局部变量,修饰符只能用 final 和 abstract 。只能在定义该内部类的方法内实例化,不能在次方法外对其实例化
局部内部类对象不能使用该内部类所在方法的非 final 局部变量。因为方法的局部变量位于栈上,只存在与该方法的生命期内。当一个方法结束,其栈结构被删除,局部变量成为历史。但是该
方法结束后,在方法内创建的内部类对象可能仍然存在于堆中。例如,如果对它的引用被传递到期他代码上,并存储在一个成员变量内。正因为不能保证局部变量的存活期和方法内部类对象相
同,所以内部类对象只能使用所在方法中被定义为 final 的局部变量。静态方法的局部内部类没有 this 的引用。 示例:
- class Outer {
- public void doSomething() {
- final int a = 10;
- class Inner {
- public void myInner() {
- System.out.println(a);
- }
- }
- }
- }
三、 匿名内部类:没有名字的内部类
1、继承式的匿名内部类
- class Car {
- public void drive() {
- System.out.println(“Driving a car!”);
- }
- }
- class Temp {
- public static void main(String[] args) {
- Car car = new Car() {
- pulbic void drive() {
- System.out.println(“Driving another car!”);
- }
- };
- car.drive();
- }
- }
2、 接口式的匿名内部类
- interface Face {
- public void drive();
- }
- class Temp {
- public static void main(String[] args) {
- Face face = new Face() {
- public void drive() {
- System.out.println();
- }
- };
- face.drive();
- }
- }
3、 参数匿名内部类:顾名思义,将匿名内部类作为参数使用
四、静态嵌套类:从技术上讲,静态嵌套类不属于内部类。因为内部类与外部类共享一种特殊关系,更确切的说是对实例的共享关系。而静态嵌套类则没有上述关系。只是它的位置在一个类的内部。因此也被成为顶级嵌套类。静
态的含义是该内部类可以像期他静态成员一样,没有外部类对象十,也能够访问它。静态嵌套类不能访问外部类的成员和方法。
- class Outer {
- static class Inner{}
- }
- class Temp {
- public static void main(String[] args) {
- Outer.Inner n = new Outer.Inner();
- }
- }
关键性补充
看了 Think in Java 的内部类章节后,有点小感觉。其实Java的原理都很简单,困难就在于Java的灵活性,而要掌握牢固则必须夯实基础,你不变应万变。看着书上的例子敲了一下
首先有两个接口 IService 和 IServiceFactory
IService:
- public interface IService {
- void methord1();
- void methord2();
- }
IServiceFactory:
- public interface IServiceFactory {
- IService getService();
- }
其次还有两个类 Implement1 和 Implement2
Implement1:
- public class Implement1 implements IService {
- @Override
- public void methord1() {
- System.out.println("Implement1实现方法1");
- }
- @Override
- public void methord2() {
- System.out.println("Implement1实现方法2");
- }
- public static IServiceFactory factory = new IServiceFactory() {
- public IService getService() {
- return new Implement1();
- }
- };
- }
Implement2:
- public class Implement2 implements IService {
- @Override
- public void methord1() {
- System.out.println("Implement2实现方法1");
- }
- @Override
- public void methord2() {
- System.out.println("Implement2实现方法1");
- }
- public static IServiceFactory factory = new IServiceFactory() {
- @Override
- public IService getService() {
- return new Implement2();
- }
- };
- }
对外只暴露了一个接口,利用匿名内部类实现了IServiceFactory的功能。
工厂类:
- public class Factory {
- public static void serviceConsumer(IServiceFactory fact) {
- IService s = fact.getService();
- s.methord1();
- s.methord2();
- }
- }
入口函数:
- public class Test {
- public static void main(String[] args) {
- Factory.serviceConsumer(Implement1.factory);
- Factory.serviceConsumer(Implement2.factory);
- }
- }
匿名内部类也就是没有名字的内部类
正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
实例1:不使用匿名内部类来实现抽象方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
abstract
class
Person {
public
abstract
void
eat();
}
class
Child
extends
Person {
public
void
eat() {
System.out.println(
"eat something"
);
}
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Child();
p.eat();
}
}
|
运行结果:eat something
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用
但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?
这个时候就引入了匿名内部类
实例2:匿名内部类的基本实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
abstract
class
Person {
public
abstract
void
eat();
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Person() {
public
void
eat() {
System.out.println(
"eat something"
);
}
};
p.eat();
}
}
|
运行结果:eat something
可以看到,我们直接将抽象类Person中的方法在大括号中实现了
这样便可以省略一个类的书写
并且,匿名内部类还能用于接口上
实例3:在接口上使用匿名内部类
interface
Person {
public
void
eat();
}
public
class
Demo {
public
static
void
main(String[] args) {
Person p =
new
Person() {
public
void
eat() {
System.out.println(
"eat something"
);
}
};
p.eat();
}
}
|
运行结果:eat something
由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现
最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
实例4:Thread类的匿名内部类实现
public
class
Demo {
public
static
void
main(String[] args) {
Thread t =
new
Thread() {
public
void
run() {
for
(
int
i =
1
; i <=
5
; i++) {
System.out.print(i +
" "
);
}
}
};
t.start();
}
}
|
运行结果:1 2 3 4 5
实例5:Runnable接口的匿名内部类实现
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
Demo {
public
static
void
main(String[] args) {
Runnable r =
new
Runnable() {
public
void
run() {
for
(
int
i =
1
; i <=
5
; i++) {
System.out.print(i +
" "
);
}
}
};
Thread t =
new
Thread(r);
t.start();
}
}
|
运行结果:1 2 3 4 5
转自:http://blog.youkuaiyun.com/driverking/article/details/6553877
http://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html