Stefan
Stefan

Reputation: 848

compile time type at runtime

Is there any way in Java to get the compile time type of a reference at runtime?

Example:

private void doSomething(final Object o)
{
   // do somthing
}

final Number n = 1; 
doSomething(n);

final Object o = 1; 
doSomething(o);

final Integer i = 1; 
doSomething(i);

1st call --> Number

2nd call --> Object

3rd call --> Integer

Edit: This is a very simplified version of the problem. What i am trying to do is to detect(instead of being told) inside a framework metadata about objects being passed. What could happen is, that the method gets first called with an Integer and then with a Double, both declared as Number.

Upvotes: 2

Views: 929

Answers (5)

cyber-monk
cyber-monk

Reputation: 5570

you can use 'instanceof'

public class Test {
  private static void doSomething(final Object o){
    if(o instanceof Number){
      System.out.println("it's a number!");
    }
    System.out.println("canonical class : "+o.getClass().getCanonicalName());
  }
  public static void main(String[] args) {
    Number n = new Integer(10);
    doSomething(n);
  }
}

prints out

it's a number!
canonical class : java.lang.Integer

Another option is to recursively check superclasses

public class Test {
  private static Class<?> doSomething(final Object o){
    // assuming o is not null
    Class<?> klass = getSuperClass(o.getClass());
    return klass;
  }

  private static Class<?> getSuperClass(Class<?> klass){
    // if super class is object or null break recursion
    if(klass.getSuperclass() == null || klass.getSuperclass().equals(Object.class)){
      return klass;
    }
    // keep looking higher up 
    return getSuperClass(klass.getSuperclass());
  }

  public static void main(String[] args) {
    Number n = new Integer(10);
    System.out.println("n  is a "+doSomething(n).getCanonicalName());
    Object o = new Integer(10);
    System.out.println("o  is a "+doSomething(o).getCanonicalName());
    Number d = new Double(10.0d);
    System.out.println("d  is a "+doSomething(d).getCanonicalName());
    String s = "10";
    System.out.println("s  is a "+doSomething(s).getCanonicalName());
    Object so = "10";
    System.out.println("so is a "+doSomething(so).getCanonicalName());
  }
}

prints out

n  is a java.lang.Number
o  is a java.lang.Number
d  is a java.lang.Number
s  is a java.lang.String
so is a java.lang.String

Upvotes: 0

Jhonathan
Jhonathan

Reputation: 1601

Use object.getClass()

private static void doSomething(final Object o) {
    System.out.println(o.getClass().getSuperclass());
}

private static <T extends Number> void doSomething(final T o) {
    System.out.println(o.getClass());
}


final Integer n = 2;
doSomething(n);

final Double n = 2D;
doSomething(n);

Upvotes: 0

NPE
NPE

Reputation: 500853

Quite simply, you can't.

You already know the compile-time of the function argument (Object) and you can find out the run-time type of the object that's passed in (by using getClass()). However, there's no way to get the information you're asking for.

Upvotes: 1

Paul
Paul

Reputation: 20091

You can't. Integer is the correct answer, because Number is an abstract class and you can't have an instance of an abstract class, and you relied on autoboxing to convert the primitive int.

Upvotes: 0

H-Man2
H-Man2

Reputation: 3189

The only way I see is to use overloading. But you would need to specify a overlading method for each class of the inheritance relation to exclude sub classes.

private void doSomething(final Object o)
{
   // do something
}

private void doSomething(final Number n)
{
   // do something
}

private void doSomething(final Integer i)
{
   // do something
}

final Number n = 1;
doSomething(n); // doSomething(final Number) is called.

Upvotes: 2

Related Questions