Java 7 API中FileInputStream的两个重载构造函数有趣的事情

22

在谈论FileInputStream之前,我将从一个场景开始,此场景中有两个完全有效的重载方法,但编译器会因某些输入而混乱,并报告编译时错误。

以下是这些方法:

double calcAverage(double marks1, int marks2) {  
   return (marks1 + marks2)/2.0;  
}  

double calcAverage(int marks1, double marks2) {  
   return (marks1 + marks2)/2.0;  
} 

这里是完整的代码,展示了方法的使用:

class MyClass {  
  double calcAverage(double marks1, int marks2) {  
            return (marks1 + marks2)/2.0;  
  }  
  double calcAverage(int marks1, double marks2) {  
           return (marks1 + marks2)/2.0;  
  }  
  public static void main(String args[]) {  
          MyClass myClass = new MyClass();  
          myClass.calcAverage(2, 3);  
  }  
}  

由于int字面值可以传递给类型为double的变量,因此两种方法都可以接受字面值23,因此编译器无法决定选择哪种方法。

当我将上述概念带入更深入地研究Java 7 API中的FileInputStream类并研究该类的两个重载构造函数时,我感到困惑。

  1. public FileInputStream(String name) throws FileNotFoundException {.....}
  2. public FileInputStream(File file) throws FileNotFoundException {.....}

根据Java 7 API源代码,使用String对象作为参数的版本的定义如下:

public FileInputStream(String name) throws FileNotFoundException {  
       this(name != null ? new File(name) : null);  
} 

现在,如果“name”确实为null,则this(name != null ? new File(name) : null);将评估为this(null);,这又等同于调用FileInputStream(null);,但是接下来FileInputStream(String)FileInputStream(File)都成为使用null值调用的可能选择。这不会引起歧义吗?因此,编译时是否会出现错误?

我确实理解最终会引发FileNotFoundException,但这是一个后续问题。那么在此之前如何解决歧义呢?


可能是Java中如何解决选择重载方法时的歧义?的重复问题。 - Smutje
4
可能是Java中null会选择哪个重载方法?的重复问题。 - earthmover
3
不,它不是重复的。我刚刚访问了那个链接。那里的场景是不同的,因为在该主题中涉及的类之间存在等级关系。但在这里,String类和File类是无关的。 - Mohammad Ali Asgar
在可能的重复项中,说最具体的类应该在Object和String之间选择...但在这种情况下,String和File都扩展了Object,所以...我认为这个问题不是重复的。 - Carlos Verdes
4
问题在于三元条件运算符 a ? b : c 的返回类型,在这种情况下为 java.io.File,因此没有歧义。问题并不是两个建议中的任何一个的重复。 - Erwin Bolwidt
2个回答

18

你的错误在这里:

现在,如果“name”确实为null,“this(name != null ? new File(name) : null);”就会评估为“this(null);”,这又等同于调用“FileInputStream(null);”

实际上,它评估为this((File) null)--也就是说,一个显式类型为File的null值。这是因为表达式name != null ? new File(name) : null必须具有类型,而该类型是两个备选项中最具体的类型。在这种情况下,一种替代方案被标记为File,另一种替代方案被标记为null,因此最具体的公共类型是File

这就是为什么它能够明确地解析为FileInputStream(File)构造函数的原因。与以下类比:

File file = null;
new FileInputStream(file);

为什么你说它会评估为((File)null)? 根据简洁的“if”语句,结果要么是this(new File(name)),要么是this(null)。 - Mohammad Ali Asgar
1
@mth的回答描述了为什么。 - Erwin Bolwidt
4
重要的是要理解 ? ... : 不是语句的快捷方式,而是一个表达式。所有表达式都有一个类型。例如,你不能使用 ? 调用返回 void 的方法。 - yshavit
是的,我现在明白了。太好了。感谢大家,特别是yshavit、mth和Erwin Bolwidt。 - Mohammad Ali Asgar
当你说“最具体类型”时,难道不是指“最具体的公共超类型”吗?也就是说,由于null是File的子类型,因此比File更具体,并且是两种选择中最具体的。 - meriton
除了 null 实际上不是 File 的子类型,或者说不是任何其他类型的子类型。它被特殊处理。null instanceof File 的结果是 false - yshavit

15

条件运算符的结果类型是FileJLS定义:

如果第二个和第三个操作数中有一个是null类型,而另一个是引用类型,则条件表达式的类型为该引用类型。

因此,应该调用哪个构造函数没有任何歧义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接