java泛型使用

Java 泛型

本文是学习过程中一些笔记,如有不对之处欢迎指正

我们在使用Java的时候通常会看到Object、Item等字样,它们通常指我们所说的泛型。它相当于客户端使用的某种具体类型的符号占位符,当我们写一个类的时候可能不确定应用这个类的对象 是什么类型的,这样的话我们就可以使用泛型,然后在应用的时候传入相应的参数即可。
在Java的 Tutorials 用BOX 类定义泛型:

下面是Java 的 Tutorials 里面的讲解:

泛型类型是通过类型参数化的泛型类或接口。将修改以下Box类以演示该概念。
首先检查对任何类型的对象进行操作的非泛型Box类。它只需要提供两个方法:set,它将一个对象添加到框中,get,它将检索它:

public class Box {
    private Object object;

    public void set(Object object) { this.object = object; }
    public Object get() { return object; }
}

由于它的方法接受或返回一个Object,所以你可以自由地传入任何你想要的东西,前提是它不是一种原始类型。在编译时无法验证类的使用方式。代码的一部分可能会在框中放置一个Integer并期望从中获取Integers,而代码的另一部分可能会错误地传入String,从而导致运行时错误。(在这里我们传入的只能是引用类型,而不能是int等八种基本类型)

Box类的通用版本

一个泛型类通常被定义为:

class name<T1, T2, ..., Tn> { /* ... */ }

由尖括号(<>)分隔的类型参数部分跟在类名后面。它指定类型参数(也称为类型变量)T1,T2,…和Tn。要更新Box类以使用泛型,可以通过将代码“public class Box”更改为“public class Box ”来创建泛型类型声明。这样我们就引入了自己定义的类型变量T , 并且可以在类中的任何位置使用。
这样的话Box类的重新定义为:

/**
 * Box 类的通用类型
 * @参数<T>是被封装的类型
 */
public class Box<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

如上所示,所有出现的Object都被T替换。类型变量可以是您指定的任何非基本类型:任何类类型,任何接口类型,任何数组类型,甚至是其他类型变量。
可以应用相同的方法创建通用接口。这样我们在一个方法里面就可以引入自己的类型变量,而在实例化的时候我们将这个变量引入就可以了

键入参数命名约定

按照惯例,类型参数名称是单个大写字母。 这与您已经了解的变量命名约定形成了鲜明的对比,并且有充分的理由:如果没有这种约定,就很难区分类型变量和普通类或接口名称。
常用的参数命名
E - Element (通常用于集合中) K - Key
N - Number T - Type
V - Value S,U,V etc. - 2nd, 3rd, 4th types

调用和实例化泛型类型

要从代码中引用通用Box类,必须执行泛型类型调用,它将T替换为某些具体值,例如Integer。

Box<Integer>  integerBox;

