Java multiplication of numbers and

Discussion in 'Java' started by leung.january@gmail.com, Jul 16, 2008.

  1. Guest

    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)));
    }
    }
    , Jul 16, 2008
    #1
    1. Advertising

  2. Mark Space Guest

    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 ) );
    }
    }
    Mark Space, Jul 16, 2008
    #2
    1. Advertising

  3. 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
    Joshua Cranmer, Jul 16, 2008
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Subra
    Replies:
    25
    Views:
    1,190
    user923005
    Mar 8, 2007
  2. Andrew Tatum

    Fibonacci Numbers and Lucas Numbers

    Andrew Tatum, May 26, 2007, in forum: C++
    Replies:
    6
    Views:
    561
    Howard
    May 27, 2007
  3. William Hughes
    Replies:
    13
    Views:
    1,216
    Ben Bacarisse
    Mar 15, 2010
  4. harryos
    Replies:
    6
    Views:
    763
    Peter Otten
    Sep 20, 2010
  5. eli m
    Replies:
    10
    Views:
    359
    Geoff
    Mar 18, 2013
Loading...

Share This Page