先来看一个案例:
这是一个抽象类
package org.westos.demo7;
abstract class Device {
private String name;
public abstract double getPrice();
public Device(){}
public Device(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这是一个测试类
package org.westos.demo7;
public class AnonymousInner {
public void test(Device d){
System.out.println("购买了一个".concat(d.getName()).concat(",花掉了"+d.getPrice()));
}
public static void main(String[] args) {
AnonymousInner ai = new AnonymousInner();
//调用有参数的构造器创建Device匿名实现类的对象
ai.test(new Device("电子示波器") {
@Override
public double getPrice() {
return 89;
}
});
//调用无参数的构造器
ai.test(new Device(){
{
System.out.println("匿名内部类的初始化块");
}
//实现抽象方法
@Override
public double getPrice() {
return 56;
}
//实现弗雷的实例方法
@Override
public String getName() {
return "键盘";
}
});
}
}
众所周知抽象类和接口不能被实例化,只能被继承或者实现。但是在上述案例中出现了这段代码:
ai.test(new Device(){
{
System.out.println("匿名内部类的初始化块");
}
//实现抽象方法
@Override
public double getPrice() {
return 56;
}
//实现弗雷的实例方法
@Override
public String getName() {
return "键盘";
}
});
我刚开始疑惑为什么这里会实例化一个抽象类而且还没有报错。这里的new Device()到底是Person的对象还是它子类的对象?
它重写了Person抽象类中的方法,所以它是子类的对象。
然后我又定义了一个Tom类并继承Person类并且按抽象类的规则重写了方法:
package org.westos.demo7;
public class Tom extends Person {
@Override
public void show() {
System.out.println("我重写了show方法");
}
}
在测试的时候又用Person类型的引用变量指向了这个对象,这样一弄我更不明白了。
package org.westos.demo7;
public class Test {
public static void main(String[] args) {
//这个Person是个抽象类
//其实右边是Person类的子类
Person person1 = new Person() {
@Override
public void show() {
System.out.println("我是Person的重写");
}
};
person1.show();
//
Person person2=new Tom();
person2.show();
System.out.println(person1 instanceof Person);//true
System.out.println(person2 instanceof Person);//true
}
}
问题的关键就看这两行代码
Person person2=new Tom();
Person person1 = new Person()
放在一起可以看出来在这里发生了多态,用父类类型的引用变量指向了子类对象,向上转型,以方便访问子类中特有的代码。
但是单独把这行代码提出来
Person person1 = new Person()
我刚开始总觉得这不就是实例化了这个抽象类吗?和之前的抽象类不能实例化矛盾啊。
其实完整的代码是这样的。
Person person1 = new Person() {
@Override
public void show() {
System.out.println("我是Person的重写");
}
};
这个抽象类被重写了,所以左边的是父类的引用变量,而右边是被重写的子类对象。这样是不是给人一种Person抽象类被实例化了的感觉。
关键语句:匿名内部类是一个对象,是继承或实现了抽象类和接口的子类对象
可能这个很好理解,但是我纠结了一个下午,其实在匿名内部类中这种很常见,但是我又用变量接受了,这样一弄就不是匿名类了,所以想了好久。