public class Demo {
public static String doit(int x,int y)
{
return"a";
}
public static String doit(int ...val)
{
return "b";
}
public static void main(String args[])
{
System.out.println(doit(4,5));
}
}
I have a doubt that why compilier is not showing any error since doit(4,5) is causing ambiguity
When I ru the code ,I get output as a ad not b why?
The Java Language Specification defines that first method ("a") should be called (rather than "b").
See http://docs.oracle.com/javase/specs/jls/se5.0/html/expressions.html#15.12.2
In order to maintain backwards compatibility with previous Java versions (before varargs was introduced), the compiler will always pick a method with the exact number of arguments, even if a varargs method also exists.
As to whether you get a warning or not, compilers are free to add additional warnings, and there may be some that do warn about this situation, I guess yours doesn't (at least not with the settings you have)
The JLS specifies the rules that are used to resolve ambiguity. The simplified version is that the compiler first attempts to match the call against the available overloads treating the varadic argument as a simple array. If that succeeds, that is it. If it fails, it tries again treating the last argument as varadic.
In this case, the first round of matching gives a definite match.
If you are interested, the JLS rules for determining what method should be used are given in Section 15.12.2. (Warning: actual JLS rules are significantly more involved than the simplified version above, and the language / notation used is very technical.)
public static String doit(int ...val)
{
return "b";
}
will be treated by compiler as
public static String doit(int[] val)
{
return "b";
}
when passing doit(2,2), 1st method will be called, as the arguments are not an array.
When passing doit(2,2,2), the arguments will converted to array and passed to 2nd method.
change the 1st method to
public static String doit(int x,int ...y)
{
return"a";
}
call doid(2,2), it will say error
doit(int, int[]) is ambigious.
Compiler always attempts to resolve the call to the most specific function call it can find which in this case is method A. This is not really a bug but if you consider it as such it's not a compiler bug, it's in the specs. You should see the crazy stuff you could get out of this once autoboxing comes into play.
The compiler tries to match the most specific alternative. It can however be argued that it should cause an ambiguity error.
From the Java Language Specification
15.12.2.5
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.
This is a compromise they made when doing the varargs spec (it's hard to know which gets called). It is recommended not to overload varargs method for this reason. Quote from their site:
Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.
Related
Here's an example:
package com.demo;
public class PassArray {
static void vaTest(int... v){
System.out.println("no of args : "+v.length+"contents: ");
for (int x:v){
System.out.println(x+" ");
}
}
static void vaTest(boolean... v){
System.out.println("no of args : "+v.length+"contents: ");
for (boolean x:v){
System.out.println(x+" ");
}
}
public static void main(String args[]){
vaTest(1,2,3);
vaTest(true,false,true);
vaTest();//Error:Ambiguous!
}
}
Can anyone tell me :
I have some Question
1.Why ambiguous error occure ?
2.i have one Varargs parameter just like
int doIt(int a,int b,int c,int... vals)
Why varargs must be declared last ?
What is varargs and ambiguity ?
Since there are two legal method invocations to the call vaTest();, the compiler can't figure out which one to use.
To help it out, you can provide an empty array of the chosen type:
vaTest(new int[] {});
More info is available in the JLS 15.12.2.5. Choosing the Most Specific Method.
Why ambiguous error occure ?
Because you haven't passed any arguments, and both the methods are valid candidate for invocation, as both can be invoked without any argument. The compiler cannot decide onto which method to bind the method call, as there is no parameter type to distinguish between the methods.
Why varargs must be declared last ?
Well, because that's how people who created Java wanted it to be declared. May be they wanted the task for the compiler easy. If the varargs are declared as last parameter, the compiler can just go on to bind all the arguments after the last non-vararg parameter to the vararg parameter. Of course, it would have been possible even if the vararg was allowed somewhere in the middle, but that would require compiler to bind the parameters towards the ends first, or at least some kind of algorithm to find out that there are enough arguments left to bind to the further non-vararg parameters. That would have made the parsing complex, as the compiler binds method argument left-to-right (that would have required some changes). May be language creator thought, adding this feature will not weigh much to justify the changes in how compiler binds the arguments. So, this restriction.
1.Why ambiguous error occure ?
This part has been already answer by other user, nicely.
Why varargs must be declared last ?
Well this is how JAVA is written. The reasonable explanation i can think of is keeping the usual read direction of the parenthesis () which has Associativity: left-to-right, If we are to declare a function like:
public void aFunc(String... args, String x, String y, String z)
If we invoke this function with exactly three arguments:aFunc("arg1", "arg2", "arg3"): Then we have a decision problem: which variable should belong to variable arity parameter args? To know the answer we will have to go from right-to-left, just reverse of the usual order of the parenthesis () associativity.
Why following program every time prints I'm string and not I'm object. or I'm int.?
public class Demo {
public Demo(String s){
System.out.println("I'm string");
}
public Demo(int i){
System.out.println("I'm int.");
}
public Demo(Object o){
System.out.println("I'm object.");
}
public static void main(String[] args) {
new Demo(null);
}
}
Also if I replace int with Integer. It gives error as The constructor Demo(String) is ambiguous. Why?
null can be converted to Object or String, but not int. Therefore the second constructor is out.
Between the conversion to Object or the conversion to String, the conversion to String is more specific, so that's what's picked.
The JLS section 15.12.2 describes method overload resolution, and I believe the same approach is used for constructor resolution. Section 15.12.2.5 describes choosing the most specific method (constructor in this case):
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.
This about the constructor invocation with Object or String arguments - any invocation handled by new Demo(String) could also be passed on to new Demo(Object) without a compile-time type error, but the reverse is not true, therefore the new Demo(String) one is more specific... and thus chosen by the overload resolution rules.
To answer your second question (since Jon Skeet has already covered the first), when you have both a String constructor and an Integer constructor the compiler doesn't know what you mean by null in new Demo(null): it could be either a String or an Integer.
Because String can't be cast to Integer (and vice versa) the compiler gives up and reports the ambiguous error. This is in contrast to the String vs Object choice when you don't have the Integer constructor.
When you have constructors or methods like the above, the compiler generally tries to find the closest match possible and uses that.
The way to think of null in these circumstances is it acts as a subtype of all types (yes, it's not strictly speaking true but it provides a good platform for thinking about what happens). So using this rule it fits string more closely than object, hence this is the constructor that is executed.
The fact the String constructor is mentioned in by the compiler in your second error:
The constructor Demo(String) is ambiguous.
is not significant. This is because the Constructor which takes a String is the first declared constructor, so the compiler uses it in its error message. Change to have the Object constructor first and you get:
The constructor Demo(Object) is ambiguous.
What it's trying to say is there's ambiguity between the constructor which takes the Integer and the Object, so you have to be more specific, as null can be applied to each. Integer IS-NOT-A String, so the two types are not compatible. You need to be more specific so the compiler can bind the constructor call.
See #Jon Skeet answer for why the compiler raises an error in some instances and not in others.
public class Main {
public void testMethod(Object o){
System.out.println("Object Method called");
}
public void testMethod(String s){
System.out.println("String Method called");
}
public static void main(String[] args) {
new Main().testMethod(null);
}
}
This program magically calls String method? On what criteria Java compiler decided to go with String method? Can somebody please point me the reason for this?
The rule is that the compiler chooses the "most specific" overload out of all matches. Since String is a subclass of Object, that makes the String version "more specific", and hence it is chosen
The operative part of the Java Language Specification is JLS 15.12.2.5:
"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."
The JLS then proceeds to give a detailed technical specification of how to determine the most specific method.
Addressed here:
Overloaded method selection based on the parameter's real type
Consider this simple Java class:
class MyClass {
public void bar(MyClass c) {
c.foo();
}
}
I want to discuss what happens on the line c.foo().
Original, Misleading Question
Note: Not all of this actually happens with each individual invokevirtual opcode. Hint: If you want to understand Java method invocation, don't read just the documentation for invokevirtual!
At the bytecode level, the meat of c.foo() will be the invokevirtual opcode, and, according to the documentation for invokevirtual, more or less the following will happen:
Look up the foo method defined in compile-time class MyClass. (This involves first resolving MyClass.)
Do some checks, including: Verify that c is not an initialization method, and verify that calling MyClass.foo wouldn't violate any protected modifiers.
Figure out which method to actually call. In particular, look up c's runtime type. If that type has foo(), call that method and return. If not, look up c's runtime type's superclass; if that type has foo, call that method and return. If not, look up c's runtime type's superclass's superclass; if that type has foo, call that method and return. Etc.. If no suitable method can be found, then error.
Step #3 alone seems adequate for figuring out which method to call and verifying that said method has the correct argument/return types. So my question is why step #1 gets performed in the first place. Possible answers seem to be:
You don't have enough information to perform step #3 until step #1 is complete. (This seems implausible at first glance, so please explain.)
The linking or access modifier checks done in #1 and #2 are essential to prevent certain bad things from happening, and those checks must be performed based on the compile-time type, rather than the run-time type hierarchy. (Please explain.)
Revised Question
The core of the javac compiler output for the line c.foo() will be an instruction like this:
invokevirtual i
where i is an index to MyClass' runtime constant pool. That constant pool entry will be of type CONSTANT_Methodref_info, and will indicate (maybe indirectly) A) the name of the method called (i.e. foo), B) the method signature, and C) the name of compile time class that the method is called on (i.e. MyClass).
The question is, why is the reference to the compile-time type (MyClass) needed? Since invokevirtual is going to do dynamic dispatch on the runtime type of c, isn't it redundant to store the reference to the compile-time class?
It is all about performance. When by figuring out the compile-time type (aka: static type) the JVM can compute the index of the invoked method in the virtual function table of the runtime type (aka: dynamic type). Using this index step 3 simply becomes an access into an array which can be accomplished in constant time. No looping is needed.
Example:
class A {
void foo() { }
void bar() { }
}
class B extends A {
void foo() { } // Overrides A.foo()
}
By default, A extends Object which defines these methods (final methods omitted as they are invoked via invokespecial):
class Object {
public int hashCode() { ... }
public boolean equals(Object o) { ... }
public String toString() { ... }
protected void finalize() { ... }
protected Object clone() { ... }
}
Now, consider this invocation:
A x = ...;
x.foo();
By figuring out that x's static type is A the JVM can also figure out the list of methods that are available at this call site: hashCode, equals, toString, finalize, clone, foo, bar. In this list, foo is the 6th entry (hashCode is 1st, equals is 2nd, etc.). This calculation of the index is performed once - when the JVM loads the classfile.
After that, whenever the JVM processes x.foo() is just needs to access the 6th entry in the list of methods that x offers, equivalent to x.getClass().getMethods[5], (which points at A.foo() if x's dynamic type is A) and invoke that method. No need to exhaustively search this array of methods.
Note that the method's index, remains the same regardless of the dynamic type of x. That is: even if x points to an instance of B, the 6th methods is still foo (although this time it will point at B.foo()).
Update
[In light of your update]: You're right. In order to perform a virtual method dispatch all the JVM needs is the name+signature of the method (or the offset within the vtable). However, the JVM does not execute things blindly. It first checks that the cassfiles loaded into it are correct in a process called verification (see also here).
Verification expresses one of the design principles of the JVM: It does not rely on the compiler to produce correct code. It checks the code itself before it allows it to be executed. In particular, the verifier checks that every invoked virtual method is actually defined by the static type of the receiver object. Obviously, the static type of the receiver is needed to perform such a check.
That's not the way I understand it after reading the documentation. I think you have steps 2 and 3 transposed, which would make the whole series of events more logical.
Presumably, #1 and #2 have already happened by the compiler. I suspect that at least part of the purpose is to make sure that the they still hold with the version of the class in the runtime environment, which may be different from the version the code was compiled against.
I haven't digested the invokevirtual documentation to verify your summary, though, so Rob Heiser could be right.
I'm guessing answer "B".
The linking or access modifier checks done in #1 and #2 are essential to prevent certain bad things from happening, and those checks must be performed based on the compile-time type, rather than the run-time type hierarchy. (Please explain.)
#1 is described by 5.4.3.3 Method Resolution, which makes some important checks. For example, #1 checks the accessibility of the method in the compile-time type and may return an IllegalAccessError if it is not:
...Otherwise, if the referenced method is not accessible (ยง5.4.4) to D, method resolution throws an IllegalAccessError. ...
If you only checked the run-time type (via #3), then the run-time type could illegally widen the accessibility of the overridden method (a.k.a. a "bad thing"). Its true that the compiler should prevent such a case, but the JVM is nevertheless protecting itself from rogue code (e.g. manually-constructed malevolent code).
To totally understand this stuff, you need to understand how method resolution works in Java. If you're looking for an in-depth explanation, I suggest looking at the book, "Inside the Java Virtual Machine". The following sections from Chapter 8, "The Linking Model", are available online and seem particularly relevant:
Chapter introduction
Resolution of CONSTANT_Methodref_info Entries
Direct References
(CONSTANT_Methodref_info entries are entries in the class file header that describe the methods called by that class.)
Thanks to Itay for inspiring me to do the Googling required to find this.
I have child classes, each carries a different type of value along with other members. There may be a LongObject, IntObject, StringObject, etc.
I will be given a value, which can be a long, int, string, etc., and I have to create a LongObject, IntObject, StringObject, etc., respectively.
Would it be faster to overload a method as shown below (a) or just use a elseif as shown below (b)?
It may not be a noticeable performance difference. It may be that the overloaded methods are implemented in a similar manner to the if/else anyway. I don't know.
I can also hear some of you saying to just test it. Sure, I ought to. I would also like to know how this type of overloading is handled under the hood, if anyone knows.
Please let me know what you think.
Thanks,
jbu
a)
BaseObject getObject(long l)
{
return new LongObject(l);
}
BaseObject getObject(int i)
{
return new IntObject(i);
}
BaseObject getObject(String s)
{
return new StringObject(s);
}
...
b)
BaseObject getObject(Object x)
{
if(value is a long)
return new LongObject((Long)x);
else if(value is an int)
return new IntObject((Int)x);
else if(value is a String)
return new StringObject((String)x);
...
}
edit: I guess I didn't completely add all the details, some of you caught it. For both choices, I still have to get an object/value and from the value determine what type it is. Therefore, I still have to do an if/else of some sort to even use the overloaded methods.
There's a massive discrepancy here: overloads are chosen at compile-time whereas your "if (value is a long)" would be an execution-time test.
If you know the type at compile-time, I strongly suggest you use that information. If you don't, then the overloading option isn't really feasible anyway.
EDIT: The comment suggests I elaborate a bit about overloads being chosen at compile-time.
The compiler picks which method signature is called based on compile-time information about the arguments. This is unlike overriding where the method implementation to use is determined by the type of the actual target of the method.
Here's an example:
public class Test
{
public static void main(String[] args)
{
Object x = "I'm a string";
foo(x);
}
public static void foo(String x)
{
System.out.println("foo(String)");
}
public static void foo(Object x)
{
System.out.println("foo(Object)");
}
}
This prints foo(Object) because the compile-time type of x is Object, not String. The fact that the execution-time type of the object that x refers to is String doesn't mean that foo(String) is called.
The overloading solution is much faster (and better) because it is resolved at compile time.
Basically the compiler figure out which method to invoke when you pass a value to it. When you call getObject("abc"), the compiler will emit calls to method:
BaseObject getObject(String s)
{
return new StringObject(s);
}
rather than trying to go through your if ... else state and evaluate the object type (which is a slow activity) at run time.
Dont worry about, unless the condition is tested millions of times a second it doesnt matter.
a) (overloading) will be faster as it gives the just in time compiler a chance to optimize. It could decide to inline the new object creation.
Any time you have to evaluate type information at run-time, it's liable to be a relatively slow operation. When you have a choice, it's nearly always preferable to write code that does so at compile time.
This is often referred to as "early binding" versus "late binding."
Cascading conditionals is bad karma in OO programming, and really ugly when testing the type of an object. The language already provides that king of test, with polymorphism.
Also, as a non-java guy, I'd use getLong(l), getInt(i), getString(s).
I find method overloading more confusing than not (imho static types shouldn't influence the program execution (other than optimization-wise (and despite appearances I'm not a Lisper :) )))
Most importantly, getObj(int), getObj(string), etc. - will fail at compile time, if you try to pass something not expected.
If you allow any object to be passed into the method, you might have an instance where the app tries to pass in something that the method can't deal with, and you wind up with an ugly runtime error.