Scott の 博客 Scott の 博客
首页
  • Data Structure and Algorithm
  • Java
  • 面试
  • Drafts
  • C++
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Scott

恋爱中
首页
  • Data Structure and Algorithm
  • Java
  • 面试
  • Drafts
  • C++
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Data Structure and Algorithm

  • Java

    • Java基础知识&面试题总结
    • Java
    • Control Flow
    • Clean Coding
    • Debugging and Deployment
    • Untitled
    • Refactor towards OOSD
    • Inheritance
    • Untitled
    • Exceptions
    • Generics
      • The need for Generics
      • A Poor Solution
      • Genric Classes
      • Generics and Primitive Types
      • Constraints
      • Type Erasure
      • Comparable Interface
      • Generic Methods
      • Multiple Type Parameters
      • Generic Classes and Inheritance
      • Wildecards
    • Collections
    • Lambda-Expression
    • Streams
    • Concurrency and Multi-threading
    • The Executive Framework
    • 4
    • 1
  • c++

  • 面试

  • Bilibili_Java

  • Python

  • All kinds of Drafts

  • High Integrity Information System

  • 左神算法课

  • 个人笔记
  • Java
Scott
2022-06-14
目录

Generics

  1. The need for Generics
  2. A Poor Solution
  3. Genric Classes
  4. Generics and Primitive Types
  5. Constraints
  6. Type Erasure
  7. Comparable Interface
  8. Generic Methods
  9. Multiple Type Parameters
  10. Generic Classes and Inheritance
  11. Wildecards

# The need for Generics

public class List {
  private int[] items = new int[10];
  private int count;

  public void add(int item) {
    items[count++] = item;
  }

  public int get(int index) {
    return items[index];
  }
}

