null behavior in function overloading with polymorphism [duplicate] - java

This question already has answers here:
Strange Java null behavior in Method Overloading [duplicate]
(4 answers)
Behavior of method overloading in java [duplicate]
(1 answer)
Closed 9 years ago.
I have the following code
public class HelloWorld {
public void printData (Test t) {
System.out.println("Reached 1");
}
public void printData(NewTest t) {
System.out.println("Reached 2");
}
public static void main(String args[]) {
HelloWorld h = new HelloWorld();
h.printData(null);
}
}
and I have two simple classes
class Test {
}
class NewTest extends Test {
}
and the output I got is Reached 2
Why the second function was selected for executing and not the 1st one? Also when I tried the same code by making another class NewTest2 extending Test and analogous printData() function it gave me compile time error. Is there any rule to select which function must be executed and when?

Why the second function was selected for executing and not the 1st one?
Because the method taking NewTest is more specific than the method taking Test, and both are accessible and applicable.
However, when you've got two subclasses of Test, neither conversion is more specific than the other, hence the call is ambiguous.
See JLS section 15.12.2.5 for the exact rules involved:
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.
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 type error.

What IDE do you use ?
In Eclipse "h.printData(null)" is marked red with this error:
The method printData(Test) is ambiguous for the type HelloWorld.
In this case you need to cast null like that:
"h.printData((Test)null)"

Related

How is this called overloading - Java [duplicate]

This question already has answers here:
Java overloading and overriding
(9 answers)
Closed 5 years ago.
I have this class BindingSample with a method that takes no parameter
public class BindingSample {
public void printMsg(){
System.out.println("Binding Sample no parameter");
}
}
And another class that extends the BindingSample and uses the same method signature but adds a parameter to it
public class application extends BindingSample {
public void printMsg(int i){
System.out.println("Changed my value " + i);
}
public static void main(String[] args) {
application app = new application();
app.printMsg(5);
}
}
The output is Changed my value 5
Why did it work even if the parameters are different? And why is it called overloading? I don't think it's overriding because to override a method, the method signature and its parameter should be the same.
Why did it work even if the parameters are different?
You application class has a printMsg method that takes a single int argument. Therefore app.printMsg(5) works.
Note that making the following change will cause your code not to pass compilation:
BindingSample app = new application();
app.printMsg(5);
since now the compiler can't find a printMsg method in the BindingSample class that takes an int argument.
And why is it called overloading? I don't think it's overriding because to override a method, the method signature and its parameter should be the same
Overriding and overloading are two different concepts.
Method overloading occurs when multiple methods share the same name but have different number of arguments or different types of arguments.
Your application class has two printMsg methods (one inherited from its super class) with a different number of arguments. Hence this is method overloading.
Overloading means just the names of the methods should be same. Everything else can be different (e.g. arguments, return types, throwable exceptions etc). As both the methods in the example have same name, it's called Overloading.
The reason why it works is, Overloading is compile time phenomena, compiler just checks for accessibility of the method to the object that's calling it. As you are instantiating application class and calling printMsg method with int argument. It works fine because of the method being present in the class (or being accessible to that object).

Templates and Generics. Why can I do the following in C++ but not in Java? How do I overcome this? [duplicate]

This question already has answers here:
How do I call a method of a generic type object?
(4 answers)
Closed 7 years ago.
Consider the following C++ program:
#include <iostream>
using namespace std;
template<typename T>
class example
{
public:
void function (T a)
{
std::cout<<a.size ();
}
};
int main() {
example<string> a; // this doesn't
string b = "a";
//example<int> a; This gives an error
a.function (b);
// your code goes here
return 0;
}
And now consider the following Java program:
import java.util.ArrayList;
class example<T> {
public void function (T a)
{
System.out.println (a.toHexString(5)); /* this does not compile even when T is Integer */
}
}
public class Main
{
public static void main (String[] args)
{
example<Integer> a = new example<Integer> ();
Integer b = 2;
a.function(b);
return;
}
}
I have majorly been a C++ developer until now and am learning Java for job purposes. So, coming from a background having worked with templates, generics confuse me.
Coming to my question:
In the above C++ code, the code compiles and runs fine if I pass string as template parameter because string does have a size () method. If I used int as a template parameter, I would've gotten an error, understandably. The point to note here is that C++ lets me compile and run the code if I pass a template parameter that has a method called size().
However, in the Java code, even when I pass Integer as the generic parameter (? is that a term?) which DOES have toHexString(int) method, the program still does not compile. It returns an error:
cannot find symbol
What's the issue here? What prevents me in Java from achieving this behaviour?
Edit: The question was marked as a possible duplicate for another question:
How do I call a method of a generic type object?
I'll copy paste my response to why I think the question's different.
The above question 'potentially' tells me how to get rid of the error. What I'm asking is what prevents me in Java from achieving the above effect? The said question gives me the medicine of the disease, not the cause.
I raised a similar question on ##java and heard of a new term - reification. I was wondering if it had anything to do with this?
Java generics are implemented via type erasure. When you have a class signature like this:
class example<T> { }
.. The class is compiled as a regular Java class. For this, T effectively takes on the type of its upper bound, in this case Object. If you have a method such as the function in your example, with a parameter of type T:
public void function (T a)
... Then this is, at the point that this function is compiled, almost the same as having the parameter be of type Object. As such, you can't call a method such as toHexString on the parameter, because that method is not defined in Object.
In C++ on the other hand, a lot of symbol resolution happens when the template is instantiated rather than when it is first compiled. This is the key difference; in Java, a generic class is compiled to bytecode, and so method calls etc must be resolved when the generic class is compiled (that is, the compiler must be able to decide what class or interface the method comes from). In C++, when the compiler encounters a template, it does not try to resolve references or produce object code unless and until the template is instantiated.
Another way to think about it: in Java, example<String> and example<Integer> are both implemented via the same class. In C++, they would be two separate classes (both which result from instantiation of the template).
This is, in fact, why Java generic classes are not "templates". In C++, a class template allows to instantiate classes (i.e. it serves as a template from which to create classes). In Java, a generic class allows for parametrized types to be implemented by a single class.
A Java generic class can be considered to be quite similar to a non-generic class with the type parameters (eg T) being replaced with the bound type (Object unless otherwise specified) - the main difference being that the compiler will perform additional type checking when you call methods on an instance of the class (which has a full type with type arguments, such that T maps to some other type), and will effectively insert casts (so that you can call a method which returns a T, via a reference where T is mapped to some type, without having to cast the return type).
The problem is that Java generics is nothing like C++ templates and was never designed to be so. Java generics was designed with one specific target - to add strong type checking at compile time. As such you will find the following an approximation to your Java version.
interface Hex {
public String toHexString(int length);
}
class Example<T extends Hex> {
public void function(T a) {
System.out.println(a.toHexString(5));
}
}
class StringWithHex implements Hex {
#Override
public String toHexString(int length) {
return "Hex";
}
}
public void test() {
Example<StringWithHex> e = new Example<>();
e.function(new StringWithHex());
}
See how it is only ensuring that types match.

