java 基础——泛型

泛型

我们先来看一下代码,这是一个用泛型实现的栈,下面的 T 就是代表了这是个泛型,它是一个占位符,可以指定任何类型。

我们先看一下泛型有什么优点。比如我们要写一个栈,一般来说,栈的存储类型是固定了的,当我们需要存储其他类型的元素时,我们只能修改代码,但是使用泛型我们完全不用考虑这点,因为用泛型写的栈存储的元素随着我们传入的参数不同而不同。

class GenericStack<T>{
	private T[] elem;//声明一个 T 类型的数组,但是 T 现在不确定
	private int top;
	public GenericStack() {
		this(10);
	}
	public GenericStack(int size) {
		this.elem = (T[])new Object[size];
		this.top = 0;
	}
	
	public void push(T val){
		this.elem[this.top++] = val;
	}
	public void pop(){
		--this.top;
	}
	public T getTop(){
		return this.elem[this.top-1];
	}
}
public static void main(String[] args) {
	GenericStack<Integer> stack = new GenericStack<Integer>();
	stack.push(10);
	stack.push(20);
	stack.push(200);
	
	int a = stack.getTop();
	System.out.println(a);
}

输出结果是 200

泛型的意义

  • 对类型进行自动检查
  • 对类型进行自动转换

泛型的坑

  • 不能 new 泛型类型的数组。
  • 不能 new 泛型类型的对象。
  • 不能得到泛型类型的对象数组。
  • 简单类型不能作为泛型类型的参数。


泛型是如何编译的

泛型在编译期间通过它的类型擦除机制生成一个 Object 对象。以为就是说泛型的参数类型在编译期间被编译器擦除了,在运行期间 JVM 得到的是一个 Object 对象。类型擦除机制是向上擦除的,也就是往基类方向擦除。

泛型的类型擦除机制

泛型的上界

因为泛型的类型擦除机制,最后在运行期间我们得到的是一个 Object 类型的值,在有的情况下不是很方便,所以我们需要指定一下我们类型擦除机制向上擦除到什么地方位置,这就引出了泛型的上界。

class GenericAlg<T extends Comparable<T>>{
	public T findMaxVal(T[] array){
		T maxVal =array[0];
		for(int i = 1;i < array.length;i++){
			if(maxVal.compareTo(array[i]) < 0){
				maxVal = array[i];
			}
		}
		return maxVal;
	}
public static void main(String[] args) {
	Integer[] array = {10,20,30};
	GenericAlg<Integer> g1 = new GenericAlg<Integer>();
	System.out.println(g1.findMaxVal(array));
    }
}

输出结果:30

在这个例子中我们指出了上界为 Comparable,所以我们可以直接调用它里面的方法。

泛型方法

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;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		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;
	}	
}
class Gnericl{
	/**
	 * 
	 * @param array
	 * @return
	 * 泛型方法
	 */
	public static<T extends Comparable> T fingMaxVal(T[] array){
		T maxVal =array[0];
		for(int i = 1;i < array.length;i++){
			if(maxVal .compareTo(array[i]) < 0){
				maxVal = array[i];
			}
		}
		return maxVal;
	}
public static void main2(String[] args) {
		Usr[] usr = new Usr[3];//定义一个 Usr 类型的数组
		usr[0] = new Usr("洁1","男",17);
		usr[1] = new Usr("洁3","男",19);
		usr[2] = new Usr("洁2","男",21);
		System.out.println();		
		System.out.println(Gnericl.findMaxVal(usr));
	}
}

内存泄漏

看下面的代码,我们创建了三个对象放入栈里,然后又出栈了一个元素,所以应该是两个对象,但经过测试,我们应该得到了三个对象,这就是内存的

public static void main(String[] args) {
		GenericStack<Animal3> s = new GenericStack();
		s.push(new Animal3());
		s.push(new Animal3());
		s.push(new Animal3());
		s.pop();
		System.gc();//测试内存泄漏
	}

现在我们给出战的方法里将即将出栈的元素置为 null ,从结果来看我们成功的防止了内存的泄漏。

public void pop(){
		this.elem[top-1] = null;
		--this.top;
	}


通配符

  • 表示当前类型可以是任何类型。
  • 它也会进行类型擦除的   擦除到Object.

通配符分类

无界通配:?

通配符的上界:? extends Object

通配符的下界:? super Integer

猜你喜欢

转载自blog.csdn.net/alyson_jm/article/details/80529730