1、JAVA支持的多态性质主要是为两种:静态多分派和动态单分派。
- 静态多分派在JAVA中的表现形式即:重载。主要由静态方法和私有方法构成(还有实例构造方法、父类方法)。他们的引用在类加载之初就已经被确定了。一个是类级别的,一个是私有方法,private访问限定了它不能被子类访问并覆写。
- 动态单分派的表现形式为:覆写(Override)
public class Client {
public static void main(String[] args) {
Base base = new Sub();
//调用非静态方法
base.doAnything();
//调用静态方法
base.doSomething();
}
}
class Base{
//父类静态方法
public static void doSomething(){
System.out.println("我是父类静态方法");
}
//父类非静态方法
public void doAnything(){
System.out.println("我是父类非静态方法");
}
}
class Sub extends Base{
//子类同名、同参数的静态方法
public static void doSomething(){
System.out.println("我是子类静态方法");
}
//覆写父类的非静态方法
@Override
public void doAnything(){
System.out.println("我是子类非静态方法");
}
}点击打开链接
@来自http://www.cnblogs.com/DreamDrive/p/5428678.html
注意这里的Base base=new Sub();这一行代码,很明显这是典型的使用派生类,使用了父类的引用指向子类的对象,向上转型。其中,base的静态类型是Base,这个在编译期就已经确定,而实际类型Sub是在运行期才能确定的。
举个例子,Sub继承了父类Test,父类中有两个重载方法,一个参数类型是Test,一个是Sub。这时候我们调用这个重载方法,将Test test=new Sub();传入进去。前面我们提到了,静态分派的典型应用是重载,而这个例子中test的静态类型是Test,那么答案应该是多少呢?
没错,就是调用了Test类型的重载方法。因为重载是静态分派,所以它的类型在编译期就已经确定了,在确定使用哪一个重载方法的时候,是根据变量的静态类型来确定的。
动态分派:
前面提到了JAVA的动态分派是动态单分派,即在执行覆写的时候,只有一个宗量——参数。即参数是那个类型的,就覆写了哪一个方法。
还是刚才那个例子,只不过稍微改动了一下子类,添加了两个方法, 和Test中一样,一个静态方法和一个实例方法。当传入的类型是Sub时,调用了子类Sub中的test方法。
public class Test{
public static String test(Test test){
return "It's Test";
}
public String test(Sub sub){
return "It's Sub";
}
public static void main(String[]args) {
Test test=new Sub();
Test test2=new Test();
Sub sub=new Sub();
System.out.println(test.test(sub));
}
}
class Sub extends Test{
public static String test(Test test){
return "It's Sub Test";
}
public String test(Sub sub){
return "It's Sub Sub ";
}
}
输出:It's Sub Sub
静态方法:
那么如果传入Test类型的参数呢?
System.out.println(test.test(test));
我们改动一下,将main方法中最后一句的参数改成test2,看看结果: It's test
这次却没有覆写父类的方法,调用的不再是子类中的test方法,而是父类中的方法,这是为什么呢?
这是因为就像我们前面提到的,静态方法和私有方法不能被覆写,他们在编译期就已经确定了类型,这时候又回到了最开始提到的静态分派的过程中。
私有方法:
和静态方法一样,都不执行覆写
类的成员变量:
在Test类和Sub类中, 分别加入public int i=1,=2;输出test.i,结果1。
因为类的成员变量也是一般的静态分派。
基本数据类型==和包装类型的equals()方法:
long a=12;
float f=12.0f;
System.out.println(a==f);//输出true 因为f会先转换成long类型 再进行数值的比较
而如果将其中一个改成包装类型,在进行equals()方法比较,则会输出false
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
那如果改成Number类呢,我们知道
Byte,
Double,
Float,
Integer,
Long,
Short都是Number类的直接子类。
Long a=new Long(12);
Number b=12;
System.out.println(b.equals(a));//输出false
结果还是false,因为Number类的equals()方法是直接判定是否==