一、泛型及其作用
1.没有泛型的情况下,定义一个数组列表
package main.java.com.shixinke.java.demo.generic;
/**
* 定义一个整型的数组列表
*/
class MyIntList {
private Integer[] elements;
private int size;
public MyIntList(int capacity) {
if (capacity < 1) {
capacity = 1;
}
this.elements = new Integer[capacity];
}
public int size() {
return this.size;
}
public void add(int v) {
if (this.size == this.elements.length) {
ensureCapacity(this.size * 2);
}
this.elements[this.size] = v;
this.size ++;
}
public Integer remove(int i) {
if (i < 0 || i >= this.size) {
return null;
}
Integer v = this.elements[i];
this.size --;
if (i == this.size) {
this.elements[i] = null;
return v;
}
for (int j = i; j< this.size; j++) {
this.elements[j] = this.elements[j+1];
}
this.elements[this.size] = null;
return v;
}
public Integer get(int i) {
if (i < 0 || i >= this.size) {
return null;
}
return this.elements[i];
}
private void ensureCapacity(int capacity) {
if (capacity <= this.elements.length) {
return;
}
Integer[] oldData = this.elements;
this.elements = new Integer[capacity];
for (int i = 0; i< oldData.length; i++) {
this.elements[i] = oldData[i];
}
}
}
/**
* 定义一个字符串型的数组列表
*/
class MyStrList {
private String[] elements;
private int size;
public MyStrList(int capacity) {
if (capacity < 1) {
capacity = 1;
}
this.elements = new String[capacity];
}
public int size() {
return this.size;
}
public void add(String v) {
if (this.size == this.elements.length) {
ensureCapacity(this.size * 2);
}
this.elements[this.size] = v;
this.size ++;
}
public String remove(int i) {
if (i < 0 || i >= this.size) {
return null;
}
String v = this.elements[i];
this.size --;
if (i == this.size) {
this.elements[i] = null;
return v;
}
for (int j = i; j< this.size; j++) {
this.elements[j] = this.elements[j+1];
}
this.elements[this.size] = null;
return v;
}
public String get(int i) {
if (i < 0 || i >= this.size) {
return null;
}
return this.elements[i];
}
private void ensureCapacity(int capacity) {
if (capacity <= this.elements.length) {
return;
}
String[] oldData = this.elements;
this.elements = new String[capacity];
for (int i = 0; i< oldData.length; i++) {
this.elements[i] = oldData[i];
}
}
}
public class ListDemo {
public static void main(String[] args) {
MyIntList list1 = new MyIntList(5);
list1.add(5);
list1.add(8);
for (int i = 0; i< list1.size(); i++) {
System.out.println(list1.get(i));
}
MyStrList list2 = new MyStrList(5);
list2.add("h");
list2.add("e");
for (int i = 0; i< list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
- 上例可以看到一个数组列表,因为其数组元素数据类型不同,得定义两个结构非常雷同的代码
2.泛型
- 泛型是将数据类型进行抽象,提高代码复用性而产生的
通过泛型,我们来将上面的二个类合二为一:
class MyList<T> {
private T[] elements;
private int size;
public MyList(int capacity) {
if (capacity < 1) {
capacity = 1;
}
this.elements = (T[])new Object[capacity];
}
public int size() {
return this.size;
}
public void add(T v) {
if (this.size == this.elements.length) {
ensureCapacity(this.size * 2);
}
this.elements[this.size] = v;
this.size ++;
}
public T remove(int i) {
if (i < 0 || i >= this.size) {
return null;
}
T v = (T)this.elements[i];
this.size --;
if (i == this.size) {
this.elements[i] = null;
return v;
}
for (int j = i; j< this.size; j++) {
this.elements[j] = this.elements[j+1];
}
this.elements[this.size] = null;
return v;
}
public T get(int i) {
if (i < 0 || i >= this.size) {
return null;
}
return (T)this.elements[i];
}
private void ensureCapacity(int capacity) {
if (capacity <= this.elements.length) {
return;
}
T[] oldData = this.elements;
this.elements = (T[])new Object[capacity];
for (int i = 0; i< oldData.length; i++) {
this.elements[i] = oldData[i];
}
}
}
二、泛型的基本使用
1.泛型类
- 在定义类的时候,在类名后面加上类似于
的标识
/**
* 响应类
*/
class Response<T> {
private int code;
private String message;
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
注:因为我们的每个接口响应的数据一般不一样,所以用泛型来代替,根据具体的返回对象进行实例化半设置返回数据的类型即可
2.泛型接口
- 与定义普通的接口相比,只是在接口名称后面加上了一个类型于
这样的泛型
interface Sortable<T> {
T sort(T obj);
}
注:因为排序接口,是一个通用的接口定义,具体的可能是数字排序,也可能是字符串排序等
3.泛型方法
- 泛型方法可以在泛型类中使用,也可以不在泛型类中使用
- 它是在方法的返回类型前面添加一个泛型标识
class Cache {
/**
* 在返回类型List<T>前面有一个<T>这样的泛型标识
*/
public <T> List<T> mget(List<String> keys) {
return new ArrayList<>();
}
}
注:类不是泛型类,但可以定义泛型方法
4.泛型类型变量的限定
- 通过
:限制T必须是继承自Number类型
class Point<T extends Number> {
private T x;
private T y;
public Point (T x, T y) {
this.x = x;
this.y = y;
}
}
public class InterfaceDemo {
public static void main(String[] args) {
//可以使用Integer型或Double类型,因为它们都是Number的子类
Point<Integer> p = new Point<Integer>(10, 20);
Point<Double> p2 = new Point<Double>(10.1, 20.1);
//而使用String却不可以,因为String不是Number的子类
//Point<String> p3 = new Point<String>("1", "2");
}
}
三、泛型的高级使用
1.通配符
- 通过<? extends List>:限制通配符类型必须继承自List
- 通过<? super Collection>:限制通配符类型只要是Collection的子类即可
- 无限制通配符?
class Point<T> {
private T x;
private T y;
public Point (T x, T y) {
this.x = x;
this.y = y;
}
}
class Comparator {
/**
* 参数p1和p2必须继承自Number
*/
public static void compare(Point<? extends Number> p1, Point<? extends Number> p2) {
}
/**
* 参数p1和p2只要是Collection的子类即可
*/
public static void compareTo(Point<? super Collection> p1, Point<? super Collection> p2) {
}
}
public class GenericDemo {
public static void main(String[] args) {
Comparator.compare(new Point(12, 13), new Point(13.5, 14.5));
Comparator.compareTo(new Point(new ArrayList(), new ArrayList()), new Point(new ArrayList(), new ArrayList()));
}
}