Rio: Guys, today Mr Archie would be telling us about the concept of Generics in Java. I am sure this lecture is going to clear all your doubts around Generics. You may come up with your queries as we move along. You have the floor now, Mr Archie.
Mr Archie: Thank you, Rio. So guys, most of you must have already heard about the term Generics in Java.
Rio: Yes, Mr Archie.
Mr Archie: Good, so have you ever wondered where do we use Generics in Java?
Audience is silent.
class StringPrinter {
private String toPrint;
StringPrinter(String toPrint){
this.toPrint = toPrint;
}
public void print(){
System.out.println(toPrint);
}
}
public class Generics {
public static void main(String[] args) {
StringPrinter printer = new StringPrinter("Anshul");
printer.print();
}
}
Suppose later at some point of time you need to create another class which you should be able to use to print an integer. You can create another class almost like the above one
public class IntegerPrinter {
private Integer toPrint;
IntegerPrinter(Integer toPrint) {
this.toPrint = toPrint;
}
public void print() {
System.out.println(toPrint);
}
}
public class Generics {
public static void main(String[] args) {
StringPrinter stringPrinter = new StringPrinter("Anshul");
stringPrinter.print();
IntegerPrinter integerPrinter = new IntegerPrinter(12);
integerPrinter.print();
}
}
If you take a look carefully, the code is almost duplicate for the two classes viz. StringPrinter and IntegerPrinter.
This duplicity can easily be removed using Generics. We can create a parameterised class as below
public class Printer<T> {
T toPrint;
Printer(T toPrint){
this.toPrint = toPrint;
}
public void print(){
System.out.println(toPrint);
}
}public class Generics {
public static void main(String[] args) {
Printer<String> stringPrinter = new Printer<>("Anshul");
stringPrinter.print();
Printer<Integer> integerPrinter = new Printer<>(12);
integerPrinter.print();
}}
Mr Archie: Yes its, indeed, a cool feature provided by Java. Not only classes we can also create generic methods using Generics.
public class Printer<T> {
T toPrint;
Printer(T toPrint){
this.toPrint = toPrint;
}
public void print(){
System.out.println(toPrint);
}
public T get(){
return toPrint;
}
}
public class Generics {
public static void main(String[] args) {
Printer<String> stringPrinter = new Printer<>("Anshul");
String str = stringPrinter.get();
System.out.println(str);
Printer<Integer> integerPrinter = new Printer<>(12);
Integer integer = integerPrinter.get();
System.out.println(integer);
}
}
- Unbounded Generic Types: The unbounded generic types can take any known reference type <T> or a wildcard <?> if the type is unknown.
- Bounded Generic Types: In case, for known reference types, if you want to create a boundary of the types that will be accepted by the generic class/method. we can use bounded generic types.
- Upper Bounded
- Lower Bounded
public class Animal {
private String name;
Animal(String name) {
this.name = name;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
'}';
}
}
public class Generics {
public static void main(String[] args) {
Printer<String> stringPrinter = new Printer<>("Anshul");
String str = stringPrinter.get();
System.out.println(str);
Printer<Integer> integerPrinter = new Printer<>(12);
Integer integer = integerPrinter.get();
System.out.println(integer);
Printer<Animal> aPrinter = new Printer<>(new Animal("Cat"));
System.out.println(aPrinter);
}
}
public class Printer<T extends Number> {
T toPrint;
Printer(T toPrint){
this.toPrint = toPrint;
}
public void print(){
System.out.println(toPrint);
}
public T get(){
return toPrint;
}
public String toString(){
return toPrint.toString();
}
}
public class Printer<T extends Animal> {
T toPrint;
Printer(T toPrint){
this.toPrint = toPrint;
}
public void print(){
System.out.println(toPrint);
}
public T get(){
return toPrint;
}
public String toString(){
return toPrint.toString();
}
}
public class Generics {
public static void main(String[] args) {
List<Number> listNumber =Arrays.asList(1, 2);
List<Integer> listInteger =Arrays.asList(1, 2);
List<Object> listObject =Arrays.asList(1, 2);
print(listNumber);
print(listInteger);
print(listObject);
}
private static void print(List<Integer> listNumber) {
}
private static void print(List<Number> listNumber) {
}
private static void print(List<Object> listNumber) {
}
}
public class Generics {
public static void main(String[] args) {
List<Number> listNumber =Arrays.asList(1, 2);
List<Integer> listInteger =Arrays.asList(1, 2);
List<Object> listObject =Arrays.asList(1, 2);
print(listNumber);
print(listInteger);
print(listObject);
}
private static void print(List<? super Integer> listNumber) {
listNumber.stream().forEach(System.out::println);
}
}
public class Generics {
public static void main(String[] args) {
Animal[] arrayAnimal = new Animal[10];
arrayAnimal[0] = new Animal("monkey");
arrayAnimal[1] = new Cat("cat");
arrayAnimal[2] = new Dog("dog");
List<Animal> listAnimal = new ArrayList<>();
listAnimal.add(new Animal("monkey"));
listAnimal.add(new Cat("cat"));
listAnimal.add(new Dog("dog"));
}
private static void doStuff(Object[] objects) {
System.out.println(objects);
}
private static void doStuff(List<Object> objects) {
System.out.println(objects);
}
}
public class Generics {
public static void main(String[] args) {
List<Animal> listAnimal = new ArrayList<>();
listAnimal.add(new Animal("monkey"));
listAnimal.add(new Cat("cat"));
listAnimal.add(new Dog("dog"));
doStuff(listAnimal);
}
private static void doStuff(List<?> objects) {
System.out.println(objects);
}
}
public class Generics {
public static void main(String[] args) {
Animal[] arrayAnimal = new Animal[10];
arrayAnimal[0] = new Animal("monkey");
arrayAnimal[1] = new Cat("cat");
arrayAnimal[2] = new Dog("dog");
List<Animal> listAnimal = new ArrayList<>();
listAnimal.add(new Animal("monkey"));
listAnimal.add(new Cat("cat"));
listAnimal.add(new Dog("dog"));
doStuff(arrayAnimal);
doStuff(listAnimal);
}
private static void doStuff(Object[] objects) {
System.out.println(objects);
}
private static void doStuff(List<? extends Animal> objects) {
System.out.println(objects);
}
}
public class Generics {
public static void main(String[] args) {
List<Number> listNumber =Arrays.asList(1, 2);
List<Integer> listInteger =Arrays.asList(1, 2);
List<Object> listObject =Arrays.asList(1, 2);
print(listNumber);
print(listInteger);
print(listObject);
}
private static void print(List<? super Integer> listNumber) {
listNumber.stream().forEach(System.out::println);
}
}
- For bounded type parameters, bounded types are inserted.
- For unbounded type parameters, Object class is inserted.
- To preserve type safety, type casts are introduced t
- To preserve polymorphism in extended generic type classes, bridge methods are generated.
No comments:
Post a Comment