内部类
1、什么是内部类?
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
2、为什么要声明内部类呢?
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,不在其他地方单独使用,那么整个内部的完整结构最好使用内部类。
而且内部类因为在外部类的里面,因此可以直接访问外部类的私有成员。
3、内部类都有哪些形式?
根据内部类声明的位置(如同变量的分类),我们可以分为:
(1)成员内部类:
- 静态成员内部类
- 非静态成员内部类
(2)局部内部类
- 有名字的局部内部类
- 匿名的内部类
静态内部类
【修饰符】 class 外部类{
【其他修饰符】 static class 内部类{
}
}
非静态成员内部类
【修饰符】 class 外部类{
【修饰符】 class 内部类{
}
}
匿名内部类
1、引入
当我们在开发过程中,需要用到一个抽象类的子类的对象或一个接口的实现类的对象,而且只创建一个对象,而且逻辑代码也不复杂。那么我们原先怎么做的呢?
(1)编写类,继承这个父类或实现这个接口
(2)重写父类或父接口的方法
(3)创建这个子类或实现类的对象
例如:
public interface Runnable{
public abstract void run();
}
//声明接口实现类
public class MyRunnable implements Runnable{
public void run(){
while(true){
System.out.println("大家注意安全");
try
Thread.sleep(1000);
}catch(Exception e){
}
}
}
}
public class Test{
public static void main(String[] args){
//如果MyRunnable类只是在这里使用一次,并且只创建它的一个对象
//分开两个.java源文件,反而不好维护
Runnable target = new MyRunnable();
Thread t = new Thread("安全提示线程",target);
t.start();
}
}
这里,因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。
可以修改为如下形式:
public class Test{
public static void main(String[] args){
//MyRunnable类只是在这里使用一次,并且只创建它的一个对象,那么这些写代码更紧凑,更好维护
Runnable target = new Runnable(){
public void run(){
while(true){
System.out.println("大家注意安全");
try
Thread.sleep(1000);
}catch(Exception e){
}
}
}
};
Thread t = new Thread("安全提示线程",target);
t.start();
}
}
2、语法格式
new 父类(【实参列表】){
重写方法...
}
//()中是否需要【实参列表】,看你想要让这个匿名内部类调用父类的哪个构造器,如果调用父类的无参构造,那么()中就不用写参数,如果调用父类的有参构造,那么()中需要传入实参
new 父接口(){
重写方法...
}
//()中没有参数,因为此时匿名内部类的父类是Object类,它只有一个无参构造
匿名内部类是没有名字的类,因此在声明类的同时就创建好了唯一的对象。
注意:
匿名内部类是一种特殊的局部内部类,只不过没有名称而已。所有局部内部类的限制都适用于匿名内部类。例如:
- 在匿名内部类中是否可以使用外部类的非静态成员变量,看所在方法是否静态
- 在匿名内部类中如果需要访问当前方法的局部变量,该局部变量需要加final
思考:这个对象能做什么呢?
答:(1)调用某个方法(2)赋值给父类/父接口的变量,通过多态引用使用这个对象(3)作为某个方法调用的实参
3、使用方式一:匿名内部类的对象直接调用方法
interface A{
void a();
}
public class Test{
public static void main(String[] args){
new A(){
@Override
public void a() {
System.out.println("aaaa");
}
}.a();
}
}
4、使用方式二:通过父类或父接口的变量多态引用匿名内部类的对象
interface A{
void a();
}
public class Test{
public static void main(String[] args){
A obj = new A(){
@Override
public void a() {
System.out.println("aaaa");
}
};
obj.a();
}
}
5、使用方式三:匿名内部类的对象作为实参
interface A{
void method();
}
public class Test{
public static void test(A a){
a.method();
}
public static void main(String[] args){
test(new A(){
@Override
public void method() {
System.out.println("aaaa");
}
});
}
}