简体   繁体   中英

How to resolve type on runtime in generics overloading java

I am tying to resolve type on runtime with generics. Here is my code.

public class NewClas {
    public static void main(String[] args) {
        Object object = null;
        String string = null;
        Integer integer = null;
        // with out generics
        print(object);
        print(string);
        print(integer);
        // print(null); // this won't complile

        // with generics
        Verify<Object> objectVerify = new Verify<Object>();
        Verify<String> stringVerify = new Verify<String>();
        Verify<Integer> integerVerify = new Verify<Integer>();

        objectVerify.call();
        stringVerify.call();
        integerVerify.call();

    }

    public static void print(Object obj) {
        System.out.println("Obj");
    }

    public static void print(String string) {
        System.out.println("string");
    }

    public static void print(Integer integer) {
        System.out.println("Int");
    }
}

// if T extends String then only print(String string) will call
class Verify<T> {
public T obj = null;

    public void call() {
        print(obj);
    }

    // even this is not working
    /*public <T> void call() {
        print((T)obj);
    }*/

    public  void print(Object obj) {
        System.out.println("Obj");
    }

    public  void print(String string) {
        System.out.println("string");
    }

    public  void print(Integer integer) {
        System.out.println("Int");
    }
}

How do I utilize/call methods print(String string),print(Integer integer) in generic class.

Even I have tried

stringVerify.obj =  new String();
stringVerify.call();

which is calling same method with object signature.

Also tried following, which is also invoking same method with object signature.

Verify<String> stringVerify = new Verify<String>() {};
stringVerify.obj =  new String();
stringVerify.call();

for all above scenarios output will be.

Obj
string
Int
Obj
Obj
Obj

Following is what I want

Obj
string
Int
Obj
string
Int

please educate me.

Check for instanceof in your call method of Verify class:

public void call() {
 if(obj.instanceof(String)) {
    print((String)obj);
 } else if (obj.instanceof(Integer) {
    print((Integer)obj)
 }

Your code works as it should. The first three results are correct because method overloading is resolved at compilation. This means that the method whose signature argument matches the type of the parameter used when calling the method will be used.

Regarding the calls made from the Verify class, you must take into account that type information is erased at compilation. This means that for all the instances of your class, the obj variable's type will be Object. Because of this, the same result (Object) will be printed for all calls.

If you use <T extends String> as the type declaration for your Verify class, at compilation the obj reference variable will be of type String.

You can modify your class like this, but this won't allow you to pass a null object since it will throw a NPE:

 public Verify(T obj) {
    this.obj = obj;
    this.type = (Class<T>) this.obj.getClass();
 }

 public void call() {
    if (type == Object.class) {
        print(obj);
    } else if (type == String.class) {
        print((String) obj);
    } else if (type == Integer.class) {
        print((Integer) obj);
    }
}

You can also send the class as an explicit parameter and no NPE will be thrown:

    private Class<T> type = null;

    public Verify(Class<T> type, T obj) {
       this.obj = obj;
       this.type = type;
    }

Try with this implementation :

class Verify<T> {
        public final T obj;

        Verify(T obj) {
            this.obj = obj;
        }


        public void print() {

            switch (obj.getClass().getSimpleName()) {
                case  "String" :
                    System.out.print("string");
                    break;
                case "Integer" :
                    System.out.print("Int");
                    break;
                 default:
                     System.out.print("Object");
            }
        }

    }

Generics type erasure. In your case generic type <T> erased to Object .

For more information read this documentation

https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Sorry for my bad English.

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