Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generic method - how to make it call a specialized method

Tags:

java

generics

Is it possible for a generic method in Java to call a specific other method based on the type of the input?

I tried the following example which hopefully represents the problem.

class X {
  public void pr(Object s) {
      System.out.println("Object");
  }

  public void pr(String s) {
      System.out.println("String");
  }

  public <T> void go(T x) {
      this.pr(x);
  }

  public static void main(String[] args) {
    String v = "hello";
    X x = new X();

    // Both print "Object", while I want "String"
    x.go(v);
    x.<String>go(v);
  }
}

I would want go() to call pr(String). But whatever I do, pr(Object) is called.

The example above is for demonstration only, real application of this is much more complex.

Thanks in advance.

like image 707
Marcin Zukowski Avatar asked Sep 16 '26 18:09

Marcin Zukowski


2 Answers

Unfortunately what you described is not possible because of type erasure, so at runtime T is treated as Object so pr(Object) is chosen here.

One of possible solutions would be manually testing type of passed data and invoking correct method with little help of casting like

public <T> void go(T x) {
    if (x instanceof String)
        pr((String)x);
    else
        pr(x);
}

But if you can edit code of classes you will pass to go method then preferable solution would be adding/implementing pr method in each of them so you could invoke them using polymorphism:

interface CanPR{
    void pr();
}

class Foo implements CanPR{
    @Override
    public void pr() {
        System.out.println("pr from Foo");
    }
}

class Bar implements CanPR{
    @Override
    public void pr() {
        System.out.println("pr from Bar");
    }
}


class X {

    public <T extends CanPR> void go(T x) {
        x.pr();
    }

    public static void main(String[] args) {
        CanPR a = new Foo();
        CanPR b = new Bar();

        X x = new X();

        x.go(a); //prints: pr from Foo
        x.go(b); //prints: pr from Bar
    }
}

Actually in this context you don't even need generic type in go so you can rewrite it to

    public void go(CanPR x) {
        x.pr();
    }
like image 163
Pshemo Avatar answered Sep 19 '26 06:09

Pshemo


Try this:

class X {
      public void pr(Object s) {
          System.out.println("Object");
      }

      public void pr(String s) {
          System.out.println("String");
      }

      public <T> void go(T x) {
          if(x instanceof String){
              this.pr((String)x);
          } else {
              this.pr(x);
          }
      }

      public static void main(String[] args) {
        String v = "hello";
        X x = new X();

        // Both print "Object", while I want "String"
        x.go(v);
        x.go(new Object());
//      x.<String>go(v);
      }
    }

The problem was String is an Object too, so you need to check if it is something else, and that can be done with instanceof.

like image 38
Bruno Franco Avatar answered Sep 19 '26 08:09

Bruno Franco