调用的时候可以将泛型类型调用视为与普通方法调用类似,但不是将参数传递给方法,而是将类型参数(在本例中为Integer)传递给Box类本身。 与任何其他变量声明一样,此代码实际上并不创建新的Box对象。 它只是声明integerBox将保存对“Box of Integer”的引用,这就是Box 的读取方式。
泛型类型的调用通常称为参数化类型。
要实例化此类,请像往常一样使用new关键字,但在类名和括号之间放置:`

Box<Integer> integerBox = new Box<Integer>();

在Java SE 7及更高版本中,只要编译器可以从上下文中确定或推断类型参数,就可以用一组空的类型参数(<>)替换调用泛型类的构造函数所需的类型参数, 这对尖括号<>非正式地称为 diamond。 例如,您可以使用以下语句创建Box 的实例:Box<Integer> integerBox = new Box<>();

如前所述,泛型类可以有多个类型参数。 例如,通用的OrderedPair类,它实现了通用的Pair接口:

public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {

    private K key;
    private V value;

    public OrderedPair(K key, V value) {
	this.key = key;
	this.value = value;
    }

    public K getKey()	{ return key; }
    public V getValue() { return value; }
}

以下语句创建OrderedPair类的两个实例:

Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String>  p2 = new OrderedPair<String, String>("hello", "world");

在这里,新的OrderedPair <String,Integer>,将K实例化为String,将V实例化为Integer。 因此,OrderedPair的构造函数的参数类型分别是String和Integer。 由于自动装箱,将String和int传递给类是有效的。
正如The Diamond中所提到的,因为Java编译器可以从声明OrderedPair <String,Integer>推断出K和V类型,所以可以使用<>表示法缩短这些语句:

OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);
OrderedPair<String, String>  p2 = new OrderedPair<>("hello", "world");

参数化类型

还使用参数化类型(即List )替换类型参数(即K或V)。 例如,使用OrderedPair <K,V>示例:

OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));

**

应用

**

以下为为我对泛型的简单应用,在这里我创建了一个顺序表,让它指定类型为E,然后我就可以在类里面定义变量类型为E ,然后我在后面实例化对象的时候给它指定类型,

package sjjg_liuxiaojing_learn;

public class IList<E> {
	private Object[] SqList ;
	private  int curlen ;
	  IList() {
		curlen = 0;
		SqList = null;
	}
	public void add(E i) {
		Object[] newcur = new Object[curlen + 1];
		for(int j = 0;j < curlen;j++) {
			newcur[j] = SqList[j];    //遍历的不是新数组,而是原来的那个旧数组
		}                             //所以才使用curlen作为遍历长度。
		curlen++;
		newcur[curlen - 1] = i;
		SqList = newcur;
	}
	public void clear() {
		curlen = 0;
	}
	public boolean isEmpty() {
		return curlen == 0;
	}
	public int length() {
		return curlen;
	}
	public Object get(int i) throws Exception{ 
		//得到线性表里面位置i的元素
		if(i < 0 || i > curlen - 1)
			throw new Exception("第i个元素不存在");
		return SqList[i];
	}
	public void insert(int i,E x)throws Exception {
		//在线性表里面第i个位置插入元素
		if(i < 0||i > curlen )
			throw new Exception("插入位置不合法");
		Object[] newList = new Object[curlen + 1];
		for(int j = 0;j < curlen + 1;j++) {  //还是遍历数组出现问题
			if(j < i)                //要分清应该遍历那个数组,这个应该是遍历新数组
				newList[j] = SqList[j];    
			else if(j == i)
				newList[j] = x;
			else
				newList[j] = SqList[j - 1];
		}
		curlen++;
		SqList = newList;
	}
	public void remove(int i)throws Exception{
        //删除链表中位置为i的元素		
		if(i < 0||i > curlen -1)
			throw new Exception("删除位置不合法");
		for(int j = i;j<curlen -1;j++)  //遍历的是新的数组
			SqList[j] = SqList[j + 1];
		curlen--;
	}
	public int indexOf(E x) {
		for(int i = 0;i<curlen -1;i++) {
			if(SqList[i] == x)
				return i;			
		}
		return -1;
	}
	public void display(){
		for(int i = 0;i<curlen;i++)  //遍历数组为数组的长度
			System.out.print(SqList[i] + " ");
		System.out.println();
	}
	
	//数据结构课后题1:实现线性表顺序逆置操作
	public void inverse() {
		Object[] newcur = new Object[curlen];
		for(int i = 0,j = curlen - 1;i < j;i++,j--) {   //空间复杂度低
			Object temp = SqList[i];
			SqList[i] = SqList[j];
			SqList[j] = temp;
		}
	}
	public void turnright(int k) {
		Object[] newcur = new Object[curlen];
		
		for(int i= 0;i < curlen;i++) {
			newcur[i] = SqList[i];    //第一次出错为不能直接复制,相当于多加一个标签没什么用
			if(i < k)
				SqList[i] = SqList[curlen - k + i];
			else             //有时候还是要根据整体来列这个式子
				SqList[i] = newcur[i - k];   
		}
	}
}

实例化对象
在这里我实例化对象IList 为L,并且类型设置为Integer ,这样我就可以添加类型为Integer ,并且加入类型为int的时候自动向上转型为Integer

package sjjg_liuxiaojing_learn;

public class IList_shixian {

	public static void main(String[] args)throws Exception {
		// TODO Auto-generated method stub
		IList<Integer> L = new IList<Integer>();
		L.add(3);
		L.add(2);
		L.add(3);
		L.insert(1, 33);
		L.add(4);
		L.add(3);
		for(int i = 0;i<5;i++) {   //insert方法出现错误记得改正
			L.add(i);
		}
		L.remove(0);
		L.display();
		System.out.println(L.length());
		System.out.println(L.isEmpty());
		System.out.println(L.indexOf(5));		
		L.inverse();
		L.display();
		L.turnright(2);
		L.display();
	}
}

在这里插入图片描述如图所示在for循环里插入int类型,自动转换为Integer.

猜你喜欢

转载自blog.csdn.net/weixin_42784951/article/details/84027328