Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Java (http://www.velocityreviews.com/forums/f30-java.html)
-   -   Java multiplication of numbers and (http://www.velocityreviews.com/forums/t625920-java-multiplication-of-numbers-and.html)

leung.january@gmail.com 07-16-2008 06:10 PM

Java multiplication of numbers and
 
I have written my own Arithmetic class to do multiplication of
subclasses of Number and char, etc. But I am not sure how to make
multiply() invoke mult() of the right signature. Would I have to go
so far as to use Java reflection method such as getConstuctor() in
multiply()? Or is there a simpler way?

My current code has the following compilation error in the body of
multiply():

The method mult(Integer, Integer) in the type Arithmetic is not
applicable for the arguments (Object,
Object)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public class Arithmetic {
public static Integer mult(Integer i, Integer j) {
return i * j;
}

public static Double mult(Double i, Double j) {
return i * j;
}

public static int mult(char i, char j) {
return ((int) i * (int) j);
}


// ... mult() on other data types

public static Object multiply(Object i, Object j) {
return mult(i, j);
}

public static void main(String[] args) {
System.out.println("3 * 4 = " + Arithmetic.mult((Integer) 3,
(Integer) 4));
System.out.println(Arithmetic.multiply(new Integer(1), new
Integer(3)));
}
}

Mark Space 07-16-2008 08:09 PM

Re: Java multiplication of numbers and
 
leung.january@gmail.com wrote:
> I have written my own Arithmetic class to do multiplication of
> subclasses of Number and char, etc. But I am not sure how to make


> public class Arithmetic {
> public static Integer mult(Integer i, Integer j) {
> return i * j;
> }


You can't do this. static methods don't participate in polymorphism.
And since Integer, Double, etc. are final, you can't extend them. You
could make your own classes, although that will be a fair amount of
work. And the result would be pretty dubious, the need to box and unbox
kills performance.

And with char and other primitives there is no hope. They simply do not
behave polymorphically, ever, in Java.

Here's the closest I could come up with. You could use java.lang.Number
instead of MyNumber, but the code will be longer because you have to
implement several abstract methods.



interface MyNumber<T extends MyNumber> {
T mult( T m);
}

class MyInteger implements MyNumber<MyInteger>{
private int i;
MyInteger(int i) {
this.i = i;
}
@Override
public MyInteger mult( MyInteger m ) {
return new MyInteger(i * m.i);
}
@Override
public String toString() {
return Integer.toString(i);
}
}
class MyDouble implements MyNumber<MyDouble>
{
private double d;
MyDouble( double d ) {
this.d = d;
}
@Override
public MyDouble mult( MyDouble m ) {
return new MyDouble(d * m.d );
}
@Override
public String toString() {
return Double.toString( d );
}
}

class Arithmetic {

public static MyNumber multiply(MyNumber i, MyNumber j) {
return i.mult(j);
}

public static void main(String[] args) {
MyNumber k = new MyInteger( 3 );
MyNumber n = new MyInteger( 4 );
MyNumber f = new MyDouble( 2.4456 );
MyNumber g = new MyDouble( 3.14159 );

System.out.println( multiply( k, n ) );
System.out.println( multiply( f, g ) );
}
}

Joshua Cranmer 07-16-2008 09:13 PM

Re: Java multiplication of numbers and
 
leung.january@gmail.com wrote:
> public static Object multiply(Object i, Object j) {
> return mult(i, j);
> }


This is not doing what you think it does (indeed, it causes an error
based on the rest of your code). Java has no runtime overloaded method
dispatch [1]. The compiler is determining which method to call (modulo
virtual effects) based on the /static/ types of the method. So, in
short, the compiler is looking for a relevant method mult method that
takes as its parameters two Objects or supertypes thereof (and Objects
have no supertype).

Longer answer, citing from the JLS:
Method invocations are covered in 15.12. The process of determining the
method at compile-time is in three steps.

In the first step, it selects the class to look for the method in. To
save you the effort of decoding the spec, it selects Arithmetic as the
class.

In the second step, it first selects potentially applicable methods
(their terminology). Once again, simplifying, it finds the mult methods.
It then tries to find the one that should be invoked. The relevant stuff
happens in 15.12.2.2 (.3 and .4 are two more phases, but if one ignores
auto{un}boxing and variable-arity methods, those don't get applied).

Quoting:
"Let m be a potentially applicable method (15.12.2.1), let e_1, ...,
e_n be the actual argument expressions of the method invocation and let
A_i be the type of e_i, 1 <= i <= n.... [L]et S_1 ... S_n be the types
of the formal parameters of m.
"The method m is applicable by subtyping if and only if both of the
following conditions hold:
* "For 1 <= i <= n, either:
o "A_i is a subtype (4.10) of S_i (A_i <: S_i) or
o "A_i is convertible to some type C_i by unchecked conversion
(5.1.9), and C_i <: S_i. "

Applying this to your case, the A_1 = java.lang.Object, and A_2 =
java.lang.Object. The S_1 and S_2 are either both java.lang.Integer, or
java.lang.Double, or char. Obviously, an Object is not an Integer nor is
it a Double or char, so none of the methods apply.

15.12.2 then proceeds to start delving into more complex matters
inapplicable here, especially the process of resolving generic types.
This is an interesting discussion, but an off-topic one nonetheless for
the problem at hand. However, there is one last useful tidbit of matter,
and that emanates from 15.12.2.12:

"The most applicable method is chosen at compile time; its descriptor
determines what method is actually executed at run time." Paraphrasing,
the compiler is the one who decides which method to call, not the
runtime engine. All that happens at runtime is that the right overridden
method is called (15.12.4 if you're feeling adventuresome).

If you want to be able to dynamically select methods, the only
non-reflection mechanisms to do so rely on either overriding polymorphic
methods, which static methods are not, or manual switch-like constructs.
The structure of Integer/Double/etc. are such that the first approach is
likely to present problems. Your other option, of course, is to use
reflection.

[1] If you really want to split hairs, I believe the JVM's invokedynamic
instruction has functionality which could select an overloaded method
based on runtime-determined types. However, invokedynamic has no
correlating Java equivalent, and can only be emulated through reflection.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth


All times are GMT. The time now is 07:11 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.