Home > OS >  Difference between abstract class BaseVMActivity<VM : ViewModel, B : ViewBinding> and abstract
Difference between abstract class BaseVMActivity<VM : ViewModel, B : ViewBinding> and abstract

Time:12-16

I'm new to Kotlin and learning it. I came up with some advance syntax.

abstract class BaseVMActivity(VM:ViewModel,B:ViewBinding) => This is I know as constructor.

But

abstract class BaseVMActivity<VM : ViewModel , B : ViewBinding> => This syntax I didn't understand.

How it is different from constructor?

CodePudding user response:

The syntax with <> is for generic type parameters, it is independent from the constructor.

You can read a little about generics in the documentation, but the doc is more focused on the differences with Java (for instance regarding generic variance), rather than explaining the basics of generics. The Java documentation, as mentioned by @Tenfour04, is more instructive.

Basically generic classes are useful when the code of the class should be identical apart from the types of some input/output values of the class (constructor/method arguments and return types). It allows to have more type safety than just using Any everywhere, or another parent type.

For instance, this Box class can contain any type of value:

class Box(var value: Any)

But when you get an instance of Box you can't know what it contains at compile time: accessing box.value gives you a value of type Any, and you need to cast it (risking failures at runtime) in order to get a usable value:

val box: Box = Box("some string")

val value1: String = box.value // not allowed

val value2: String = box.value as String // risky if box is declared somewhere else

val value3: Int = box.value as Int // compiles fine, fails at runtime

Generics are a nice way to add compile-time safety. This is how to declare a generic Box<T> class, where T is a type that is decided when instantiating the class. Different instances of Box can have a different type of value:

class Box<T>(var value: T)


val box: Box<String> = Box("some string")

// this compiles and is safe, because it's a Box<String>, not any box
val value: String = box.value

val value: Int = box.value // doesn't compile
val value: Int = box.value as Int // doesn't compile, because String can't be cast to Int

Now this Box<T> can be used with any type T, but sometimes you want to constrain that type to only accept some types. This is where the syntax with : comes from:

abstract class Animal
class Dog : Animal()
class Cat : Animal()

class Box<T : Animal>(val animal: T)

If I declare Box this way, only subtypes of Animal will be allowed:

val catBox: Box<Cat> = Box(Cat())
val dogBox: Box<Dog> = Box(Dog())
val stringBox: Box<String> = Box("some string") // doesn't compile

You can also declare multiple type parameters in a generic class by separating them with commas:

interface Map<K, V>

Each type parameter can have its own bounds as well, which is what leads to the syntax you've seen:

abstract class BaseVMActivity<VM : ViewModel , B : ViewBinding>

In this case, there are 2 type parameters, VM and B, which must respectively be subtypes of ViewModel and ViewBinding.

  • Related