简体   繁体   中英

Recognizing extended class object

In Java, I have a class Num , and a few classes that extend Num , like Num_int and Num_double . I want to know whether it's possible for a method to recognize whether a given Num object is a Num_int or not.

I have the following code:

void test(Num_int x) {
  System.out.println("int");
} // test
void test(Num x) {
  System.out.println("other");
} // test

Num_int A = new Num_int( );
Num B     = new Num_int( );
Num C     = new Num_double( );

test(A); // prints "int"
test(B); // prints "other"
test(C); // prints "other"

Unfortunately, the method "test" only prints "int" when A is given as argument. I wan't the function to also print "int" when B is passed, since B is created via Num B = new Num_int( ); . Is this possible?

Thanks.

if (x instanceof Num_int) {
  System.out.println("int");
} else {
  System.out.println("other");
}

If you want polymorphic behaviour, then make the test method an overridable method of the Num class.

Overloaded methods are not resolved polymorphically based on the runtime type of the arguments. They're resolved at compile-time, based on the declared type of the arguments.

This can be done using the instanceof operator and casting. However, this is a poor programming practice.

A better option is to make test() a non- final member of Num , and override it appropriately in each class. Then you just call A.test() , and Java's dynamic dispatch will take care of everything for you.

public class Num {
  public void test() {
    System.out.println("other");
  }
}

public class Num_int extends Num {
  public void test() {
    System.out.println("int");
  }
}

public class Num_double extends Num {
  // inhertis Num.test()
}

The problem is that method signatures are binded at compile time in Java, so the declared type determines which method is called.

See also the puzzler "Making a Hash of It" in the book Java Puzzlers .

You could use double-dispatching and the Visitor pattern. It would look something like this:

Num_int A = new Num_int( );
Num B     = new Num_int( );
Num C     = new Num_double( );

Num_printer p = new Num_printer();

A.accept(p);
B.accept(p);
C.accept(p);

The Num_int.accept(...) and Num_double.accept(...) methods would both look like this:

public class Num_int extends Num {
    public void accept(Num_visitor v) {
        v.visit(this); // from this scope, `this` has a declared type of `Num_int`
                       // so at compile time this is binded to signature visit(Num_double)
    }
}

public class Num_double extends Num {
    public void accept(Num_visitor v) {
        v.visit(this); // from this scope, `this` has a declared type of `Num_double`
                       // so at compile time this is binded to signature visit(Num_double)
    }
}

Even though these methods are almost identical, it's important that the method isn't extracted into the parent class. I'd go so far as to make it abstract in the parent class:

public class Num {
    public abstract void accept(Num_visitor);
}

From within class Num , this is of declared type Num . If the accept method were defined here, the compile-time binding would be to signature visit(Num) - giving you the same original problem all over again.

Lastly, the Num_printer would look like this:

public class Num_printer implements Num_visitor {

    public void visit(Num_int n) {
        System.out.println("int");
    }

    public void visit(Num_double n) {
        System.out.println("double");
    }

}

You can use the instanceof operator. Read the " The Type Comparison Operator instanceof " part in this document .

if (x instanceof Num_int) {
  // do something
} else if (x instanceof Num_double) {
  // do something else
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM