一、objectives(学习目标)
1.To describe the benefits of generics.
Generic type enable you to detect errors at complie rather then at runtime.
自动装箱自动拆箱(autoboxing , autounboxing)
自动装箱就是基本类型(primitive type)直接包装为包装类类型。
如:int ——> integer
ArrayList<Integer> list = new ArrayList<>(); list.add(5);//这就是自动装箱 5 是基本类型 而 泛型约束的是Integer
自动拆箱就是包装类类型赋值给基本类型变量时不需要 强制转换。
如:integer——> int
Arraylist<Double> list = new ArrayList<>(); list.add(5.5); double element = list.get(0);//这就是自动拆箱。约束类型为Double 不需要强制转换就可以直接赋值给基本类型double 变量
2.To use generic classes and interfaces.
java jdk中ArrayList类就是一个泛型类、Comparable接口 是泛型接口。
3.To define generic classes and interfaces.
//泛型类
class ClassName <T>{//这个T就是一个形式化的反省代表,之后可以被实际类型代替
}
//泛型接口
interface InterfaceName <T>{//这个T就是一个形式化的反省代表,之后可以被实际类型代替
}
define GenericStack class
package javaLanguage;
import java.util.ArrayList;
/**
* 泛型类
* @param <T>
*/
public class GenericStack<T> {
public GenericStack() {
}
public GenericStack(ArrayList<T> list) {
this.list = list;
}
//用ArrayList存储数据
private ArrayList<T> list = new ArrayList<>();
//栈的当前容量
public int getSize(){
return list.size();
}
//入栈
public void push(T o){
list.add(o);
}
//出栈
public T pop(){
T o = list.get(getSize() - 1);
list.remove(getSize() -1);
return o;
}
//查看栈顶元素
public T peek(){
return list.get(getSize() - 1);
}
//判断栈是否为空
public boolean isEmpty(){
if (getSize() == 0){
return true;
}
else {
return false;
}
}
/**
* 在main方法中测试GenericStack class
* @param args
*/
public static void main(String[] args) {
GenericStack<String> stack1 = new GenericStack<>();//stack1 can only store strings type.
GenericStack<Integer> stack2 = new GenericStack<>();//stack2 can only store integer type.
stack1.push("heihei");
stack1.push("haha");
stack1.push("上了生活的贼船,就要做个快乐的海盗!");
System.out.println(stack1.peek());
stack2.push(1);//自动装箱
int pop = stack2.pop();//自动拆箱
System.out.println(pop);
}
}
需要注意的地方构造方法以前是怎样写还是怎样写。 下面这样是错的
public GenericStack<E>()
注意: 泛型类当有多个参数时,这样写<T1,T2,T3>
4.To explain why generic types can improve readability and reliability.
因为泛型能在编译时就检测出错误。
如:
4.To define and use generic method and bounded generic types.
generic method
package javaLanguage.generic;
import java.util.Arrays;
public class GenericMethodDemo {
public static void main(String[] args) {
String[] strings = {"heihei","haha"};
Integer[] integers = {1,2};
print(strings);
print(integers);
}
/**
* 泛型方法 ,静态方法
* @param list
* @param <T>
*/
public static <T> void print(T[] list){
System.out.println(Arrays.toString(list));
}
}
bounded generic method
//An unbounded generic type <E> is the same as <E extends Object>.
You must invoke equalArea by passing two instances of GeometricObject
package javaLanguage.generic;
public class BoundedTypeDemo {
public static void main(String[] args) {
}
/**
* 受约束的泛型方法
* You must invoke equalArea by passing two instances of GeometricObject.
* @param o1
* @param o2
* @param <E>
* @return
*/
//An unbounded generic type <E> is the same as <E extends Object>.
public static <E extends GeometricObject> boolean equalArea(E o1,E o2){
return o1.getArea() == o2.getArea();
}
}
//这个类就是个辅助,不用细看
abstract class GeometricObject {
private String color = "white";
private boolean filled;
private java.util.Date dateCreated;
/**
* Construct a default geometric object
*/
protected GeometricObject() {
dateCreated = new java.util.Date();
}
/**
* Construct a geometric object with color and filled value
*/
protected GeometricObject(String color, boolean filled) {
dateCreated = new java.util.Date();
this.color = color;
this.filled = filled;
}
/**
* Return color
*/
public String getColor() {
return color;
}
/**
* Set a new color
*/
public void setColor(String color) {
this.color = color;
}
/**
* Return filled. Since filled is boolean, * the get method is named isFilled
*/
public boolean isFilled() {
return filled;
}
/**
* Set a new filled
*/
public void setFilled(boolean filled) {
this.filled = filled;
}
/**
* Get dateCreated
*/
public java.util.Date getDateCreated() {
return dateCreated;
}
@Override
public String toString() {
return "created on " + dateCreated + "\ncolor: " + color + " and filled: " + filled;
}
/**
* Abstract method getArea
*/
public abstract double getArea();
/**
* Abstract method getPerimeter
*/
public abstract double getPerimeter();
}
5.To devolop a generic method for sort an array of Comparable objects.
方法中使用的排序时选择排序
package javaLanguage.generic;
public class GenericSort {
public static void main(String[] args) {
// Create an Integer array
Integer[] intArray = {new Integer(2), new Integer(4), new Integer(3)};
// Create a Double array
Double[] doubleArray = {new Double(3.4), new Double(1.3), new Double(-22.1)};
// Create a Character array
Character[] charArray = {new Character('a'), new Character('J'), new Character('r')};
// Create a String array
String[] stringArray = {"Tom", "Susan", "Kim"}; // Sort the arrays
//下面三行不行
// int[] arr = {new Integer(3)};
// int[] array = {1,2,3}
// sort(arr);
sort(intArray);
sort(doubleArray);
sort(charArray);
sort(stringArray);
// Display the sorted arrays
System.out.print("Sorted Integer objects: ");
printList(intArray);
System.out.print("Sorted Double objects: ");
printList(doubleArray);
System.out.print("Sorted Character objects: ");
printList(charArray);
System.out.print("Sorted String objects: ");
printList(stringArray);
}
public static <E extends Comparable<E>> void sort(E[] list) {
E currentMin;
int currentMinIndex;
for (int i = 0; i < list.length - 1; i++) {
currentMin = list[i];
currentMinIndex = i;
// Find the minimum in the list[i+1..list.length-2] currentMin = list[i];
for (int j = i + 1; j < list.length; j++) {
if (currentMin.compareTo(list[j]) > 0) {
currentMin = list[j];
currentMinIndex = j;
}
}
// Swap list[i] with list[currentMinIndex] if necessary;
if (currentMinIndex != i) {
list[currentMinIndex] = list[i];
list[i] = currentMin;
}
}
}
/**
* Print an array of objects
*/
public static void printList(Object[] list) {
for (int i = 0; i < list.length; i++) System.out.print(list[i] + " ");
System.out.println();
}
}
6.To use raw type for backward compatibility.
用原始类型向后兼容,因为早期的java版本(jdk1.5之前)是没有泛型的,新的Java版本出来了要兼容以前的代码,所以有raw type.
何为原始类型:
比如Arraylist类是一个泛型类,然而在创建对象的时候不特别指定类型,像这样Arraylist list = new Arraylist(); 没有用尖括号指出具体的类型,这就是raw type (原始类型)。
原始类型是unsafe,请看下面的图片。
7.泛型通配符(wildcard)
问题: To explain why wildcard generic type is necessary? 因为它可以给泛型指定一个范围 通配符有三种类型: ? AND ? extends T AND ? super T
第一种就相当于 ? extends Object
第二种约束是T 或T的子类
第三种约束也是T 或T的子类
例子1: 通配符 ?(不受限通配符)
package javaLanguage.generic;
public class AnyWildcardDemo {
public static void main(String[] args) {
GenericStack<Integer> integerGenericStack = new GenericStack<>();//这里Integer是 Object类的子类
integerGenericStack.push(1);
integerGenericStack.push(2);
integerGenericStack.push(3);
print(integerGenericStack);
}
public static void print(GenericStack<?> stack){//这里通配符用的是 ? ,意味着泛型尖括号里只要是Object类的子类或本身都可以使用
if (!stack.isEmpty()){
System.out.println(stack.peek());
}
}
}
例子2:? extends T (受限通配符)
例子3:? super T (下限通配符)
这个的关键就是你要确定好 T 必须是父类,要不然就可能出现下面这个错误。
8.泛型的消除和限制
消除:
泛型只是存在于编译阶段,运行阶段就消失了,这是为了向后兼容,兼容以前的java版本。
限制:
1.不能创建泛型对象 如: new T(); 2.不能 new T[ ] , 这样不能 E[] elements = new E[capacity]; 但是可以规避可以这样E[] elements = (E[])new Object[capacity]; 不过或许会出现异常,如T是String 而 创建的是Object类的实例,会出现ClassCastException 3.泛型类中不能出现静态字段和静态方法等,因为泛型类可以有不同类型的对象,但是静态数据是被公用的,有多个不同类型的对象时,使用这个静态数据到底是听谁的,对吧,所以不能使用。 想要使用静态方法,就必须把方法写成静态泛型方法。在static关键字后写上 泛型