java重载-方法重载中的准确性原则



java重载-方法重载中的准确性原则                            

本文章已收录于:
      
大家先猜猜看下边这段程序执行结果
public class StringUtil {
	
	/**
	 * 判断输入的字符串是否是null或""
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isEmpty(String str) {
		System.out.println("222222222::::::::::"+str);
		if (str == null || "".equals(str.trim()))
			return true;
		return false;
	}

	/**
	 * 判断输入的对象是否是null或""
	 * 
	 * @param obj
	 * @return
	 */
	public static boolean isEmpty(Object obj) {
		System.out.println("11111111::::::::::"+obj);
		return obj == null || "".equals(obj.toString());
	}
	

	
	public static void main(String[] args) {
		String s = " ss ";
		isEmpty(s);
		
		Integer i = 10;
		isEmpty(i);
		
		isEmpty(null);
		
		isEmpty((Object)null);
		isEmpty((Double)null);
	}
}


执行环境:myeclipse10 jdk1.6.0.31

执行结果:

222222222:::::::::: ss
11111111::::::::::10
222222222::::::::::null
11111111::::::::::null
11111111::::::::::null

 

 

以下几则网文很好的解释了以上的现象

Java Gossip: 重載(Overload)方法

http://www.knowsky.com/369172.html

Java支援方法「重載」(Overload),又有人譯作「超載」、「過載」,這種機制為類似功能的方法提供了統一的名稱,但是根據參數列型態的不同,而自動呼叫對應的方法。

一個例子可以從
java.lang.String 類別上提供的所有方法看到,像是它的valueOf()方法就提供了多個版本:

static String valueOf(boolean b)
static String valueOf(char c)
static String valueOf(char[] data)
static String valueOf(char[] data, int offset, int count)
static String valueOf(double d)
static String valueOf(float f)
static String valueOf(int i)
static String valueOf(long l)
static String valueOf(Object obj)


雖然呼叫的方法名稱都是valueOf(),但是根據所傳遞的引數資料型態不同,您可以呼叫不同版本的方法來進行對應的動作。

方法重載的功能使得程式設計人員能較少苦惱於方法名稱的設計,以統一的名稱來呼叫相同功能的方法,方法重載不僅可根據傳遞引數的資料型態不同來呼叫對應的方法,參數列的參數個數也可以用來設計方法重載。

方法重載時可以根據方法參數列的資料型態,也可以根據參數的個數,不過必須注意的是,方法重載不可根據傳回值的不同來區別。

方法重載當被使用於物件導向設計時的建構方法的使用時,提供物件生成時不同的建構方法,或者是使用於物件所提供的同名方法,但多樣化的參數設定方式。

J2SE 5.0 後,當您使用方法重載時,要注意到autoboxing、 unboxing 的問題,來看看下面的程式片段,您認為結果要是什麼?

  • Test.java
public class Test {
    public static void main(String[] args) {
        someMethod(1);
    }
 
    public static void someMethod(int i) {
        System.out.println("i");
    }
 
    public static void someMethod(Integer integer) {
        System.out.println("integer");
    }
} 


結果必須是顯示 "i",您不能期待裝箱(boxing)的動作會發生,如果您想要呼叫引數列為Integer版本的方法,您要明確指定:

someMethod(new Integer(1));


編譯器在處理重載與裝箱問題時,會依以下的順序:

  1. 找尋在還沒有裝箱動作前可以符合的方法
  2. 第一步失敗的話,嘗試裝箱動作後可以符合的方法
  3. 第二步也失敗,嘗試有裝箱及有 不定長度引數 的方法
  4. 第三步也失敗,編譯器找不到合適的方法,回報編譯錯誤

 

实例说明Java中的方法重载机制

http://www.knowsky.com/369172.html

本文旨在通过一道测试题目分析java语言中方法重载的机制,帮助读者更好的把握java语言的基础知识。
    首先我们先看一道测试题目,源代码如下所示,你觉得程序能否通过编译呢,假如可以通过编译输出的结果会是什么呢?
//TestOverLoad.java
public class TestOverLoad
{
 public static void main(String[] args)
 {
  Test test = new Test();
  test.PRint(null); 
 }
}

class Test
{

 public void print(String some)
 {
  System.out.println("String version print");
 }
 
 public void print(Object some)
 {
  System.out.println("Object version print");
 }

}

答案是可以通过编译,输出的结果是String version print。不知道你猜测的是否准确是否知道其中的原理,这个题目明显是考察方法重载的,重载使得java的类可以有具有多个相同方法名的方法。编译器可以通过方法的参数的类型和个数来区分他们。而返回值和异常是不能作为区别标志的。上面的程序输出了String version print是遵循了方法重载中准确性的原则,null是作为一个很非凡的参数传给了方法print(),因为你可以认为null是String,也可以认为null是Object。但是从层次上看Object处在更上层,String是从Object继续过来的,调用print(String some)将更准确。

    假如在TestOverLoad类中再添加一个方法如下所示,这样会如何呢?
public class TestOverLoad
{
 public static void main(String[] args)
 {
  Test test = new Test();
  test.print(null); 
 }
}

class Test
{

 public void print(String some)
 {
  System.out.println("String version print");
 }
 
 public void print(Object some)
 {
  System.out.println("Object version print");
 }
 
