Java——泛型
泛型,听起来比较抽象,但是确实很好用,其实理解也比较容易,就是使用<E>来确定集合中的元素类型
泛型的两大功能:
①解决使用Java集合存储对象的安全问题
②解决从Java集合中取出存储对象时可能引发的强制转换问题
不使用泛型的Java集合可以添加任何类型的元素,这样在遍历的时候就比较容易出现类型转换错误
1、在java集合中使用泛型:
//List+泛型限定元素类型只能为String
List<String> list_string = new ArrayList<String>();//后一个String可以省略
list_string.add("Hello");
list_string.add("Tom");
// list_string.add(12); //会报错,因为12不是String类型的
//使用泛型的List遍历
Iterator<String> i_list = list_string.iterator();
while(i_list.hasNext()){
System.out.print(i_list.next()+"\t");
}
System.out.println();
//Map+泛型限定key和value的类型
Map<String, Integer> map = new HashMap<>();
map.put("Tom", 12);
map.put("Jerry", 12);
// map.put(12, "Tom"); //会报错,因为类型不对
//使用泛型的Map遍历
Set<String> key_set = map.keySet(); //获得Map的key集合
Collection<Integer> val_col = map.values(); //获得Map的value集合
Set<Map.Entry<String, Integer>> entries = map.entrySet(); //获得Map的元素集合
Iterator<Map.Entry<String, Integer>> i_map = entries.iterator();
while (i_map.hasNext()){
System.out.print(i_map.next()+"\t");
}
2、实现自定义泛型类:
/**
*
* @author KeXin
* 自定义泛型类,适合用来创建一个较为通用的类、接口、方法
* 在同一个类中,所有的T都是同一类型,有点像C++中的模板类
* @param <T>
*/
class TestMyGenericity<T,G>{
private String name;
private int age;
private T t;
private List<T> list;
public TestMyGenericity(String name, int age,T t) {
super();
this.name = name;
this.age = age;
this.t = t;
}
//定义一个测试方法
public void show(){
list = new ArrayList<>();
list.add(t);
System.out.println(list);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((t == null) ? 0 : t.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestMyGenericity other = (TestMyGenericity) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (t == null) {
if (other.t != null)
return false;
} else if (!t.equals(other.t))
return false;
return true;
}
@Override
public String toString() {
return "TestMyGenericity [name=" + name + ", age=" + age + ", t=" + t + "]";
}
}
自定义泛型类跟java自带的泛型类一样,当新建一个类对象的时候才会将泛型确定为哪一个类型,如果没有指明就默认为Object,同样可以创建泛型方法、泛型接口,但是
不能在static、catch中使用
/*
* 自定义一个泛型方法,实现数组到List的转换,可以到真正调用这个方法的时候确定泛型类型
*/
public <E> List<E> array2list(E[] e,List<E> list){
for(int i = 0;i<e.length;i++){
list.add(e[i]);
}
return list;
}
3、通配符?:
在Java中有一个通配符“ ?”,它相当于所有具体泛型类型的父类,除了null不能添加任何新元素,但是可以遍历。用个程序说明它的地位:
List<?> list1 = null;
List<Object> list2 = new ArrayList<>();
List<String> list3 = new ArrayList<>();
list1 = list2;
list1 = list3;
// list2 = list3; //报错,因为List<String>不是List<Object>的子类,二者都是List<?>的子类
list3.add("HELLO");
list3.add("Tom");
list1 = list3;
for (int i = 0;i<list1.size();i++){
System.out.println(list1.get(i));
}
// list1.add("hello"); //报错,因为?不等于任何类型
4、例题
package com.kexin.day1;
import org.junit.Test;
public class Demo6 {
/*
* 使用泛型编写一个方法,交换数组中指定位置的元素
*/
public static <T> T[] SwapT(T[] arr, int i, int j) {
if (i >= 0 && i >= 0 && i < arr.length && j < arr.length) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
return arr;
}
/*
* 使用泛型编写一个方法,实现数组中元素的转置
*/
public static <T> T[] TraverT(T[] arr) {
int len = arr.length;
for (int i = 0; i < len / 2; i++) {
arr = SwapT(arr, i, len - 1 - i);
}
return arr;
}
@Test
public void test() {
Integer[] arr = { 1, 2, 3, 4 };//这里需要用基本数据对象,int不可以
arr = SwapT(arr, 0, 2);
for (int i : arr) {
System.out.print(i + "\t");
}
System.out.println();
arr = TraverT(arr);
for (int i : arr) {
System.out.print(i + "\t");
}
}
}