一.通用栈
栈的特点:
先进后出
所有类的基类是Object,所以如果我们呢想要写一个通用栈的话,就可以写成Object类的通用栈
写一个简单的入栈出栈的操作:
/**
* 通用栈 Object
* @author wangyu
* @data 2018年5月31日
*/
class ObjectStack {
private Object[] elem;
private int top;
public ObjectStack() {
this(10);
}
public ObjectStack(int size) {
this.elem = new Object[size];
this.top = 0;
}
public void push(Object val) {
this.elem[this.top++] = val;
}
public void pop() {
--this.top;
}
public Object getTop() {
return this.top - 1;
}
}
public class TestDemo1 {
public static void main(String[] args) {
ObjectStack s1 = new ObjectStack(10);
s1.push(10);
s1.push(20);
s1.push("hello");
s1.push(20.6);
//出栈的时候,需要强转,入栈的时候无影响
double data = (double)s1.getTop();
}
}
s1.push(10);采用了自动装箱的原理,使用了valueOf的方法(源码)
我们直到栈顶的元素是20.6,也就double类型
所以出栈的时候必须对此出栈的数据进行强转的操作,否则编译器不识别会报错
但是入栈的时候是没有影响的
二.泛型
泛型的意义:
1.会对类型进行自动检查
2.会进行自动类型转换
如上的通用栈,我们出栈的时候需要进行强转才可以,但是我们这里如果改为泛型的话
泛型会对类型进行自动检查
所以先用泛型来实现栈的话:
/**
* 用泛型实现栈
* @author wangyu
* @data 2018年5月31日
*/
class GenericStack<T> {
private T[] elem;
private int top;
public GenericStack() {
this(10);
}
public GenericStack(int size) {
//this.elem = new T[size];
this.elem = (T[])new Object[size];
this.top = 0;
}
public void push(T val) {
this.elem[this.top++] = val;
}
public void pop() {
this.elem[this.top - 1] = null;
--this.top;
}
public T getTop() {
return this.elem[this.top - 1];
}
}
public class TestDemo2 {
public static void main(String[] args) {
GenericStack<Animal> s1 = new GenericStack<Animal> ();
GenericStack<Integer> s1 = new GenericStack<Integer> ();
s1.push(10);
s1.push(20);
s1.push(30);
s1.pop();
int val = s1.getTop();
}
}
如果我们测试类中输入
s1.push(“hello”);
会发现有报错
是因为泛型会对类型进行自动检查
只能是Integer类型的
int val = s1.getTop();
发现不报错,不需要强转
是因为会进行一次自动类型转换
这是通用栈和泛型栈的区别,且是泛型的意义的举例
三.Java中泛型是如何编译的?
方法:类型的擦除
擦除成Object类型,注意是类型检查(不是替换)
擦除方向是向上擦除,往基类(Object)方向进行擦除
也就是类型擦除的机制
此时要引入泛型的上界:
如果某一上界的话,那么我们就那些擦除的时候会直接擦除到Object
但是查看源码发现Object没有某些方法,如compareTo方法
擦除过了
此时如果需要用泛型来编写某些方法时,用到这些方法的话,会无法实现
就需要引入一个上界,来限定一下
/**
* 泛型的上界
* 找出数组当中的最小值
* 泛型没有下界
* @author wangyu
* @data 2018年5月31日
*/
class GenericAlg<T extends Comparable<T>> {
public T findMinVal(T[] array) {
T minVal = array[0];
for(int i = 0;i < array.length;i++) {
if(minVal.compareTo(array[i]) > 0) {
minVal = array[i];
}
}
return minVal;
}
}
class GenericAlg2 {
/**
* 泛型方法
* @param array
* @return
*/
public static<T extends Comparable <T>> T findMinVal(T[] array) {
T minVal = array[0];
for(int i = 0;i < array.length;i++) {
if(minVal.compareTo(array[i]) > 0) {
minVal = array[i];
}
}
return minVal;
}
}
class Usr implements Comparable<Usr>{
private String name;
private String sex;
private int age;
public Usr (String name,String sex,int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return "Usr [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
@Override
public int compareTo(Usr o) {
return age > o.age ? 1 : ((age == o.age) ? 0 : -1) ;
}
}
public class TestDemo3 {
public static void main(String[] args) {
Usr[] usr = new Usr[3];
usr[0] = new Usr("liubei","man",18);
usr[1] = new Usr("caocao","man",28);
usr[2] = new Usr("li","man",38);
GenericAlg<Usr> g2 = new GenericAlg<Usr>();
System.out.println(g2.findMinVal(usr));
System.out.println(GenericAlg2.findMinVal(usr));
}
}
这里是将上界设定为有Comparable接口的地方
因为Object是不能实现compareTo方法的
但是我们比较年龄的时候需要引入compareTo方法的
此时如果向上擦除到Object就过了,无法实现
所以我们需要设定上界到Comparable接口,然后重写compareTo方法来实现比较年龄的大小
泛型没有下界,只会向基类方向擦除
四.泛型中常见的坑有哪些?
1.能不能new泛型类型的数组?
this.elem = new T[size];这种方法是错误的写法
也就是泛型是不能new泛型类型的数组
this.elem = (T[])new Object[size]; 需要强转(有警告)
2.能不能new 泛型类型的对象 ?
例如: T obj = new T();
这种写法是错误的
必须有尖括号,指定此时泛型的类型,不然无法检查,违背了泛型的意义
3.能不能得到泛型类型的对象数组?
例如:
GenericStack<Integer>[] s3 = new GenericStack<Integer>[10];
这样的写法也是错误的,会报错
如果有人说写成如下:
Object obj = new GenericStack<Integer>[10];
假设是成立的,这样的话,会造成我们传参数的时候又回去了Object通用类型,就又需要出栈强转等,白费功夫,违背了泛型的意义
4.简单类型不能作为泛型的参数
例如:
GenericStack<int> s4 = new GenericStack<int>();
int没有基类,擦除机制是向基类擦除,所以说简单类型都不能作为泛型的参数
5.static方法当中不能用泛型类型的参数
因为static定义的方法数据 不依赖于对象 无法指定当前泛型的类型
如上GenericAlg2中的寻找最小值的方法中
采用的是静态方法,但是这里我们指定了类型
如果不指定的话:
如:
public static T findMaxVal(T[] array){
}
会报错
需要进行指定:
public static<T> T findMaxVal(T[] array) {
}