This question already has answers here:
How to do method overloading for null argument?
(7 answers)
Closed 6 years ago.
I am confused with the Output of the following two programs.
When I'm only having two methods with parameters as String and Object in Program 1 it gives me output as String.
But when I add a new method with parameter as Integer in Program 2 it won't compile and gives error as
The method nullTest(Object) is ambiguous for the type testNull
Program 1 :
package onkartest;
public class TestNull {
public static void nullTest(Object b)
{
System.out.println("object");
}
public static void nullTest(String x)
{
System.out.println("String");
}
public static void main(String x[])
{
nullTest(null);
}
}
Output : String
Program 2 :
package onkartest;
public class TestNull {
public static void nullTest(Object b)
{
System.out.println("object");
}
public static void nullTest(String x)
{
System.out.println("String");
}
public static void nullTest(Integer i)
{
System.out.println("Integer ");
}
public static void main(String x[])
{
nullTest(null);
}
}
Output :
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method nullTest(Object) is ambiguous for the type testNull
at onkartest.testNull.main(testNull.java:26)
And also if I run the program with keeping only Object parameter method, it gives me output as Object.
Can you explain me the reason behind this behavior?
When determining which function to use, Java will try to find the function with the most specific input parameter. So in the first case, the String function was chosen as null can be assigned to a String. Object is a parent of String so the String function will be more specific.
In the second case, both Integer and String inherits from Object, and both of these can be assigned to null. Therefore, both of them are equally specific and Java cannot decide which one of these functions to use.
The reason is that in case of method overloading,when a parameter is passed that can be referenced by both child and parent class, the method with the parameter of type child class will always be called.
The String is a subclass of Object and therefore its method is called.
In the following example we have class Parent that can be considered as Object class and Child class that can be considered as String class.
Now what happens with your program 1, exactly the same thing happens, that is the method with parameter of child class object gets called
public class Program
{
public static void method(Parent p1)//Consider the Parent as Object
{
System.out.println("parent");
}
public static void method(Child c)//Consider the Child as String
{
System.out.println("Child");
}
public static void main(String []args)
{
method(null);
}
}
class Parent//consider Parent as Object
{
}
class Child extends Parent//consider Child as String
{
}
But suppose now you add the following class Child2 that can be considered as your Integer class. Child2 is a subclass of Parent, just like Integer is a subclass of Object
class Child2 extends Parent
{
}
and add the following method
public static void method(Child2 c)//Consider the Child2 as Integer
{
System.out.println("Child");
}
Now what happens is exactly what happend in your program 2. The reason is that the compiler is not able to decide which is the right one because of the ambiguity because both are child class of the same same parent class and most importantly none of them(Either Child2 or Child) is a parent of the other.
If we had a case where we have either of the 2 classes a subclass of the other and both inherit Parent class, then there would be no ambiguity and the method with child class will be called.
When try to pass the arguments to a method it first try a exact same type. if not then try to have immediate super type. in first program Object is super than string so it match with String. But in second program Object class have two children in same level so java compiler is not able to find which one to be mapped the null value.
Related
class Super {
public Integer i = 1;
void Sample() {
System.out.println("method of super class");
}
}
public class Sub extends Super {
public Integer i = 1000;
void Sample() {
System.out.println("method of sub class");
}
public static void main(String args[]) {
Super obj;
obj = new Super();
obj.Sample();
System.out.println(obj.i);
obj = new Sub();
obj.Sample();
System.out.println(obj.i);
}
}
Output:
method of superclass
1
method of subclass
1
When the Sample() method is called we get consequently different outputs (method of super class/subclass)
But when the variable, i is printed, outputs are identical (1)
Are problems the reference/object types or inheritance rules?
Variables in Java do not follow polymorphism and overriding is only applicable to methods, not variables. Thus, you see the overriding behaviour for the method, Sample() but not for the variable, i.
Note that in this case, the child class variable hides the parent class variable and the concept is known as variable hiding.
Note: Always follow the Java naming conventions e.g. you should rename the method, Sample() to sample().
I have 3 following cases for a method in Parent class and Child class with same names and different parameters.
Case 1 :
class Parent
{
public void hello(Object obj)
{
System.out.println("Parent");
}
}
class Child extends Parent
{
public void hello(String obj)
{
System.out.println("Child");
}
}
Case 2 :
class Parent
{
public void hello(String obj)
{
System.out.println("Parent");
}
}
class Child extends Parent
{
public void hello(Object obj)
{
System.out.println("Child");
}
}
Case 3 :
class Parent
{
public void hello(Object obj)
{
System.out.println("Parent");
}
public void hello(String obj)
{
System.out.println("String in Same Class");
}
}
class Child extends Parent
{
}
Have main() as follows :
public static void main(String[] args) {
Child c = new Child();
c.hello(null);
}
Output For Case 1 :
Child
Output for Case 2:
Parent
Output for case 3:
String in Same Class
I have Observed that in all the three cases, every time method which has String parameter gets called. Doesn't matter if it is in Child or Parent. I am really confused, because 'null' should create some ambiguity or method from child class should have been selected as its an object of Child. Why this behavior?
According to the Java Language Specification §15.12.2.5 Choosing the Most Specific Method
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run- time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
In your case, there is a method that accepts an Object and one that accepts String. Since String is a subclass of Object, the latter is more specific and hence will be chosen. For more details regarding what is considered more specific, see the language specification.
I have four classes below.
Class Note:
public class Note {
Pitch primaryPitch = new Pitch();
static Pitch secondaryPitch = new Pitch();
Note() {
System.out.println("Tune()");
}
static void pitch() {
System.out.println("Note.pitch()");
}
void volume() {
System.out.println("Note.volume()");
}
}
Class Tune:
public class Tune extends Note{
Tune() {
System.out.println("Tune()");
}
static void pitch() {
System.out.println("Tune.pitch()");
}
void volume() {
System.out.println("Tune.volume()");
}
void rhythm()
{
Note note = (Note) this;
note.volume();
}
}
Class Song:
public class Song extends Tune{
void volume() {
System.out.println("Song.volume()");
}
}
Class Test:
public class Test {
public static void main(String[] args) {
Note note2 = new Song();
((Tune)note2).rhythm();
}
When I run main, I expect the output Note.volume(). The reason I expect that output is because in the Tune class, when I call note.volume();, note has been typecast to a Note object, so I expect to use the Note class volume() method call. Instead I get Song.volume() which means I am using the Song class volume() method call.
My question is, why do I get Song.volume() and not note.volume();?
Because note is an object of type Song(). The fact that you cast it to a parent type does not change the polymorphic behavior of the volume() method. This is evident if you run the code in your IDE, and in Tune.Rhythm(), look at the variable values:
this means current instance Song, even you cast to Note, it's still Song instance
by the way, In the runtime, Java doesn't have type, so cast in the runtime is meaningless. cast is just fro Compiler to infer type by context.
Since Song also extends from Note by extends from Tune,
and Override volume method, so this.volume() will invoke the Override Song.volume method.
And if need to call the parent class Note.volume, need to use super with volume method, like: super.volume().
Please see this Java Class
class Demo
{
public static void a(String s)
{
System.out.println("string called");
}
public static void a(Object a)
{
System.out.println("Object called");
}
public static void main(String...asrgs)
{
a(null);
}
}
The output of this code is "string called" but I am not able to understand that how compiler is able to resolve between Object and String.
Moreover, examine this code fragment
class Demo
{
public static void a(String s)
{
System.out.println("string called");
}
public static void a(Integer n)
{
System.out.println("number called");
}
public static void a(Object a)
{
System.out.println("Object called");
}
public static void main(String...asrgs)
{
a(null);
}
}
Here we get a compile time error related to ambiguous call (which is quite obvious).
Any good explanations for this ?
The answer lies in §15.12.2 of the JLS:
The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expressions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.
There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.
(my emphasis)
...and §15.12.2.5, which the section above refers to, which has the full details of specificity rules, but also this handy summary:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
In your first example, a(String) is more specific than a(Object), so the compiler knows which one to use and is happy. In your second example, both a(String) and a(Integer) are more specific than a(Object), but either is applicable to null and they're in separate lineages (String is String > Object, Integer is Integer > Number > Object), creating the ambiguity the compiler complains about.
If they were in the same lineage, there'd be no ambiguity, because there'd be a single applicable most specific option. For example:
class Base {
}
class Child extends Base {
}
class GrandChild extends Child {
}
public class Example {
public static final void main(String[] args) {
a(null);
}
public static void a(Base b) {
System.out.println("Base");
}
public static void a(Child b) {
System.out.println("Child");
}
public static void a(GrandChild b) {
System.out.println("GrandChild");
}
}
That prints "GrandChild", because while both a(Child) and a(GrandChild) are more specific than a(Object), a(GrandChild) is more specific than a(Child).
I was referring to the java language specification to understand the use of super. While I understand the first use case i.e.
The form super.Identifier refers to the field named Identifier of the current object, but with the current object viewed as an instance of the superclass of the current class.
I can't seem to understand the following use case:
The form T.super.Identifier refers to the field named Identifier of the lexically enclosing instance corresponding to T, but with that instance viewed as an instance of the superclass of T.
Could someone please explain this with the help of code?
I suppose the following could be illustrative of the second case:
class S{
int x=0;
}
class T extends S{
int x=1;
class C{
int x=2;
void print(){
System.out.println(this.x);
System.out.println(T.this.x);
System.out.println(T.super.x);
}
}
public static void main(String args[]){
T t=new T();
C c=t.new C();
c.print();
}
}
output:
2
1
0
I believe it applies to this situation
public class Main {
static class Child extends Parent{
class DeeplyNested {
public void method() {
Child.super.overriden();
}
}
public void overriden() {
System.out.println("child");
}
}
static class Parent {
public void overriden() {
System.out.println("parent");
}
}
public static void main(String args[]) {
Child child = new Child();
DeeplyNested deep = child.new DeeplyNested();
deep.method();
}
}
In the JLS
The form T.super.Identifier refers to the field named Identifier of
the lexically enclosing instance corresponding to T, but with that
instance viewed as an instance of the superclass of T.
Identifier is overriden, the method.
Here, the lexically enclosing instance is of type Child and its superclass is Parent. So T.super refers to the instance of Child viewed as Parent.
The code above prints
parent