import javax.swing.*;
public class Toast {
static Object[] objects = { new JButton(),
new String("Example"), new Object() };
public static void main(String[] args) {
System.out.println( new Count(objects) );
for (Object o : objects)
System.out.println(o);
}
}
class Count {
int b, s, o;
public Count(Object[] objects) {
for (int i=0; i<objects.length; i++)
count(objects[i]);
}
public void count(JButton x) { b++; }
public void count(String x) { s++; }
public void count(Object x) { o++; }
public String toString() {
return b + " : " + s + " : " + o + "\n";
}
}
Above is a piece of code that appears in some form or the other in past exam papers for one of my upcoming tests. The idea of the question is to gauge if you fully understand polymorphism, dynamic and static casting. Basic ideas of OO.
I would like to put out what I think is correct and if people would be able to correct me or add points that would be greatly appreciated.
From what I can see in the above code:
Items are upcast to objects in the object array as every class in java technically inherits from the object class. This is why when count is run it will say there are 3 objects not 1 Jbutton, 1 string and 1 object.
When the enhanced for loop is run the toString of that object type e.g. Example from the string and memory address of the object (not sure what the JButton will print). As this is done at runtime this is known as dynamic casting.
I cannot see any other points that would be relevant to the above bit of code.
The idea behind static cast and dynamic cast is related to the moment a type decision needs to be made. If it needs to be made by the compiler then it's static cast. If the compiler postpones the decision to runtime then it's dynamic cast.
So, your first observation is incorrect. The upcast does not explain the count. Objects do not loose they type but the compiler needs to perform a static cast to decide which method to invoke and it chooses count(Object). There is no dynamic dispatch in java which means that the method called is always decided at compile time.
You second observation is also incorrect. What is in use is polymorphism. In Java, methods are always invoked for the type of the instance and not for the type in the code. Also, there is no dynamic casting here. The compiler can verify all the types. It's just that method invocation is always virtual but that's not a cast.
Actually in this example, I don't see a single case of dynamic casting. The compiler can verify all types. You normally only see dynamic casting when down casting and there is no case of that.
Here's what I would take away:
The compiler implicitly upcasts when performing assignments. This includes assigning to array elements during initialization.
The compiler and JVM do not implicitly downcast when selecting method overloads. The static type of the objects array is Object[], so the count(Object) method will always be called.
The JVM does implicitly "downcast" (in a sense) when invoking a virtual method. The println loop will always invoke the toString method of the actual object instance rather than always invoking Object.toString.
In your Count() method, always count(object) will be called as all objects are up casted to object.
To prevent that you can call method instance of and then downcast the object and call the count
public Count(Object[] objects) {
for (int i=0; i<objects.length; i++)
{
if(objects[i] instanceof JButton)
count((JButton) objects[i]);
else if(objects[i] instanceof String)
count((String) objects[i]);
else
count(objects[i]);
}
}
Related
I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
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);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.
This question already has answers here:
Dealing with an ArrayStoreException
(4 answers)
Closed 4 years ago.
Consider the following example, ignoring the reason one would want to do this:
private static class Original {
public String getValue() {
return "Foo";
}
}
private static class Wrapper extends Original {
private Original orig;
public Wrapper(Original orig) {
this.orig = orig;
}
#Override
public String getValue() {
return orig.getValue();
}
}
public static void test(Original... o) {
if (o != null && o.length > 0) {
for (int i = 0; i < o.length; i++) {
if (o[i] instanceof Wrapper) {
o[i] = ((Wrapper) o[i]).orig; // Throws java.lang.ArrayStoreException at runtime
}
}
}
}
public static void main(String[] args){
test(new Wrapper[] { // Explicitly create an array of subclass type
new Wrapper(new Original())
});
}
This example gives no warnings or errors at compile-time. It seems like the compiler decides that an Wrapper[] contains Wrapper instances, which effectively means that those are definitely instances of Original class. This is perfectly fine.
However, at runtime, the Wrapper[] instance is directly passed into the method. I have thought that it would be smart enough to tear down this array and re-create an instance of Original[] at runtime, but it seems like this is not the case.
Is this behavior ever documented somewhere (like JLS)? An ordinary programmer like me will always assume that I can manipulate that vararg parameter of Original... as if it is an Original[].
Yes, when a Wrapper is an Original, then also a Wrapper[] is an Original[] (it surprised me too when I realized it).
Your Wrapper is a subtype of Original since it exteds the Original class.
And yes, the subtype relationship between the array types may give rise to an ArrayStoreException if the called method tries to store an Original that is not a Wrapper into the passed array. But this is not checked at compile time. It is my understanding that this is exactly why we have the ArrayStoreException type since usually other attempts to store the wrong type into an array are caught at compile time. There is a nice brief example in the documentation of ArrayStoreException. That example also demonstrates that it hasn’t really got anything to do with varargs or method calls, its for all arrays.
The Java language was designed this way from version 1 (which is long before varargs were introduced, BTW). Thanks to Andy Turner for finding the Java Language Specification (JLS) reference: It is in section 4.10.3 Subtyping among Array Types:
If S and T are both reference types, then S[] >_1 T[] iff S >_1 T.
I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
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);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.
I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
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);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.
I have a method foo
void foo (String x) { ... }
void foo (Integer x) { ... }
and I want to call it from a method which does not care about the argument:
void bar (Iterable i) {
...
for (Object x : i) foo(x); // this is the only time i is used
...
}
the code above complains that that foo(Object) is not defined and when I add
void foo (Object x) { throw new Exception; }
then bar(Iterable<String>) calls that instead of foo(String) and throws the exception.
How do I avoid having two textually identical definitions of bar(Iterable<String>) and bar(Iterable<Integer>)?
I thought I would be able to get away with something like
<T> void bar (Iterable<T> i) {
...
for (T x : i) foo(x); // this is the only time i is used
...
}
but then I get cannot find foo(T) error.
The problem you are facing is that overloaded methods are bound at compile time. In your example, the compiler tries to figure out which of the foo() methods to call. However, the strongest static type of x in your example is Object, and there is not method foo(Object), so the compiler says it can't call the appropriate method.
If you add the foo(Object) method, no matter what the actual runtime type of x is, you will always call the foo(Object) method.
This problem extends to using generics. Since T can be any type, you must have a generic method foo(T) or your code will not compile. However, if you add that method, you lose the ability to have these methods discern between the different argument types, because only foo(T) will be called.
The only way to work around this is by doing a case by case check and cast like the other answers proposed. Unless the argument types are classes you define and they can all implement a common interface. Then you can do something like:
interface ArgumentType {
void callback(FooClass c);
}
class YourClassA implements ArgumentType {
void callback( FooClass c ) {
c.foo( this );
}
}
FooClass would still have to have a foo() method for every implementing class of ArgumentType, but this way you can have your selection by type agnostic.
Think of it this way: which version of foo should be called if x is an Object?
That's the problem faced by the JVM.
If you want a truly polymorphic method, then you need to explicitly write one. Such a method could then inspect the Object through introspection to see what it's actual class type is and call the appropriate method after that.
Or, you could take a close look at what foo does. Is it only calling methods defined by Object? If so, just create a void foo(Object x) method that does the necessaries.
The trouble is you are trying to find foo(Object x) and while String and Integer are both Objects, not all Objects are either String or Integer, and java doesn't narrowcast to the right class.
I would perhaps suggest creating a method like:
void foo(Object o){
if ( o instanceof String){
String s = (String) o;
//Deal with s
} else if ( o instanceof Integer){
Integer i = (Integer) o;
//Deal with i
}
}
Also, if you are using generics anyway, you shouldn't be passing a raw iterator in bar