 public void print(StringBuffer some)
 {
  System.out.println("StringBuffer version print");
 }
}
答案是不能通过编译,为什么呢?由于StringBuffer和String并没有继续上的关系,因此编译器感觉StringBuffer和String作为参数的方法都很准确,它就不知道到时候会运行哪个方法了,因此会出现编译错误,这是方法重载中唯一性的原则。假如我们把参数null修改为"hello world",那么就可以通过编译并运行输出String version print了。

    曾经在java.sun.com上读文章看到一篇文章说方法的返回值也是区别方法的标志,其实这是错误的。看看下面的程序
public class A
{
 
 public  int aMethod(String s)
 {
  System.out.println(s);
  return 1;
 }
 
 public  void aMethod(String s)
 {
  System.out.println(s);
 }
}
编译的时候会提示aMethod(String s)方法已经定义过的错误。实践证实一切!

 

 

资料引用:http://www.knowsky.com/369172.html

 

 

 

关于java重载函数,参数为null时,调用的处理。(精确性原则)

http://blog.csdn.net/sxzlc/article/details/6124099

关于以下程序的输出结果

 

 

  1. public class TestNull {  
  2. public void show(String a){  
  3. System.out.println("String");  
  4. }  
  5. public void show(Object o){  
  6. System.out.println("Object");  
  7. }  
  8. public static void main(String args[]){  
  9. TestMain t = new TestMain();  
  10. t.show(null);  
  11. }  
  12. }  

结果是 String

 

解释(主要是重载函数调用时精确性的问题)

 

《java解惑》

谜题46:令人混淆的构造器案例
本谜题呈现给你了两个容易令人混淆的构造器。main方法调用了一个构造器,但是它调用的到底是哪一个呢?该程序的输出取决于这个问题的答案。那么它到底会打印出什么呢?甚至它是否是合法的呢?

public class Confusing {
  private Confusing(Object o) {
  System.out.println("Object");
  }
  private Confusing(double[] dArray) {
  System.out.println("double array");
  }
  public static void main(String[] args) {
  new Confusing(null);
  }
}

传递给构造器的参数是一个空的对象引用,因此,初看起来,该程序好像应该调用参数类型为Object的重载版本,并且将打印出Object。另一方面,数组也是引用类型,因此null也可以应用于类型为double[ ]的重载版本。你由此可能会得出结论:这个调用是模棱两可的,该程序应该不能编译。如果你试着去运行该程序,就会发现这些直观感觉都是不对的:该程序打印的是double array。这种行为可能显得有悖常理,但是有一个很好的理由可以解释它。
Java的重载解析过程是以两阶段运行的。第一阶段选取所有可获得并且可应用的方法或构造器。第二阶段在第一阶段选取的方法或构造器中选取最精确的一个。如果一个方法或构造器可以接受传递给另一个方法或构造器的任何参数,那么我们就说第一个方法比第二个方法缺乏精确性[JLS 15.12.2.5]。

在我们的程序中,两个构造器都是可获得并且可应用的。构造器Confusing(Object)可以接受任何传递给Confusing(double[ ])的参数,因此Confusing(Object)相对缺乏精确性。(每一个double数组都是一个Object,但是每一个Object并不一定是一个double数组。)因此,最精确的构造器就是Confusing(double[ ]),这也就解释了为什么程序会产生这样的输出。

如果你传递的是一个double[ ]类型的值,那么这种行为是有意义的;但是如果你传递的是null,这种行为就有违直觉了。理解本谜题的关键在于在测试哪一个方法或构造器最精确时,这些测试没有使用实际的参数:即出现在调用中的参数。这些参数只是被用来确定哪一个重载版本是可应用的。一旦编译器确定了哪些重载版本是可获得且可应用的,它就会选择最精确的一个重载版本,而此时使用的仅仅是形式参数:即出现在声明中的参数。

要想用一个null参数来调用 Confusing(Object)构造器,你需要这样写代码:new Confusing((Object)null)。这可以确保只有Confusing(Object)是可应用的。更一般地讲,要想强制要求编译器选择一个精确的重载版本,需要将实际的参数转型为形式参数所声明的类型。

以这种方式来在多个重载版本中进行选择是相当令人不快的。在你的API 中,应该确保不会让客户端走这种极端。理想状态下,你应该避免使用重载:为不同的方法取不同的名称。当然,有时候这无法实现,例如,构造器就没有名称,因而也就无法被赋予不同的名称。然而,你可以通过将构造器设置为私有的并提供公有的静态工厂,以此来缓解这个问题[EJ Item 1]。如果构造器有许多参数,你可以用Builder模式[Gamma95]来减少对重载版本的需求量。

如果你确实进行了重载,那么请确保所有的重载版本所接受的参数类型都互不兼容,这样,任何两个重载版本都不会同时是可应用的。如果做不到这一点,那么就请确保所有可应用的重载版本都具有相同的行为[EJ Item 26]。

总之,重载版本的解析可能会产生混淆。应该尽可能地避免重载,如果你必须进行重载,那么你必须遵守上述方针,以最小化这种混淆。如果一个设计糟糕的API强制你在不同的重载版本之间进行选择,那么请将实际的参数转型为你希望调用的重载版本的形式参数所具有的类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值