---
# System prepended metadata

title: 'Java Advanced Concepts -  [Generics]'

---

---
title: Agenda
description: 
duration: 280 
card_type: cue_card
---

## Agenda

**[Note for instructor]**
* Talk about what we have covered in the previous classes and then continue with the agenda. 

Hello everyone, We have covered OOPs and Concurrency, and now we will be discussing advanced language concepts, i.e. Generics. So, let's look at our agenda today.

* Generic Types
* Raw types
* Generic Methods
* Wildcard and Bounds
* Inheritance and Generics
* Type Erasure

---
title: Generic Types
description: Why do we need generics , before and after of the generic types and its pros and cons
duration: 2420
card_type: cue_card
---

So, let's start our discussion with Why we need generics.

##  Why We Need Generics?

Suppose we need to store a pair of data, for example:
* List of Student data with student name and ID, or
* List of Coordinates of longitude and latitude, or
* bacially with any data-types.

In all these applications, we will need a data type to store these pairs to do operations on them.

**[Ask learners]**
* In programming, how have we learned to store a combination of pairs in a data structure?
    * Using Pair or Tuple.

So, Tuple and Pair are inbuilt into a lot of programming language, but it is not inbuilt in Java.
In C++, it is called a Pair, and in Python, it is called a Tuple. 

So **how we can do this in Java.**

We can create a pair like this: 

`Pair cord1 = new Pair( 1.4 , 1.6);`

Or, 

`Pair student1 = new Pair( 1C , "Naman");`

These pairs can have any values of any data types. **But as told earlier there is no Pair class in Java.**

**[Ask Learners]**
* What should be our Goal now?

Goal: To build a custom class to implement the Pair class functionality with all the features of Pair from different languages like type-safety.

First **Lets create a pair to store only the coordinates.**

1.  **To store only the coordinates as pairs**
    * We name our class as a pair
    * We declare the variables named first and second. Since we are creating the generic classes, we can't name them as latitude and longitude.
    * In most of the languages, it is called first and second.

    ```java
    class Pair{
        double first;
        double second;

        Pair(first,second){
            this.first = first;
            this.second = second;
        }
        getFirst(){
            ...
            ...
        }
        getSecond(){
            ...
            ...
        }
    }
    ```

    Now, we can use this class as a pair class and use it to store the coordinates,
    `Pair cord1 = new Pair( 1.4 , 1.6);`
    And it will work perfectly fine.

    **[Ask Learners]**
    * But is this class really a pair class?
        * No, this class is just acting like a pair class and has a fixed `double` variable type in its signature.

    **Pros :** Compile Time Type Safety
    **Cons :**  Not generic enough.
    
