Should this work?

Discussion in 'Java' started by Steve Green, Mar 26, 2005.

  1. Steve Green

    Steve Green Guest

    This gives the expected result "AB" if the class is declared as B b or cast
    to B, but when it is declared "A b" it returns "AA". Should it?

    public class A {}
    public class B extends A {}
    public class C {
    public static void main(String[] args) {
    A a = new A();
    A b = new B();
    C c = new C();
    c.print(a);
    c.print(b);
    }

    public void print(A a) { System.out.print("A"); }
    public void print(B b) { System.out.print("B"); }
    }
     
    Steve Green, Mar 26, 2005
    #1
    1. Advertisements

  2. yes its working correctly.

    When 'b' is declared as 'A b = ...' the 'b' reference is of the type
    'A' regardless of the fact that the object it points to is of type B.

    Therefore, when you do 'c.print(b)', you will be calling the print(A a)
    method.

    Its the reference Type that is used to determine which of the two
    overloaded methods to call.

    Therefore, if you did 'B b = ...' b's reference type would be 'B' and
    so print(B b) would be called.

    Andrew
     
    Andrew McDonagh, Mar 26, 2005
    #2
    1. Advertisements

  3. Steve Green

    Steve Green Guest

    Too bad, I had what I thought was a fairly eligant solution to a problem,
    but now I need to clutter it up with casts and class comparisons.
     
    Steve Green, Mar 26, 2005
    #3
  4. why would you?
     
    Andrew McDonagh, Mar 26, 2005
    #4
  5. Steve Green

    Bjorn Abelli Guest

    I wonder why you let "c" print out things based on what type "b" is in the
    first place.

    Why not turn the tables to IMHO a more "object-oriented" approach, to
    delegate that to the actual object?


    public class A {
    public void print() { System.out.print("A"); }
    }

    public class B extends A {
    public void print() { System.out.print("B"); }
    }

    public class C {
    public void print() { System.out.print("C"); }

    public static void main(String[] args) {
    A a = new A();
    A b = new B();
    A c = new C();
    a.print();
    b.print();
    c.print();
    }
    }


    // Bjorn A
     
    Bjorn Abelli, Mar 26, 2005
    #5
  6. Bjorn Abelli coughed up:
    {brake screech here!}

    C does not extend B. Poly-m cannot be achieved here in a statically typed
    language.
     
    Thomas G. Marshall, Mar 26, 2005
    #6
  7. Sometimes its not appropriate to give objects certain behaviors and so
    in this example, it may not be appropriate to give the print behavior to
    instances of A.

    A real world example would be if A and B classes were Model classes
    within an MVC triad. It would not be appropriate to give A or B the
    ability to print().

    However, having said that, there is another (well many other) way of
    achieving what Steve wants in a more 'elegant' (i.e. without casting) way.

    By using double dispatch, we can ask instance of A or B to call C back.
    Then the correct overloaded method would be called because the 'this'
    part of the updateMe(C c) method will either be an A or an B object
    depending upon the type at runtime.

    public class A {
    public void updateMe(C c) {
    c.print(this);
    }

    }

    public class B extends A {}

    public class C {
    public static void main(String[] args) {
    A a = new A();
    A b = new B();

    C c = new C();
    a.updateMe(c);
    b.updateMe(c);
    }


    public void print(A a) { System.out.print("A"); }
    public void print(B b) { System.out.print("B"); }
    }
     
    Andrew McDonagh, Mar 26, 2005
    #7
  8. Steve Green

    Bjorn Abelli Guest

    ...
    Sorry, Typo. It was meant to extend B.

    But you understood that anyway...

    ;-)


    // Bjorn A
     
    Bjorn Abelli, Mar 26, 2005
    #8
  9. Steve Green

    Bjorn Abelli Guest

    I imagined that "print" in the OP's case was only an example to illustrate
    how to achieve different behaviours depending on type without the need of
    casting.
    In both your and my example we delegate the "responsibility" of "guiding"
    the behaviour onto the actual class, but as you say, there are many
    different way to achieve this.

    In the end it all boils down to what the actual application is supposed to
    do, and what means would be appropriate in the specific case.

    // Bjorn A
     
    Bjorn Abelli, Mar 26, 2005
    #9
  10. Steve Green

    Steve Green Guest

    Maybe I should explain my situation a little more clearly and what I am
    actually trying to achive.
    I have a hierarchy of classes that define the data of my application for
    example:

    class A {}
    class B extends A {}
    class MyData
    {
    Vector<A> data;
    }
    public class MyDataWriter {
    public void writeXML(MyData md) { write(md); }
    private void write(MyData md)
    {
    System.out.println("<mydata>");
    for(A i : md.data) write(i);
    System.out.println("</mydata>");
    }
    private void write(A a) { System.out.println("<A/>"); }
    private void write(B b) { System.out.println("<B/>"); }
    }

    I didn't want MyData to know how to write itself, I wanted to keep the
    classes simple.
    I was hoping to deligate the printing to another class.
    This way I could keep XML generation separate from the classes being
    exported.
    If I wanted to write it out differently in the future I just create another
    writer and not clutter up the classes.

    In the past I have implemented this as:

    class A implements XMLWritable {}
    class MyData implements XMLWritable {}

    But I was hoping to put the logic all in one place.
    Is there a better approach?

    Thanks,
    Steve
     
    Steve Green, Mar 26, 2005
    #10
  11. Bjorn Abelli coughed up:
    Yep, sure. I only pointed it out though because the OP went out of his way
    to /not/ have C related. His declarations were:

    A a
    A b
    C c

    But whatever---I of course prefer a clean old polymorphism like you
    intended, any day of the week.
     
    Thomas G. Marshall, Mar 26, 2005
    #11
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.