大意失荊州啊-java基础之多态 & 代理
2023-04-18 14:25:55 时间
遇到个java基础的bug,搞了许久,用了一个开源库,代码比较多,就赖得一点点看完整代码,结果是越懒越花时间,使用简单的代码模拟了一下,如下:
Animal.java
abstract class Animal {
public static Animal getInstance() {
return new Dog();
}
public void hello() {
log("hello");
}
public abstract void log(String message);
}
Main.java
public class Main {
public static void main(String[] args) {
Animal.getInstance().hello();
}
}
运行结果如下:
hello
很简单,就是输出一个字符串,于是我往Animal
中增加另一个函数,如下:
Animal.java
abstract class Animal {
public static Animal getInstance() {
return new Dog();
}
public void hello() {
log("hello");
}
public void world() {
log("world");
}
public abstract void log(String message);
}
Main.java
public class Main {
public static void main(String[] args) {
Animal.getInstance().hello();
Animal.getInstance().world();
}
}
运行结果如下:
hello
Exception in thread "main" java.lang.RuntimeException
at com.company.Dog.log(Dog.java:14)
at com.company.Animal.world(Animal.java:14)
at com.company.Dog.world(Dog.java:3)
at com.company.Main.main(Main.java:6)
如上结果,出了异常,理想的结果是输出一个hello
和一个world
,但是只输出了hello
,当时我没太在意这个异常,就是很奇怪为什么我增加一个方法就不行,不都是同一个类中的方法吗?于是我打印一下类名,如下:
abstract class Animal {
public static Animal getInstance() {
return new Dog();
}
public void hello() {
System.out.println("hello: " + getClass().getName());
log("hello");
}
public void world() {
System.out.println("world: " + getClass().getName());
log("world");
}
public abstract void log(String message);
}
运行结果如下:
hello: com.company.Cat
hello
world: com.company.Dog
Exception in thread "main" java.lang.RuntimeException
at com.company.Dog.log(Dog.java:14)
at com.company.Animal.world(Animal.java:16)
at com.company.Dog.world(Dog.java:3)
at com.company.Main.main(Main.java:6)
当时我就觉得是不是见鬼了,明明一个类上的两个方法,为什么打印的对象一个是猫一个是狗?
要解决这个问题还是得看完整代码,如下:
Animal.java
abstract class Animal {
public static Animal getInstance() {
return new Dog();
}
public void hello() {
System.out.println("hello: " + getClass().getName());
log("hello");
}
public void world() {
System.out.println("world: " + getClass().getName());
log("world");
}
public abstract void log(String message);
}
Cat.java
public class Cat extends Animal {
@Override
public void log(String message) {
System.out.println(message);
}
}
Dog.java
public class Dog extends Animal {
private Cat cat = new Cat();
@Override
public void hello() {
cat.hello();
}
@Override
public void log(String message) {
throw new RuntimeException();
}
}
Main.java
public class Main {
public static void main(String[] args) {
Animal.getInstance().hello();
Animal.getInstance().world();
}
}
这里就很完整了,Animal.getInstance()
拿到的对象是Dog
,在Dog
中又创建了一个Cat
对象。画一下内存图就可以很容易理解了,如下:
首先看Animal.getInstance().hello();
的对象内存图,如下:
如上图,有些函数是继承自父类的,有些则覆盖父类的,可以看到调用的hello
函数是Cat
对象上的,所以就不难理解下面的输出结果了:
hello: com.company.Cat
hello
再来看Animal.getInstance().world();
的对象内存图,如下:
如上图,可以看到调用的world
函数是Dog
对象上的,所以就不难理解下面的输出结果了:
world: com.company.Dog
Exception in thread "main" java.lang.RuntimeException
at com.company.Dog.log(Dog.java:14)
at com.company.Animal.world(Animal.java:16)
at com.company.Dog.world(Dog.java:3)
at com.company.Main.main(Main.java:6)
所以总结起来就很简单了,Dog
实际上是一个代理类,它没有实际的功能,实际的功能都在Cat
类上,所以解决这个问题就很简单了,在Dog
中覆盖world
函数,并代理给Cat
来执行,如下:
public class Dog extends Animal {
private Cat cat = new Cat();
@Override
public void hello() {
cat.hello();
}
@Override
public void world() {
cat.world();
}
@Override
public void log(String message) {
throw new RuntimeException();
}
}
运行结果如下:
hello: com.company.Cat
hello
world: com.company.Cat
world
相关文章
- Jease 2.6发布 Java开源内容框架
- JVM调优总结:反思
- JVM调优总结:调优方法
- JVM调优总结:新一代的垃圾回收算法
- JVM调优总结:典型配置举例
- JVM调优总结:分代垃圾回收详述
- JVM调优总结:垃圾回收面临的问题
- JVM调优总结:基本垃圾回收算法
- JVM调优总结:一些概念
- 用Java GUI编写的画板程序
- Java的动态绑定机制
- jOOQ 2.0.2发布 Java的ORM框架
- Java中带复选框的树的实现和应用
- Java网络编程菜鸟进阶:TCP和套接字入门
- 甲骨文与谷歌专利权之争定于今年三月开审
- Java调用C/C++编写的第三方dll动态链接库
- 集成开发环境 NetBeans IDE 7.1正式版发布
- kangle 2.7.5紧急发布 防hash碰撞攻击
- 东方通技术引领模式为国产软件“争权”
- UML中关联,组合与聚合等关系的辨析