2. **Using the Objects :**

    **Since we needed to store strings, numbers, and combinations of these to store any data-types**

    And how can we perform that: 

    In Java we know that **Every class is implicitly the child class of object**

    ![image](https://hackmd.io/_uploads/HkP245Gqa.png)

    Lets try to implement this: 
    
    
    ```java
    class Pair{
        object first;
        object second;

        Pair(first,second){
            this.first = first;
            this.second = second;
        }
        getFirst(){
            ...
            ...
        }
        getSecond(){
            ...
            ...
        }
    }
    ```
    
    Now, we can run the following code easily:
    ```java
    Pair p = new pair(10, "Naman");
    ```

    ```java
    Pair p = new pair("Hey", "Hi");
    ```

**[Ash the Learners: ]**
So is our problem solved?? 

Problem:
Suppose We do,

```java
a = p.getFirst();
```

Moving ahead, I do some operations on **a**, and then it will throw an error. Because a is of object type, we might think of it as a string or integer.

We can perform the typecasting but, it's not necessary that we will always know the data type of the value. This is the downside of typecasting.

Let's understand this with an example:
```java
List<Pair> l = {("Hi","Hello"),(1,"Naman"),(1.3,3.2)};
```
Now, all the three elements are valid **pair**, right?

Let's iterate them as we discussed earlier using the typecasting,

```javascript
for(pair p:l){
    string f = (String) p.getFirst();
    string s = (String) p.getSecond();
}
```
**[Ask Learners]**
* Do you think this code will compile?
    * Yes, it will compile because it doesn't have a syntactical error.

You are telling the compiler to convert this object to string always, and the code gets compiled completely.
* But now, when the code is running, what will happen now?
    * You will get an error in the runtime when you try to print the values and convert long values to string; having errors in runtime is not a good thing.
    * At this point, you have to revert the code immediately and debug the code.

For a good engineer, try to catch as many errors as possible during the compilation.

**So, now our problem statement is to create classes to confirm the compile time security that we have discussed above and avoid errors in the Runtime of the program, and here comes the generics in picture.**

## Generics Types.

Generics basically allows you to define a class with **parametrized data-types** of attributes. variables(that are **not-fixed**). 
[**For the instructor:**] Emphasize on the parametrized data-types.

Let's see how to create a generic class: 

When we make our pair class, we define some variables with it, like the first and second in earlier classes that we made.
But, instead of doing so, we should send some variables along with the class name, as shown below.

```java
Class Pair<F,S>{

}
```
So, now, when anyone creates a pair, they have to say it like Pair<Integer, String>, and this will make F as Integer and S as String.

like this : 

```java
Class Pair<F,S>{
    F first;
    S second;
    Pair(F a, S b){
        this.first = a;
        this.second = b;
    }
    F getFirst(){
        return a;
    }
    S getSecond(){
        return b;
    }
}
```

We will be using them something like this: 

```java
public static void main(String[] args){
    Pair<Integer, String> p1 = new Pair(1,"Hello");
    Pair<Double, Double> coo1 = new Pair(3.1,23.1);
}
```

Now if I try from above:

```
String s = p1.getFirst();
```
It will throw a compile-time type-safety error which is a good thing.

Now let's discuss about the Raw-Data Types: 

---
title: Raw Data types
description: what basically are the raw types and how the generics was used before the Java 5
duration: 3000
card_type: cue_card
---

### Raw Types: 

So, before Java 5, there were no concepts of generics, and Java tries to make the code written on the older version must keep on working in the newer versions. They call it as a **Backward compatibility**.

So **generic data types** can be used without their parameters as well, and when you use them like this, they are called **Raw Data types**. They used objects to perform similar operations.

The best example to understand the raw data types is the **Hashmaps**

**[Ask the Learners]**
What this is going to return: 

```java
HashMap hm = new HashMap();

    hm.put(1,"Naman");

    hm.put("Naman",1);

    for(var v: hm.keySet()){
        int i = (Integer) v;
        System.out.println(i);
    }
```

It wil return the error in the compile-time as: 

```error
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
	at Main.main(Main.java:12)
```

Thats why we used the parametrized one but due the **backward compatibility ** of the Java it is still present.

This is what a **raw-types** basically looks like.

---
title: Generic Methods 
description: When we use the generic methods. and what are they
duration: 3000
card_type: cue_card
---

Till we were creating the generic class but sometimes we don't even need to use to generics at the level of class and we specify in the methods.

Typically this happens with the **static utility methods.**


So what does a generic method mean. lets understand them with an example: 

For example: 

I created a Demo class as follows: 

```
package com.example.practice;

public class Demo {
    public static void doSomething(K key, V value){
        System.out.println(key);
        System.out.println(value);

    }
}
```

**[Ask the Learners:]**

Now are **K and V pre-defined data-types**. 

**Answer: ** No. 

So if I want to use the type-parameters as method I can do is that I can use the class-parameters: 

```
package com.example.practice;

public class Demo<K,V> {
    public static void doSomething(K key, V value){
        System.out.println(key);
        System.out.println(value);

    }
}
```

But these parameters are called after creation of object but **the static methods are defined even before the creation of the object.**

```
package com.example.practice;

public class Demo<K,V> {
    public void doSomething(K key, V value){
        System.out.println(key);
        System.out.println(value);

    }
}
```


But if I don;t want to use the class parameters I can do something like: 

```
package com.example.practice;

public class Demo {
    public <K,V> void doSomething(K key, V value){
        System.out.println(key);
        System.out.println(value);

    }
}
```

Now If I call it: 

![image](https://hackmd.io/_uploads/HJbIEaMq6.png)

we can see that how before using the parameters it was the object and after that if became that specific data-type. 

![image](https://hackmd.io/_uploads/HkL5Npz9T.png)

I can do the both no matter. 

**[For the instructor:]** Show by changing the void return type of demo to int or string and how we can use them particularly.

**Note:**

* In the class parameter the data-types are defined at the creation of object.
* But in the methods the data-types are defined during the method call.

Lets move onto the next section: 

---
title: Generics and Inheritance and Bounds
description: How generics works with the inheritance and how bounds play a role in that,Upper Bound and Lower Bound.
duration: 3000
card_type: cue_card
---

For example: If I have a Animal class. and that animal class has some child classes say: Dog , Cat and any other. 

Now I define some method doSomething as: 

```java
doSoemthing(List<Animals> as){

}
```

Lets say I no define: 

```java
List <Dogs> dogs = {};

doSomething(dogs);
```

**[Ask the Learners:]**

How many of thinks that this method is allowed that we passed.

Answer: 
**We can't.**

Intutively we should have been because the **Dogs is the child class of animal** so **this should be allowed.** But this not how the generics works in **inheritance.**

Basically we have to find that in the below image why the first one is correct and the second one is not: 

![image](https://hackmd.io/_uploads/Sy91cpG5a.png)

This usually happens because of that concept that says that let say **Animal is the parent of the Dog** but the **List<Animal> is not the parent of List<Dog>**.
    
![image](https://hackmd.io/_uploads/SyHIc6Gqp.png)

The answer to this lies how the list works at the run time: 
    
say we had **List <K>**
1. At runtime in order to provide the type safety the K gets removed.
2. At runtime it is only a List<>
    
So all of the List<Animals> or the List<Dogs> they becomes List<> at run time.

This is **against our intution** but it is a **newbie mistake.**
    
Here comes the concept of bounds: 
    
When you declare the generic types you can also specify the constarins on that. 
    
What I mean is that : 
    
instead of 
    
```
doSomething(List<T>)
```
becuase this only refers to the animals.
    
we can pass: 
    
    
```
doSomething(List<T extends Animal>)
```    
    
which basically looks like this: 
    
![image](https://hackmd.io/_uploads/H1Um26f56.png)

    
Lets also think that we had created another method `doSomething2()` and we want to pass the List<Dogs> to it. 
    
```java
doSomething2(List<Dogs>)
```
    
But I also want to take fromt the Animal class since its a parent one.
    
so what I can write is : 
    
```java
doSomething2(List<T super Dogs>)
```
    
So it i basically saying **list of dogs or the superclass of dog.**
    
So basically,
    
1. When we are using **extends** we are specifying the **upper-bound.**
2. and, when we are using the **super** we are specifying the **lower-bound.**
    
---
title: Type Erasure
description: How Type Erasure and Problems that it causes.
duration: 3000
card_type: cue_card
---
    
As we have seen above that during the run time any list of any type say: 
    
List<Animals> or List<Dogs> was just becoming a normal list.
    
Let's see this with our hashmap example also: 
    
![image](https://hackmd.io/_uploads/HyUTQCMcp.png)

As we can in the below exmaple that we are getting the output to be just the hasmap not the data-type that we defined to it as <String,Integer>. 
    
This is what we call as **Type Erasure.**
    
### Problem with the Type Erasure. 
    
1. In the upcoming classes we will be building our multi microservice architecture.
2. There each service talks to another.
3. The data is transfered also in the form of **JSON** only. 
4. But since we the Java as the backend we also have to define the List type there.
    
For exmaple: 
    
![image](https://hackmd.io/_uploads/ryMhNCM96.png)
meaning **whatever response you get fromt the URL convert this to the object of Animal class.**
    
But since all of this will be happening at the **run-time** so the Animal data-type will get erased and we won't be able to perform the operation.
    
This is what **problem occurs with the type-erasure.**
    
We will be learning about tackling them in the **project-module.**
    
### Homework: 
    
1. Read this [articel](https://docs.oracle.com/javase/tutorial/java/generics/why.html) in detail.
2. Try to solve all the 12 questions presnt in the above article. [link](https://docs.oracle.com/javase/tutorial/java/generics/QandE/generics-questions.html)