Null value in method parameter [duplicate]

This question already has answers here:
Which overload will get selected for null in Java?
(3 answers)
Closed 7 years ago.
I have the following code
import java.util.List;
public class Sample {
public static void main(String[] args) {
test(null);
}
static void test(List<Object> a){
System.out.println("List of Object");
}
static void test(Object a){
System.out.println("Object");
}
}
and I got following output in console
List of Object
Why doesn't this call test(Object a)? Can you some one explain how it took "List as" null?
In a nutshell, the most specific method among the overloads is chosen.
In this case the most specific method is the one that takes List<Object> since it's a subtype of Object.
The exact algorithm Java uses to pick overloaded methods is quite complex. See Java Language Specification section 15.12.2.5 for details.
Always specific first, in cases like that. If you change List to String, it will print the same thing. Every class is child of Object, so if it have to overload, will be to the more specific class.

Checking for valid overloading [duplicate]

This question already has answers here:
Which overload will get selected for null in Java?
(3 answers)
Closed 8 years ago.
I want to know whether this is a valid overloading :
public class OverLoadingTest{
private void callFunction(Object object){
System.out.println("Printing Object");
}
private void callFunction(String string){
System.out.println("Printing String");
}
}
Further more, since someone asked me this question.
If I do like this,
OverLoadingTest test = new OverLoadingTest();
test.callFunction(null);
what will be printed ?
Of course my opinion is that it isn't valid overloading at all.
So no question of the second part.
Please tell me about this with some explanation.
The method with the least generic argument is called. So, in your case, it will be method accepting String
Note : If 2 classes are at the same level, then you will get an ambiguous call exception. For example if one method took String and another took Exception.
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.
See more details in JSL 15.12.2.5
In your case, String method will be invoked, if argument is String or null and for other argument's types Object method will be invoked.
In your example, if you define one more method with argument type that is not String (e.g Integer), can't compile the source as it is ambiguous to be invoked between the methods with String and Integer as they are same level.

Overloading method calls with parameter null [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Method Overloading for NULL parameter
In the code below the output is
String
and if I remove the method with the parameter of type String then the output is
Object
I know how overloading of methods acts when the parameter types don't match exactly but I can not understand how null can be treated as an Object and/or a String parameter.
What is the explanation for this?
class C {
static void m1(Object x) {
System.out.print("Object");
}
static void m1(String x) {
System.out.print("String");
}
public static void main(String[] args) {
m1(null);
}
}
It always uses the most specific method according to the Java specs, section 15.12.2.5.
The intro is reasonably specific about it:
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.
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 type error.
Generally speaking, and at least for code readability, it's always best to try to be as explicit as possible. You could cast your null into the type that matches the signature you want to call. But that's definitely a questionable practice. It assumes everyone knows this rule and makes the code more difficult to read.
But it's a good academic question, so I +1 your question.
When multiple overloads match a signature, Java picks the most specific method from among them.
The value of null matches both Object and String, but String is a subclass of Object, so String is picked. If you add another overload with a sibling of String in the class hierarchy, you'd get a compile error.\
// DOES NOT COMPILE
class C {
static void m1(Object x) {
System.out.print("Object");
}
static void m1(String x) {
System.out.print("String");
}
static void m1(Integer x) {
System.out.print("Integer");
}
public static void main(String[] args) {
m1(null);
}
}
Here is a link to a post that discusses your code example at some length.
If you need to force the call of a aprticular overloaded method when passing null as parameter, you have to cast it, like this:
m1((String)null);
By doing this, you make sure you're calling the correct overloaded version of the method.
You have to set the type of null to tell Java what function you want to call.
So you do: m1((Object) null); to call the implementation with the Object parameter and you do m1((String) null); to call the other one.
1. As String is also an object the JVM got confused to call which method at runtime.
2. If you want to specify which method to call at runtime, you can do this by explicit casting
eg:
m1((String)null);

Categories