Java Overloading concept [duplicate] - java

This question already has answers here:
Java method dispatch with null argument
(4 answers)
Understanding which constructor is chosen and why
(4 answers)
Closed 9 years ago.
When I run this code it prints String. My question is why there is no compile time error?
Default value of Object and as well as String is null. Then why not compiler says Reference to method1 is ambiguous.
public class Test11
{
public static void method1(Object obj) {
System.out.println("Object");
}
public static void method1(String str) {
System.out.println("String");
}
public static void main(String[] arr ) {
method1(null);
}
}

From this answer:
There, you will notice that this is a compile-time task. The JLS says in subsection 15.12.2:
This step uses the name of the method and the types of the argument expressions to locate methods that are both accessible and applicable There may be more than one such method, in which case the most specific one is chosen.

The compiler will look at all the possible overloads of the method that could match the parameters you pass. If one of them is more specific than all the others then it will be chosen, it's only considered ambiguous if there is no single most specific overload.
In your example there are two possible overloads, method1(Object) and method1(String). Since String is more specific than Object there's no ambiguity, and the String option will be chosen. If there were a third overload such as method1(Integer) then there is no longer a single most specific choice for the call method1(null), and the compiler would generate an error.

Well in one sentence
In case of Overloaded methods compiler chooses the method with most
specific type, as String is the most specific type of Object compiler
will invoke the method which takes string as an argument

public class Test11
{
public static void method1(String str)//here str is the object of string
{
System.out.println("String");
}
public static void method1(Object obj)//here this is a common object not specified
{
System.out.println("Object");
}
public static void main(String[] arr )
{
Test11 t=new Test11();
String null1=new String();
method1(null1);
method1(t);
}
}
output is :
String
Object
//null1- is a string object if u pass this it will call method1(String str) only because u pass string object
//t-is general object if u pass this it will call method1(Object obj)only because u pass class objct so it will pass object as parameter

Related

What is the purpose of additional diamond parameters in a method signature (that look like an additional return type(s))? [duplicate]

