What is the formal reason of prefering one to method to the other(by compiler)?
Why it chooses first one for bytes etc. I know that int can represent bytes, but float also. Why is it so formally?
public class MethodCurrier {
public void setValue(int wrt){//naglowek
System.out.println("Typ int "+ wrt);
}
public void setValue(float wrt){//naglowek
System.out.println("Typ float "+ wrt);
}
public static void main(String[] args) {
MethodCurrier currier = new MethodCurrier();
currier.setValue(4);//int
currier.setValue(2.3f);//float
currier.setValue('c');//char
currier.setValue((byte)4);
}
}
The Java Language Specification defines this as follows:
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.
In your case, the int method is more specific than the float method, because an int can be implictly converted to a float, but not vice versa.
Because the Java Language Specification says so.
Related
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)
public class Demo1{
public static void main(String[] args){
show('A','A');
}
public static void show(char c, long a){
System.out.println("long-char");
}
public static void show(char c, int a){
System.out.println("char-int");
}
}
Output : char-int
But when I change the order of parameters in the first show() method (replacing
public static void show(char c, long a){} with public static void show(long a, char c) {}), I get a compilation error.
The compiler says that it is an ambiguous method call, because it is.
The general approach taken for overload resolution is to find the most specific applicable method, given the number and types of the actual parameters.
In the first case, the two methods have char as their first parameter; so it is only down to choosing whether the int or long overload is more specific, given that the actual parameter is a char: it is the int overload which is more specific, because int is narrower than long.
In the second case, one method has char as the first parameter; one method has char as the second parameter. So, given that the actual parameters are both chars, one of the parameters has to be converted (widened) to invoke either of the methods.
The language spec does not define that one is more specific than the other in such a case; they are both considered equally applicable, so the method call is ambiguous, and thus is a compile-time error.
So, today I've been testing Java's overloading techniques and I've come across ambiguity which I can't explain. Basically, when there is a vararg method with primitive and its corresponding wrapper the compiler complains and can't decide which one to choose and I don't understand why? It's easy for human to decide and not for compiler?
Here is the fragment which works for non-vararg parameters:
public static void main(String[] args)
{
int a = 14;
Integer b = new Integer(14);
stuff(a);
stuff(b);
}
static void stuff(Integer arg) { System.out.println("Integer"); }
static void stuff(int arg) { System.out.println("int"); }
And here comes the vararg which complains and cries like a baby:
public static void main(String[] args)
{
int a = 14;
Integer b = new Integer(14);
stuff(a); // Doesn't compile (ambiguity)
stuff(b); // Doesn't compile (ambiguity)
}
static void stuff(int... arg) { System.out.println("varargs int"); }
static void stuff(Integer... arg) { System.out.println("varargs Integer"); }
Consider the following two hypothetical calls to stuff():
int a = 14;
Integer b = new Integer(14);
stuff(a, b);
stuff(b, a);
How does the compiler even know which method should be called here? Because of autoboxing rules, either call could be referring to either overloaded method.
Update:
My answer is logically correct, or at least on the right track, but for a more formal answer we can refer to this SO question:
Why ambiguous error when using varargs overloading with primitive type and wrapper class?
The two varargs method are invoked in loose invocation context. As a result, the compiler will attempt to find the more specific method via JLS 15.12.2.5 Choosing the Most Specific Method. However, since neither int nor Integer are subtypes of one another, the compiler will throw an error.
The problem is:
java is doing behind the scenes bridge methods (you need to verify that is you need deep info)
AND the important part, vargargs means too YOU CAN JUST NOT PASS ANY PARAMETER, so:
static void stuff(int... arg)
and
static void stuff(Integer... arg)
can both being invoked taking no parameters... so that will create some conflict about what method should the JVM invoke
I am not able to understand the output of the following program.
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
The correct output is "double array". WHy was this constructor chosen as more specific than the other when both can accept null?
Even though both constructors can accept null, double[] inherits from java.lang.Object, and is therefore more specific.
The challenge of compiling dynamically typed languages is how to implement a runtime system that can choose the most appropriate implementation of a method or function — after the program has been compiled. Treating all variables as objects of Object type would not work efficiently.
Hence, choosing the specific one over Object.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Final arguments in interface methods - what’s the point?
While trying to experiment a few things, I've ran into a problem that it's described in this page.
interface B {
public int something(final int a);
}
abstract class C {
public int other(final int b);
}
class A extends C implements B {
public int something(int a) {
return a++;
}
public int other(int b) {
return b++
}
}
Why is such feature possible? I don't know why it's possible to to make a final parameter into a non-final one by just overriding the method. Why is the final keyword ignored in a method signature? And how do I obligate sub-classes to use in their methods final variables?
Java passes arguments to a method by value.
Therefore, no changes to a parameter can propagate back to the caller. It follows that whether or not the parameter is declared final makes absolutely no difference to the caller. As such, it is part of the implementation of the method rather than part of its interface.
What's your motivation for wanting to "obligate sub-classes to use in their methods final variables"?
final for a parameter only means that the value must not be changed within the method body. This is not a part of the method signature, and is not relevant to subclasses.
It should be invalid to have final parameters in interface or abstract methods, because it's meaningless.
Final variables are the only ones that can be used in closures. So if you want to do something like this:
void myMethod(int val) {
MyClass cls = new MyClass() {
#override
void doAction() {
callMethod(val); // use the val argument in the anonymous class - closure!
}
};
useClass(cls);
}
This won't compile, as the compiler requires val to be final. So changing the method signature to
void myMethod(final int val)
will solve the problem. Local final variable will do just as well:
void myMethod(int val) {
final int val0;
// now use val0 in the anonymous class
Java's final is not C++ const; there is no such thing as const-correctness in Java.
In Java, one achieves const-ness using immutable classes. It turns out to be quite effective because unlike C++, one cannot simply mess with memory. (You can use Field.setAccessible(true), and then use Reflection. But even that corruption-vector can be prevented by running the JVM with an appropriately configured security manager.)
The final keyword for arguments is not part of the method signature, and is only important for the body of the method, because Java passes all arguments by value (a copy of the value is always made for the method call).
I only use the final keyword (for arguments) if the compiler forces me to make it final, because the argument is used inside an anonymous class defined in the method.
In Java parameters are passed by value. Whether a parameter is final or not only affects that method, not the caller. I don't see why a class needs to obligate the subtypes.
Note that final parameters have one main purpose: you can't assign new values to them.
Also note that parameters are always passed by value, thus the caller won't see any assignments to the parameter inside the method.
If you really want to force parameters to be final (in order to prevent bugs that might be introduced when reassigning a parameter accidentially), employ a code anaylzer such as checkstyle.