Java零基础入门笔记14-详细探讨匿名内部类

1、概述

  • 匿名内部类即没有名字的内部类
  • 由于没有名字,所以匿名内部类只能使用一次,它通常用来简化代码的编写
  • 使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
  • 匿名内部类的创建方式:
new 父类构造器(参数列表)|实现接口(){
    //匿名内部类的类体部分
}

2、匿名内部类的初始化

我们一般都是利用构造器来完成某个实例的初始化工作,但是匿名内部类是没有构造器的,那该如何初始化匿名内部类呢?对,没错,使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。
  • 1.新建一个名为AnonymousInnerClass的Java项目,在其中新建两个包,分别为com.cxs.modelcom.cxs.test。在model包下新建一个名为Destination的接口。
public interface Destination {
    String readLable();
}
  • 2.在test包下新建一个名为InnerClassInitTest测试类,并勾选主方法。
public class InnerClassInitTest {

    public Destination destination(final String dest, final float price) {
        return new Destination() {
            private int cost;
            private String label = dest;

            {// 在构造代码块儿中完成初始化工作,相当于构造器的实际效果
                cost = Math.round(price);
                if (cost > 100)
                    System.out.println("Over budget!");
            }

            @Override
            public String readLable() {
                // TODO Auto-generated method stub
                return label;
            }
        };
    }

    public static void main(String[] args) {
        InnerClassInitTest test = new InnerClassInitTest();
        test.destination("chaixingsi", 102.34f);
    }
}
  • 3.运行代码结果如下。
    这里写图片描述
  • 4.分析:
    • 如果匿名内部类希望使用一个在其外部定义的对象(调用父类构造器时,传入的参数除外),那么编译器要求其参数引用是final的(具体原因参考这里);
    • 构造器是与类名同名的函数,而匿名类因为没有名字,所以也就没有构造器,为了达到与构造器实例化对象的效果,可以使用代码块来进行实例初始化操作。
    • 匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备,并且实现接口也仅能实现一个接口。

3.匿名内部类的不同表现形式

3.1、继承式的匿名内部类

  • 1.在model包下新建一个名为Car的类,代码如下:
public abstract class Car {
    public abstract void drive();
}
  • 2.在test包下新建一个测试类CarTest,代码如下:
public class CarTest {
    public static void main(String[] args) {
        Car car = new Car() {
            @Override
            public void drive() {
                System.out.println("Driving another car!");
            }
        };
        car.drive();
    }
}
  • 3.运行代码结果如下。
    这里写图片描述
  • 4.分析:建立匿名内部类的关键点是重写父类的一个或多个方法。这里要强调的是重写父类的方法,而不是创建新的方法。因为用父类的引用不可能调用父类本身没有的方法,创建新的方法是多余的。

3.2、接口式的匿名内部类

  • 5.修改Car的代码,将Car改为接口,代码如下;
public interface Car {
    void drive();
}
  • 6.测试类CarTest代码不变,运行代码,结果同上,图略。
  • 7.分析:上面的代码很怪,好像是在实例化一个接口。事实却并非如此,接口式的匿名内部类是实现了一个接口的匿名类。并且只能实现一个接口。

3.3、参数式的匿名内部类(有疑问?

  • 1.新建一个名为IWalk的接口。
public interface IWalk {
    void walk();
}
  • 2.新建一个名为Person的类。
public abstract class Person {
    public abstract void doWalk(IWalk iWalk);
}
  • 3.新建一个名为Children的类并继承自父类Person。
public class Children extends Person {
    @Override
    public void doWalk(IWalk iWalk) {
        System.out.println("小孩儿会直立行走");
    }
}
  • 4.新建一个名为Test的测试类。
public class Test {
    public static void main(String[] args) {
        Person person=new Children();

        person.doWalk(new IWalk() {
            @Override
            public void walk() {
                System.out.println("行走的能力");
            }
        });
    }
}
  • 5.运行代码,结果如下。
    这里写图片描述

4、借助匿名内部类实现多线程

从上面的三个例子可以看出,只要一个类是抽象的或是一个接口,那么在其子列中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程,必须继承Thread类或实现Runnable接口。

4.1、Thread类的匿名内部类实现

public class Test {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
            }
        };
        thread.start();
    }
}

4.2、Runnable接口的匿名内部类实现

public class Test {
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

猜你喜欢

转载自blog.csdn.net/chaixingsi/article/details/82151684