This question already has answers here:
What does the type parameter <T> in the method definition mean? [duplicate]
(1 answer)
What are Generics in Java? [closed]
(3 answers)
Java Generics: Generic type defined as return type only
(6 answers)
Understanding generic parameters with void return types
(5 answers)
Closed 10 months ago.
I have the following class which builds:
public class Test<T> {
public T DoSomething(T value) {
return value;
}
}
I can also define it like this class like this (notice the extra in the DoSomething signature (which also builds):
public class Test<T> {
public <T> T DoSomething(T value) {
return value;
}
}
What is its purpose and when do I need to include it? I am asking about the additional <T> in the return type, not what generics are.
Maybe this will clear it up. The notation <T> declares a type variable.
So we have one variable T at the class level, and a redeclaration of that same symbol for a particular method.
class Test<T> {
<T> T doSomething(T value) {
// <T> declares a new type variable for this one method
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
T doSomethingElse(T value) {
// T is not redeclared here, thus is the type from the class declaration
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
public static void main(String... a) {
Test<String> t = new Test<>();
t.doSomething(42);
t.doSomething("foo"); // also works
t.doSomething(t); // contrived, but still works
t.doSomethingElse("hi");
t.doSomethingElse(42); // errors because the type `T` is bound to `String` by the declaration `Test<String> t`
}
}
In main, I create a Test<String> so the class-level T is String. This applies to my method doSomethingElse.
But for doSomething, T is redeclared. If I call the method with an Integer arg, then T for that case is Integer.
Really, it would have been better to call the second type variable anything else at all, on the declaration of doSomething. U, for example.
(In most cases, I actually favour giving useful names to type variables, not just single letters).
The concept is known as a generic method (docs.oracle.com).
In the code presented, we have an especially tricky case of generics since we have two generic parameters with the same name:
the <T> on the class-level: public class Test<T>, and
the <T> on the method-level: public <T> T DoSomething(T value)
The latter hides the former within the scope of the method DoSomething(...), just like a local variable would hide an instance field with the same name. In general, I would advice against this type of "hiding" since it makes the code harder to read and understand. Thus, for the rest of the discussion we will work with this (slightly modified) version of the code:
public class Test<T> {
public T doSomethingWithT(T t) {
return t;
}
public <U> U doSomethingWithU(U u) {
return u;
}
}
The scope of the class-level generic parameter T is for the whole class, while the scope of the method-level generic parameter U is only for the one method it is delared on. This will lead to the following observation:
// T is bound to type String for the instance testString:
final Test<String> testString = new Test<>();
final String tString = testString.doSomethingWithT("Hello");
System.out.println(tString); // prints "Hello"
// will not compile since 1 is not a String:
// int tInt = testString.doSomethingWithT(1);
// For this one invocation of doSomethingWithU(...), U is bound to
// type String:
final String uString = testString.doSomethingWithU("World!");
System.out.println(uString); // prints "World!"
// for this one invocation of doSomethingWithU(...), U is bound to
// type Integer:
final int uInt = testString.doSomethingWithU(1);
System.out.println(uInt); // prints "1"
Ideone demo
Notice that, although doSomethingWithU(...) is a generic method, we did not have to specify the generic parameter, the compiler inferred the type for us. While seldom used, we can also explicitly specify the generic parameter for thie method:
final Test<String> testString = new Test<>();
final Number number = testString.<Number>doSomethingWithU(1);
System.out.println(number);
Ideone demo
(In this example, the explicit generic parameter is not necessary, the code works without it aswell, but there are rare cases where this may be useful or even necessary.)
The following is not strictly necessary to understand generic methods, but more of a curiosity one might find in code and is meant to prime the reader that it is bad practice, should not be used and removed when seen.
It should also be mentioned that the JLS allows us to add generic method parameters on method invocations that do not have any generic parameter. Those parameter do not have any effect:
Object o = new Object();
// Method "hashCode()" on "Object" has not generic parameters, one
// can "add" one to the method invocation, it has no effect on the
// semantics, however
int hash = o.<String>hashCode();
Ideone demo
A remark on the code: In Java, methods should be written in camelCase instead of CamelCase (DoSomething(...) -> doSomething(...))

Matching function name but different arguments

Studying "cracking the coding interview" in Java, on page 51 I came across:
void permutation(String str){
permutation(str,"");
}
void permutation(String str, String prefix){
if(str.length()==0){
System.out.println(prefix);
} else{
for(int i=0;i<str.length();i++){
String rem=str.substring(0,i)+str.substring(i+1);
permutation(rem,prefix+str.charAt(i));
}
}
}
I get that the first permutation function takes a string and calls the second permutation function which does all the work. However, isn't the second permutation a redeclaration of the first permutation function? How will Java recognize and use the first permutation function and not overwrite it?
How will java recognize and use the first permutation function?
When you call the method, Java will see what you're trying pass into it. Based on the arguments you pass, it will decide which 'version' of the method you are trying to use.
Like others have said - this is method overloading
Unlike in Python, in Java these two declarations live side-by-side -- the second doesn't replace the first. In Java, the rule is roughly that when you call a method with multiple definitions (aka an "overloaded" method), Java will look for the one that best matches the arguments you called it with and run that method. So permutation("hi") invokes the first version, and permutation("hi", "") calls the second.
The fundamental difference here is that in Python you can imagine the interpreter reading the definitions one at a time and replacing its overall definition of permutation every time it gets a new definition. In Java, you have to think of it as reading all the definitions of permutation at once, and calling the most appropriate one for any given invocation.
(A consequence of this is that Java also checks at compile-time that every overloaded version of a method is callable: for instance, if you wrote two versions of permutation that both took just a string as their argument, the compiler would give you an error and wouldn't compile your program at all. In python you'd just get the second definition.)
To explain what the semantics are, we need to take a look at how Java methods are differentiated.
In Java, a method is identified by its signature. JLS §8.4.2 specifies that
Two methods have the same signature if they have the same name and argument types.
Important to note is that the return type of a method is not part of a method's signature. Thus if one would write:
public class Foo {
void bar(String baz) {
}
String bar(String baz) {
}
}
Both methods would have the same signature. In Java, this would lead to a compilation error since it is not allowed to have two methods with the same signature in the same class.
The behaviour changes if we take inheritance into the picture:
public class Foo {
void bar(String baz);
}
public class Zoo extends Foo {
#Override
void bar(String baz);
}
In this case, class Zoo overrides method bar(...) of class Foo. Note that the annotation is not responsible for the behaviour and merely a compile-time check to ensure that there is a method void bar(String baz) in at least one parent-class.
The code presented has two method with same name, but different signatures. This is called Overloading in Java. Thus, the method are treated as not "equal". You could rename one of those method and they would not be more or less "equal".
To make things even weirder, if methods are overloaded, the signature for the method to call is made at compile-time. That means that only the static types of parameters can be considered. Let us look at the following code and figure out what the result is:
public class Test {
public static void main(final String... args) {
final String s = "foo";
final Object o = s;
print(s);
print(o);
}
private static void print(final String s) {
System.out.println("Called with String parameter");
}
private static void print(final Object o) {
System.out.println("Called with Object parameter");
}
}
Ideon demo
Now what is the static type of s? It is the type to the left, where s was declared, thus print(final String s) is called and "Called with String parameter" is printed. What is the static type of o? Again, it is the type to the left, where o was declard, and thus print(final Object o) is called and "Called with Object parameter" is printed out. One could argue that in this trivial example, the compiler could figure out that the type of o can only be String, but basing this behaviour on the ability of the compiler to recognize types at compile-time makes it only more confusing.
In java, the whole class is loaded before a method is executed.
This means that the second method is loaded/ready before the first method is executed and the first method is loaded/ready before the second method is executed.
This allows to call a method recursively, and to call a method that will be declared later.
Also, the method is overloaded.
In java, it's possible to create multiple methods with the same name in the same class if the parameters are different. The methods will be treated as different, deoending of the argument that are passed to the method.
In other words, the name alone does not define which method is called but the signature, including the parameters(not the return value)

Why Compiler Confused in compiling Java code [duplicate]

This question already has answers here:
How to do method overloading for null argument?
(7 answers)
Closed 5 years ago.
public class CompilerConfuse {
public static void main(String[] args) {
A a =new A();
a.method(null); // error line
}
}
class A
{
public void method(Integer a)
{
System.out.println("In Integer argument method" + a);
}
public void method(Object a)
{
System.out.println("In Object argument method" + a);
}
public void method(String a)
{
System.out.println("In String argument method " + a);
}
}
In Integer and String overload method,Compiler could not able to decide which one to call.Why this happening?
If we remove either of String or Integer overload method it is not giving error when passing null.
The compiler selects the method the most specific according to the type of the passed argument(s).
In your case, String and Integer are more specific than Object but both are also as much specific, so the compiler doesn't chose between and emits a compilation error.
You can refer to 15.12.2.5. Choosing the Most Specific Method :
It is possible that no method is the most specific, because there are
two or more methods that are maximally specific. In this case:
If all the maximally specific methods have override-equivalent
signatures (§8.4.2), then:
...
Otherwise, the method invocation is ambiguous, and a compile-time
error occurs.

Method calling in java [duplicate]

This question already has answers here:
How is an overloaded method chosen when a parameter is the literal null value?
(8 answers)
Closed 7 years ago.
I have the following structure of my class:
void add(String s){
System.out.println("string");
}
void add(Object s){
System.out.println("object");
}
public static void main(String[] args) {
new MyClazz().add(null);
}
O/P : string
Why object is not called?
String is more specific than Object. Therefore void add(String s) is preferred over void add(Object s).
15.12.2. Compile-Time Step 2: Determine Method Signature
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.

Why constructor call is not ambiguous in the following example? [duplicate]

This question already has answers here:
Method overloading and choosing the most specific type
(9 answers)
Closed 8 years ago.
class Test {
public Test(Object obj) {
System.out.println("Object");
}
public Test(String s) {
System.out.println("String");
}
public static void main(String[] args) {
new Test(null); //prints String. Why not Object?
}
}
If I add another constructor with argument of type Integer ,or, for that matter any other type, calling new Test(null); results in compilation error - The constructor Test(Object) is ambiguous. Why no error is generated for the above example? On executing it, constructor with argument String is called. Why constructor with argument type Object is not called? How this ambiguity is resolved?
//prints String. Why not Object?
Because compiler choose most specific type.
If I add another constructor with argument of type Integer ,or, for
that matter any other type, calling new Test(null); results in
compilation error - The constructor Test(Object) is ambiguous.
Now String and Integer are in the same level in the object hierarchy, So, compiler can't choose one out of those two
Because it is determined by the most specific type of the parameter.
Since String is subclass of Object, and null is subtype of anything, then the second constructor is called, because String is more specific than Object.
Compiler is designed to pick up the overloaded method that very closely matches the Value sent in parameter.

Categories