public class Main {
    public static void main(String[] args) {
        var list = new List();
        list.add(1);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • The problem: We can only use the list to store integers
  • To store other types, we need to create XXXList classes, which is not scalable

# A Poor Solution

public class List {
  private Object[] items = new Object[10];
  private int count;

  public void add(Object item) {
    items[count++] = item;
  }

  public Object get(int index) {
    return items[index];
  }
}

public class Main {
    public static void main(String[] args) {
        var list = new List();
        list.add(1); // == list.ad(Integer.valueOf(1)) transfer a primtive type to a 				      //  new instace of the object class
        list.add("1");
        list.add(new User());
         
        // however 
        int number = (int) list.get(0); 
        int text   = (int) list.get(1);
        // 1. noisy and verbose type translation 
        // 2. possible invalid cast exception 
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# Genric Classes

public class Main {
    public static void main(String[] args) {
        // we specify the type of parameter when declaring the list object 
		var list = new GenericList<Integer>()
        // this ensures that every elements in that list is of the same type
            
        list.add(1);
        int number = list.get(0); // don't need explicit cast 
        // we get compile-time safety checks 
    }
}

// T stands for type parameter, it is a class parameter 
// it represents the type of parameter we want to store
public class GenericList<T> {
  // Java doesn't know what T stands for right now, so use object to replace it 
  private T[] items = (T[]) new Object[10];
  private int count;

  public void add(T item) {
    items[count++] = item;
  }

  public T get(int index) {
    return items[index];
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# Generics and Primitive Types

  • When creating an instance of a generic type, we can only use a reference type as a generic type argument
public class Main {
    public static void main(String[] args) {
        // int -> Integer
        // float -> Float
        // boolean -> Booelan 
		GenericList<Integer> numbers = new GenericList<>();
        numbers.add(1); // boxing: put this primitive valie inside a box
        int number = number.get(0) // unboxing: extract the int value
    }
}
1
2
3
4
5
6
7
8
9
10
  • The type of elements stored in that list can be User, Object or String, because they are reference types in Java
  • However, we cannot pass the primitive types
  • We need to use the wrapper class of those primitive types

# Constraints

  • Add a constraint or a restriction on a type parameter
  • This constraint can also be an interface like Comparable
// now T can only be the Number class or any of its children classes
//  e.g. Integer, Double
public class GenericList<T extends Number & Comparable> {
}
1
2
3
4

# Type Erasure

To show bit code

  • Build
  • Build project
  • Select the class
  • From the View menu
    • Select Show Bytecode

When building projects, Java will erase type parameter and replace it with an object class

If there is no constraints, in bit code, all in GenericList are still of object type, which is the same as the previous List class

  • Java will automatically replace with Object

    • Because Object is the default class
  • The difference is that Java will check data time at compile-time, which is more safe and reliable

After applying Constraints

  • Java will replace with constraints

If there are multiple constrainst

  • Java will replace with the left most constraint

# Comparable Interface

  • We use this interface to compare two objects
  • With this comparison, we can determine what objects should come first
  • Comparable is a generic interface
    • Interface Comparable
  • This interface has a single method called compareTo which takes an object
compareTo(T o)
// compares this object with the specified object fro order 
1
2
// if not write <User>, Intellij will generate compareTo(Object o)
public class User implements Comparable<User> {
  private int points;

  public User(int points) {
    this.points = points;
  }

    // the very important compareTo method
  @Override
  public int compareTo(User other) {
      // this < other  -> -1
      // this == other ->  0
      // this > other  ->  1
    return points - other.points;
  }

  @Override
  public String toString() {
    return "Points=" + points;
  }
}

public class Main {
    public static void main(String[] args) {
		var user1 = new User(10);
        var user2 = new User(20);
        if (user1.compareTo(user2) < 0)
            System.out.println("User 1 < User 2");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# Generic Methods

  • We can declare a generic method inside a non-generic class
public class Utils {
    public static int max(int first, int second) {
        return (first > second) ? first : second;
    }
    
    // becomes 
    
    public static <T extends Comparable<T>> T max(T first, T second) {
    	return (first.compareTo(second) < 0) ? second : first;
  	}
}

public class Main {
    public static void main(String[] args) {
        var max = Utils.max(1, 3);
        var maxClient = Utils.max(new User(10), new User(20));
        System.out.println(maxClient); // in order to print meaningful info, override toString method 
    }
}

public class User implements Comparable<User> {
  @Override
  public String toString() {
    return "Points=" + points;
  }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# Multiple Type Parameters

public void print(int key, int value) {
    System.out.println(key + "=" + value);
} 

// becomes 

public static <K, V> void print(K key, V value) {
    System.out.println(key + "=" + value);
}

public class Main {
    public static void main(String[] args) {
		Utils.print(1, 10);
    }
}

// declare multiple-type parameters 
public class KeyValuePair<K, V> {
  private K key;
  private V value;

  public KeyValuePair(K key, V value) {
    this.key = key;
    this.value = value;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# Generic Classes and Inheritance

// super class
public class User implements Comparable<User> {
  	private int points;

  	public User(int points) {
    	this.points = points;
  	}
}

// sub class 
public class Instructor extends User {
  	public Instructor(int points) {
    	super(points);
  	}
}

public class Main {
    public static void main(String[] args) {
        var users = new GenericList<Instructor>();
        Utils.printUsers(users); // this wrong, remember the bytecode representation of generic class?
        
        
		// this is tedius 
        var instructors = new GenericList<Instructor>();
        var users = new GenericList<User>();
        for (Instructor instructor : instructors)
            users.add(instructor)
        
        Utils.printUsers(users);
    }
}

public class Utils {

  	public static void printUser(User user) {
    	System.out.println(user);
  	}
	// generic class of instructor is not a subtype of user, so need to specify
  	public static void printUsers(GenericList<User> users) {
    	
  	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# Wildecards

  • ? Is the wildcard character
  • It represents an unknown type
public class Utils {
	public static void printUser(User user) {
    	System.out.println(user);
  	}

    // `extends` restrict the type of inputs 
    // if want to read from the list, use the `extends` keyword
  	public static void printUsers(GenericList<? extends User> users) {
    	User x = users.get(0);
  	}
    
    // if you want to add to the list, use the `super` keyword
    public static void printUses(GenericList<? super User> users) {
        GenericList<Object>  temp = new GenericList<>();
        Object x = users.get(0);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上次更新: 2022/12/04, 16:55:22
Exceptions
Collections

← Exceptions Collections→

最近更新
01
day01-Java基础语法
08-31
02
1
08-29
03
路线
08-01
更多文章>
Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×