22

Before talking about FileInputStream, I am starting with a scenario where there are two perfectly valid, overloaded methods but where the compiler will get confused and then report a compile-time error in response to certain inputs.

Here are the methods.

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

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

Here is the complete code showing the use of the methods:

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);  
  }  
}  

Because an int literal value can be passed to a variable of type double, both methods are acceptable candidates for literal values 2 and 3, and therefore the compiler fails to decide which method to pick.

This is where I get confused when I take the above concept with me, dive further into the Java 7 API to the FileInputStream class, and study about two overloaded constructors of that class.

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

According to the Java 7 API source code, the definition of the version that takes a String object as the argument is:

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

Now, if "name" is indeed null, this(name != null ? new File(name) : null); evaluates to this(null); which in turn is equivalent to invocation of FileInputStream(null); but then both FileInputStream(String) and FileInputStream(File) become possible choices to be invoked with a null value. Does it not give rise to ambiguity? So, isn't there a compile-time error for that?

I do understand that eventually a FileNotFoundException is raised, but it is a separate issue which comes later. How is the ambiguity resolved before that?

  • possible duplicate of [How is ambiguity in selecting from overloaded methods resolved in java?](http://stackoverflow.com/questions/2608394/how-is-ambiguity-in-selecting-from-overloaded-methods-resolved-in-java) – Smutje Jun 26 '14 at 07:04
  • 4
    possible duplicate of [Which overload will get selected for null in Java?](http://stackoverflow.com/questions/1545501/which-overload-will-get-selected-for-null-in-java) – earthmover Jun 26 '14 at 07:06
  • 3
    No, it is not duplicate. I have just now visited that link. There the scenario is different since on that topic there is a hierarchical relation between the classes involved. But here, the classes String and File are unrelated. – Mohammad Ali Asgar Jun 26 '14 at 07:10
  • In the possible duplicates said that the most concrete class is to be chosen between Object and String... but in this case both (String and File) extends Object so... I think the question is not duplicated. – Carlos Verdes Jun 26 '14 at 07:11
  • 4
    The issue here is the return type of the ternary conditional operator `a ? b : c`, which is in this case `java.io.File`, so there is no ambiguity. The question is not a duplicate of either of the suggestions. – Erwin Bolwidt Jun 26 '14 at 07:30

2 Answers2

18

Your error is here:

Now, if "name" is indeed null, this(name != null ? new File(name) : null); evaluates to this(null); which in turn is equivalent to invocation of FileInputStream(null);

It actually evaluates to this((File) null) -- that is, a null value explicitly typed as File. This is because the expression name != null ? new File(name) : null has to have a type, and that type is the most specific type of the two alternatives. In this case, one alternative is typed as File and the other is typed as null, so the most specific common type is File.

That's why it's able to unambiguously resolve it to the FileInputStream(File) constructor. It's analogous to:

File file = null;
new FileInputStream(file);
yshavit
  • 42,327
  • 7
  • 87
  • 124
  • Why do you say that it evaluates to this((File)null) ? According to the concise "if" statement, the outcome is either this(new File(name)) or this(null) – Mohammad Ali Asgar Jun 26 '14 at 07:34
  • 1
    @mth's answer describes why – Erwin Bolwidt Jun 26 '14 at 07:36
  • 4
    @MohammadAliAsgar It's important to understand that the `? ... :` bit isn't A shortcut for a statement, it's an _expression_. All expressions have a type. For instance, you can't call a method that returns `void` using `?`. – yshavit Jun 26 '14 at 07:37
  • Yes, I have got it now. Excellent. Thanks to everyone, especially yshavit, mth, and Erwin Bolwidt – Mohammad Ali Asgar Jun 26 '14 at 07:48
  • When you say "most specific type", don't you mean "most specific common supertype"? That is, since null is a subtype of File, it is more specific than File, and the most specific of the two alternatives. – meriton Jun 28 '14 at 13:55
  • Except that `null` isn't actually a subtype of `File`, or of anything else for that matter. It's handled specially. `null instanceof File` is `false`. – yshavit Jun 28 '14 at 19:08
15

The type of the result of the conditional operator is File. The JLS defines:

If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

So there is no ambiguity about which constructor should be called

mth
  • 677
  • 1
  • 7
  • 19