JAVA语言特性笔记

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
因为包装类中的equals方法会先用instanceof关键字判定,被比较的对象是不是该类型或该类型的子类,很明显Float不是Long类型的,或是它的子类,所以输出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()方法是直接判定是否==


在方法参数中定义的final字段,可以应用在匿名内部类变量的使用上,比如Runnable的run方法,要求使用的字段是final的,这时候可以在上一级方法中定义的参数为final型的,比如test(final String str){
 new Thread(new Runnable{
public void run(){
  
str="就是这样";}

});
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章