“死党”是一种很不健康的朋友关系。确实,收获一名死党能让寂寞远离,但同时也意味着你将面临更多的选择:你不得不爱朋友之所爱,恶朋友之所恶。最终,你将变得不像你自己。而处于一个团队之中,最忌讳出现死党,当你的死党与某人翻脸时,试问你该如何处理与此人的关系呢?死党,在形成一段紧密关系的同时也与外界产生了隔阂。这是最近的一些生活感想。
Java 中有两种方式可以复用同一个方法名,这两种方式分别称为方法重写/覆盖 override 和方法重载/过载 overload,是 Java 多态性的不同体现。
定义:
方法重写/覆盖 override:override 是面向对象语言独有的特性,即父类中的一个方法在子类中获得重新定义,但是方法名、参数列表和返回值类型均维持不变。
方法重载/过载 overload:overload 是编程语言共有的特性,是指一个类(OOP)中多个方法拥有相同的方法名,但每个方法的参数列表互不相同。
override 和 overload 均表示同一个方法名对应多个方法实现体。但 override 发生在子类和父类之间,子类中 override 的方法的参数列表和返回值类型均与父类中被 override 的方法一致,并且子类不能对父类中被声明为 final 的方法进行 override,也不能在 override 时降低父类中对应方法的访问权限、抛出更多的异常(但可以减少异常);而 ovreload 发生在同一个类(当然,父类中 public 和 protected 权限的方法也是属于子类的方法)中,overload 方法和被 overload 的方法之间通过参数列表的差异(参数个数、参数类型、参数顺序等)来进行区分,需注意的是,返回值类型不是区分的条件。
Java 多态性的一些说明:
1 Java 多态性可以分为两种,静态的多态和动态的多态,也可称为编译时多态和运行时多态。所谓编译时多态就是指方法的 overload,而运行时多态就是方法的 override。
2 静态多态性。JVM 会在编译的时候根据方法的参数列表来决定调用哪一个方法,即静态多态性是在编译是确定的,引用类型决定了调用哪个版本的重载方法。
3 动态多态性。“一个接口,多个方法”,Java 实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译时调用重载方法的机制,此时对象而非引用的类型决定了调用子类还是父类中的方法。
4 对于 overload,表示新增了一个方法;对于 override,表示子类重写了父类的方法,子类不再拥有父类中的原方法,但可以通过 super 进行调用,子类中的方法数并未增加。
一个原则:当父类对象的引用指向子类对象时,形成动态多态性,子类对象的类型而不是引用的类型决定了调用谁的方法,但这个方法必须是在父类中定义过,因为一个引用只能调用该引用类型本身具有的方法和属性。也就是说,如果一个方法发生了 override,那么当通过子类对象来实例化父类的引用后,该引用在调用该方法时实际调用的将是子类中重写过的方法,尽管调用该方法的引用的类型为其父类。
5 当然,方法的调度遵循最精确匹配原则。
输出结果:
Java 中有两种方式可以复用同一个方法名,这两种方式分别称为方法重写/覆盖 override 和方法重载/过载 overload,是 Java 多态性的不同体现。
定义:
方法重写/覆盖 override:override 是面向对象语言独有的特性,即父类中的一个方法在子类中获得重新定义,但是方法名、参数列表和返回值类型均维持不变。
方法重载/过载 overload:overload 是编程语言共有的特性,是指一个类(OOP)中多个方法拥有相同的方法名,但每个方法的参数列表互不相同。
override 和 overload 均表示同一个方法名对应多个方法实现体。但 override 发生在子类和父类之间,子类中 override 的方法的参数列表和返回值类型均与父类中被 override 的方法一致,并且子类不能对父类中被声明为 final 的方法进行 override,也不能在 override 时降低父类中对应方法的访问权限、抛出更多的异常(但可以减少异常);而 ovreload 发生在同一个类(当然,父类中 public 和 protected 权限的方法也是属于子类的方法)中,overload 方法和被 overload 的方法之间通过参数列表的差异(参数个数、参数类型、参数顺序等)来进行区分,需注意的是,返回值类型不是区分的条件。
Java 多态性的一些说明:
1 Java 多态性可以分为两种,静态的多态和动态的多态,也可称为编译时多态和运行时多态。所谓编译时多态就是指方法的 overload,而运行时多态就是方法的 override。
2 静态多态性。JVM 会在编译的时候根据方法的参数列表来决定调用哪一个方法,即静态多态性是在编译是确定的,引用类型决定了调用哪个版本的重载方法。
3 动态多态性。“一个接口,多个方法”,Java 实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译时调用重载方法的机制,此时对象而非引用的类型决定了调用子类还是父类中的方法。
4 对于 overload,表示新增了一个方法;对于 override,表示子类重写了父类的方法,子类不再拥有父类中的原方法,但可以通过 super 进行调用,子类中的方法数并未增加。
一个原则:当父类对象的引用指向子类对象时,形成动态多态性,子类对象的类型而不是引用的类型决定了调用谁的方法,但这个方法必须是在父类中定义过,因为一个引用只能调用该引用类型本身具有的方法和属性。也就是说,如果一个方法发生了 override,那么当通过子类对象来实例化父类的引用后,该引用在调用该方法时实际调用的将是子类中重写过的方法,尽管调用该方法的引用的类型为其父类。
5 当然,方法的调度遵循最精确匹配原则。
以下是一段及其恶心的示例:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 父类
* 父类中存在两个 doWork 方法
* @author dancen
*
*/
class Parent
{
/**
* @override
* @param workList
*/
public void doWork(ArrayList<Integer> workList)
{
System.out.println("Parent doWork with ArrayList ...");
}
/**
* 该方法在本类中形成第1次 overload
* @param workMap
*/
public void doWork(Map<Integer, String> workMap)
{
System.out.println("Parent doWork with Map ...");
}
}
/**
* 子类
* 子类中存在4个 doWork 方法
* @author dancen
*
*/
class Child extends Parent
{
/**
* 在父类中不存在参数列表相同的方法,该方法未形成 ovreride,而形成了第2次 overload
* 参数类型放宽,但毕竟参数类型不同了
* @param workList
*/
public void doWork(List<Integer> workList)
{
System.out.println("Child doWork with List ...");
}
/**
* 在父类中不存在参数列表相同的方法,该方法同样未形成 override,但形成了第3次 overload
* 参数类型收缩,但毕竟参数类型不同了
* @param workMap
*/
public void doWork(HashMap<Integer, String> workMap)
{
System.out.println("Child doWork with HashMap ...");
}
/**
* 该方法形成 override,同时也是一次 overload
* @param workList
*/
public void doWork(ArrayList<Integer> workList)
{
System.out.println("Child doWork with ArrayList ...");
}
}
public class Test
{
public static void main(String[] args)
{
test1();
System.out.println("****************************");
test2();
}
public static void test1()
{
ArrayList<Integer> arrayList = new ArrayList<Integer>();
Parent p = new Parent();
p.doWork(arrayList); //调用父类中对应方法
p = new Child();
p.doWork(arrayList); //发生 override,将通过对象类型,而非引用类型来决定调用的方法,因此调用的是子类中 override 的方法
Child c = new Child();
c.doWork(arrayList); //调用子类中 override 的方法
}
public static void test2()
{
HashMap<Integer , String> hashMap = new HashMap<Integer , String>();
Parent p = new Parent();
p.doWork(hashMap); //调用父类中对应方法
p = new Child();
p.doWork(hashMap); //调用父类中对应方法
Child c = new Child();
c.doWork(hashMap); //调用子类中对应方法
}
}
输出结果:
Parent doWork with ArrayList ...
Child doWork with ArrayList ...
Child doWork with ArrayList ...
****************************
Parent doWork with Map ...
Parent doWork with Map ...
Child doWork with HashMap ...