Java有三大特性:封装、继承以及多态。很久以前,对于多态这一特性,我所了解的就是由方法的重载、重写所引起的。当一个对象调用一个方法时,我们会产生疑问,程序实际运行时调用的是哪一个方法?调用的是父类中的方法,还是子类本身的方法?如果一个类中有好几个重载方法,那么还涉及到选择调用哪一个重载方法版本。
现在从较深层次来理解Java的多态。
1、静态类型与实际类型
看下面的代码示例:
package xmh0511;
public class Test {
public static void main(String[] args) {
Test test = new Test();
Human man = new Man();
Human woman = new Woman();
test.sayHello(man);
test.sayHello(woman);
}
public void sayHello(Human human) {
System.out.println("I'm a Human");
}
public void sayHello(Man man) {
System.out.println("I'm a man");
}
public void sayHello(Woman woman) {
System.out.println("I'm a woman");
}
}
class Human {
}
class Man extends Human {
}
class Woman extends Human {
}
其中man的静态类型是Human,实际类型是Man;woman的静态类型是Human,实际类型是Woman。静态类型可以说是一个变量的声明类型,实际类型就是对象实例化时的具体类型。
2、重载方法版本的选择探讨
上面代码的执行结果是什么?程序是根据静态类型来匹配重载方法的版本,还是根据对象的实际类型来选择方法执行版本?
上面代码的执行结果是:
I'm a Human
I'm a Human
可见,它是根据静态类型来匹配的,即将实际参数(上面的man对象和woman对象)的静态类型(都是Human类型)与方法的参数类型进行匹配,所以该程序在调用sayHello方法时,选择执行的是sayHello(Human human)方法。
3、再想一个问题:重载方法版本的选择是在什么时候发生的?是在程序编译期(将源程序文件编译成字节码文件),还是在程序运行期(程序已经在虚拟机中处于运行状态)?
事实上,在编译器(如:Sun公司的javac编译器)编译源文件的时候,编译器能够事先确定实际参数的静态类型(如上面代码中,编译器能在编译的时候确定man和woman的静态类型就是Human),在编译成字节码文件的时候,就已经确定了要调用哪一个重载版本。重载方法版本的选择,是在编译期实现的。在字节码文件里,就已经确定了是调用哪一个重载方法。
4、重写方法版本的选择
4.1看下面的代码
public class DynanicTest {
public static void main(String[] args) {
DynanicTest dt = new DynanicTest();
Father father = new Father();
Father son = new Son();
father.sayHello();
son.sayHello();
}
}
class Father {
public void sayHello() {
System.out.println("Father sayHello()");
}
}
能看出,Son类继承了Father类,同时Son重写了父类中的sayHello()方法。
很容易就知道程序的执行结果是:
Father sayHello()
Son sayHello()
分析:
重写方法版本的选择过程大致如下:
首先得到该对象的Class对象,判断该对象的实际类型;
根据该类的继承关系,由下往上寻找与方法名和参数类型匹配的方法;
将这个方法调用的符号引用改为直接引用。
在上面的例子中:son对象调用sayHello()方法,首先从Son类中寻找是否存在sayHello()方法,如果找到了,则执行该方法,否则,到父类或者实现的接口中寻找是否存在sayHello()方法。
重写方法版本的选择是在程序运行时动态确定的,因为事先不知道一个对象的实际类型是什么,只有在程序运行时,才能确定一个对象真实的实际类型。
相关推荐
Java动态特性eval的相关实现主要涉及Java的反射机制、表达式求值以及编译器接口。在JavaScript中,`eval()`函数能够将一个字符串作为代码执行,从而实现动态编程。Java中虽然没有直接对应的内置方法,但通过一些技术...
在Java编程语言中,"高级特性"通常指的是那些更加复杂且功能强大的概念和技术,它们能够帮助开发者编写出更高效、更简洁的代码。北大青鸟的这个Java高级特性课程主要涵盖了以下几个方面: 1. **匿名内部类**:匿名...
这是因为Java反射机制不仅是Java语言的一项重要特性,也是理解Java动态特性的关键所在。通过本文,我们将深入探讨Java反射机制的核心概念、基本原理及其应用场景。 #### 二、Java反射机制简介 Java反射机制允许...
第十四章会讨论Java的反射机制和注解,它们是Java动态特性的体现,能够增强代码的灵活性和自省能力。 最后,附录通常会提供一些实用的信息,比如字符集、Unicode、Java版本历史等。 总的来说,《Java核心技术卷一...
Java反射是Java编程语言中的一个强大特性,允许在运行时检查和操作类、接口、字段和方法的信息。在"Java Reflection in Action"这本书...无论是初学者还是经验丰富的开发者,都能从中受益,提升对Java动态特性的理解。
本教程将深入探讨几个关键的Java高级特性,包括多线程、并发包下的队列、Java消息服务(JMS)、虚拟机(JVM)技术和反射与动态代理。下面将对这些主题进行详细的讲解。 1. **多线程**:Java提供了强大的多线程支持...
Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建代理对象,这些代理对象可以代表并增强原对象的功能。动态代理在很多场景下都非常有用,比如日志记录、性能监控、事务管理等。本示例将带你深入理解...
Java动态编译特性是Java平台一个非常强大的功能,它允许我们在程序运行时将源代码编译成字节码,然后直接加载到JVM中执行。这个特性极大地提升了Java的灵活性和适应性,使得我们可以实现一些在编译时无法确定的复杂...
下面我们将深入探讨Java动态加载jar文件的原理和实践方法。 首先,我们需要理解Java的类加载机制。Java中的类是由类加载器(ClassLoader)负责加载的。默认情况下,Java虚拟机(JVM)提供了三个内置的类加载器:...
它不仅管理类的生命周期,还确保了类的正确加载和初始化,是Java动态特性的基石。 #### 类加载器的工作原理 Java类加载器遵循按需加载原则,即只有当应用程序真正需要使用某个类时,类加载器才会去加载它。这一...
Java动态代理是Java编程中一个重要的特性,它允许在运行时创建代理对象,这些代理对象可以代表并增强原对象的功能。动态代理主要应用于面向切面编程(AOP)和事件监听等场景,使得代码更加模块化,易于维护。以下是...
本篇文章将深入探讨Java动态代理的概念、原理以及如何通过一个简单的"Hello, World!"示例来理解它。 动态代理,顾名思义,是在程序运行时动态地生成代理对象。与静态代理(编译时已知)相比,动态代理更加灵活,...
总之,Java反射机制是Java动态特性的基石,为开发者提供了强大的功能,同时也带来了对设计模式、框架开发和代码优化等方面的深刻影响。理解并合理运用反射机制,对于提升Java程序的灵活性和扩展性具有重要意义。
Java动态绑定和内联是Java编程中的两个关键概念,它们对于理解Java的面向对象特性,尤其是多态性和性能优化有着重要的作用。 动态绑定,又称晚期绑定或运行时绑定,是Java语言的一个核心特性。它指的是在运行时而非...
在Java高级编程方面,开发者需要掌握包括设计模式、并发编程、垃圾回收机制、JVM优化、反射、动态代理等核心概念。例如,深入理解线程池的使用,能够根据需求定制ThreadPoolExecutor,提高程序的并发性能。 **8. ...
这一版本还引入了Java编译器API,允许开发者在运行时动态编译Java源代码,这对于构建动态代码生成工具和IDE等场景非常有用。 ### 结论 综上所述,JDK 1.4的发布标志着Java语言向着更高效、更安全、更灵活的方向...
《JAVA核心技术 卷1 高级特性》是Java开发者深入理解平台的重要参考资料,它涵盖了Java编程的高级主题,包括多线程、网络编程、高级I/O、反射、泛型、枚举、注解等核心概念。这本书是基于原书第9版编写的,更新了...
2. **动态特性**:Groovy是动态类型的,这意味着变量的类型在运行时确定,不需要在声明时指定。这种灵活性允许快速开发和原型设计,但可能导致运行时错误。 3. **元编程**:Groovy支持元编程,允许在运行时修改或...