Elye
Elye

Reputation: 60321

What's the difference between Class<*> and Class<T>

I have two way of writing my functions as below

private fun createFragment(fragmentClass: Class<*>, fragmentArgs: Bundle?): Fragment {
    try {
        val fragment = fragmentClass.newInstance() as Fragment
        fragment.arguments = fragmentArgs
        return fragment
    } catch (exception: Exception) {
        throw RuntimeException(exception.message)
    }
}

And this

private fun <T>createFragment(fragmentClass: Class<T>, fragmentArgs: Bundle?): Fragment {
    try {
        val fragment = fragmentClass.newInstance() as Fragment
        fragment.arguments = fragmentArgs
        return fragment
    } catch (exception: Exception) {
        throw RuntimeException(exception.message)
    }
}

I don't know what's the different of making it Class<*> vs 'Class`. How do they differ from each other? Which is is better?

Note: I understand the is done better using reified e.g. , without need to use Class at all. But I just want to understand without reified, what's the different between using Class<*> vs Class<T>

Upvotes: 2

Views: 162

Answers (2)

Elye
Elye

Reputation: 60321

Both resulted in the exact same decompiled Java code

private final Fragment createFragment(Class fragmentClass, Bundle fragmentArgs) {
  try {
     Object var10000 = fragmentClass.newInstance();
     if (var10000 == null) {
        throw new TypeCastException("null cannot be cast to non-null type android.support.v4.app.Fragment");
     } else {
        Fragment fragment = (Fragment)var10000;
        fragment.setArguments(fragmentArgs);
        return fragment;
     }
  } catch (Exception var4) {
     throw (Throwable)(new RuntimeException(var4.getMessage()));
  }
}

So they are the same. Like what @Willi Mentzel says, we should only use Class<T> if we need to use T. One example is as below (e.g. return the type of it), that we could get the exact same type

private fun <T>createFragmentX(fragmentClass: Class<T>, fragmentArgs: Bundle?): T {
    try {
        val fragment = fragmentClass.newInstance()
        (fragment as Fragment).arguments = fragmentArgs
        return fragment
    } catch (exception: Exception) {
        throw RuntimeException(exception.message)
    }
}

Upvotes: 0

Willi Mentzel
Willi Mentzel

Reputation: 29914

* is called star-projection. You use it when you have to specify a generic type but don't care for what it is (maybe because you don't need it).


Since this question is not in a special way related to the Class<T> class, let me show you how it works with a simple example:

Consider this simple function that takes a List and prints it:

fun printList(l: List) { println(l) }

It won't compile with the following error:

One type argument expected for interface List<out E>

I could fix it like this:

fun <T> printList(l: List<T>) { println(l) }

but this is tedious because I actually don't care for T and I don't need it.

Here comes the star-projection into play:

fun printList(l: List<*>) { println(l) }

This will compile, is short and concise.


So, in your particular example you should use Class<*> because you simply don't need T.

Upvotes: 5

Related Questions