一、利用Object写的堆栈实例
public class CommonStack {
private static final int DEFAULT_SIZE = 16;
//用来存储的数组
private Object[] objects = new Object[DEFAULT_SIZE];
//当前存储的位置
private int count = 0;
public void put(Object obj){
//首先判断是否数组满了,如果满了扩充数组
expandArray();
objects[count] = obj;
++count;
}
private void expandArray(){
if(count == objects.length){
//扩充容量
objects = Arrays.copyOf(objects, 2*count);
}
}
public Object pop(){
//首先判断是否数组为空
if (!isEmpty()){
Object obj = objects[count];
--count;<pre name="code" class="java"><span> </span>objects[count] = null;
return obj;}return null;}private boolean isEmpty(){if (count == 0){return true;}else {return false;}}}
二、将Object栈全部改为用泛型实现栈
public class GenericsStack<E> {
private static final int DEFAULT_SIZE = 16;
//该行出现了错误,无法创建泛型数组
private E[] objects = new E[DEFAULT_SIZE];
private int count = 0;
public void put(E obj){
expandArray();
objects[count] = obj;
++count;
}
private void expandArray(){
if(count == objects.length){
//扩充容量
objects = Arrays.copyOf(objects, 2*count);
}
}
public E pop(){
//首先判断是否数组为空
if (!isEmpty()){
E obj = objects[count];
--count;
<span style="white-space:pre"> </span>objects[count] = null;
return obj;
}
return null;
}
private boolean isEmpty(){
if (count == 0){
return true;
}
else {
return false;
}
}
}
解决方案
第一种:用泛型进行转型
@SuppressWarnings("unchecked")
private E[] objects = (E[])new Object[DEFAULT_SIZE];
第二种方法:将数据存出到Object数组中,然后在从Object数组中拿出来,再转型为E类型。
private Object[] objects = new Object[DEFAULT_SIZE];
public E pop(){
//首先判断是否数组为空
if (!isEmpty()){
@SuppressWarnings("unchecked")
E obj = (E)objects[count];
--count;
return obj;
}
return null;
}
推荐使用第二种方法:原因,禁止数组的警告比禁止对象的强制转换的警告还要危险。
三、有限类型参数与无限类型参数
无限类型参数:泛型的参数类型能够接收任何值
public class GenericsStack<E> 就是无限类型参数。
所以可以 new GenericsStack<String>()、new GenericsStack<Number>();
有限类型参数:
public class GenericsStack<E extends Number> 就表示优先类型参数。
该类只能接收Number或者Number的子类。
所以 new GenericsStack<String>()是会报错的。
有限类型参数的原理及应用:
我们知道泛型会在编译期间擦除参数类型,但是擦除是有边界的。虚拟机会将类型参数擦除到其的边界。
比如说:
public class GenericsStack<E>这个类,我们知道所有的类都继承了Object这个类,所以虚拟机可以确定E这个类一定是Object的子类,那么虚拟机将会将其擦除到其边界,也就是Object类。
public class GenericsStack<E>这个类,我们知道所有的类都继承了Object这个类,所以虚拟机可以确定E这个类一定是Object的子类,那么虚拟机将会将其擦除到其边界,也就是Object类。
我们可以设定这个边界,告诉虚拟机,我输入的类型参数都是在这个边界内的。就可以这样
public class GenericsStack<E extends Number> 说明:输入的参数,都必须是Number的子类。那么虚拟机就会将该参数擦除到Number类。
那么这样的好处是什么呢?
①、限定可作为类型参数的类
②、既然都知道了其边界是Number,那么就表示调用Number类下的所有方法都是安全的。
就能这样:(额。。。这个例子不太好,因为是错误,但是原理是这样的)
public class LimitGenerics <E extends Number>{
public void getData(E data){
byte myBytes = data.byteValue();//可直接调用Number类下的方法
}
}
private boolean isEmpty(){
private boolean isEmpty(){
private boolean isEmpty(){