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.
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?
The constructor overloading enables the accomplishment of static polymorphism. The class instances can be initialized in several ways with the use of constructor overloading. It facilitates the process of defining multiple constructors in a class with unique signatures.
If we want to have different ways of initializing an object using different number of parameters, then we must do constructor overloading as we do method overloading when we want different definitions of a method based on different parameters.
The constructor overloading can be defined as the concept of having more than one constructor with different parameters so that every constructor can perform a different task. Consider the following Java program, in which we have used different constructors in the class.
It is compile-time polymorphism because the constructor overload to be executed is chosen at compile time.
Your error is here:
Now, if "name" is indeed null,
this(name != null ? new File(name) : null);
evaluates tothis(null);
which in turn is equivalent to invocation ofFileInputStream(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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With