目录
- 泛型
- 一、使用泛型的好处
- 二、自定义泛型
- 1、泛型字母
- 2、泛型类
- 3、泛型接口
- 4、泛型方法
- 5、泛型的继承
- 三、泛型的通配符
- 四、extends/super
- 1、上限(extends)
- 2、下限(super)
- 五、泛型嵌套
- 六、其他
泛型
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后再使用/调用的时候传入具体的类型(类型实参)
一、使用泛型的好处
- 使用泛型时,在实际使用之前类型就已经确定了,不需要强制类型转换。
- 把运行期异常,提升到了编译期。
// 不使用泛型,存取数据麻烦
public static void test1(){
List list = new ArrayList();
list.add(100);
list.add("zhang");
/*
* 从集合中获取的数据是Object类型,Object类型是所有类型的根类,但是在具体使用的时候需要
* 类型检查,类型转化,处理类型转化异常
* 使用麻烦
*/
Object o = list.get(1);
if (o instanceof String) {
String s = (String)o;
}
System.out.println(o);
}
// 使用泛型
public static void test2(){
List<String> list = new ArrayList<String>();
//list.add(100); 放数据时安全检查,100不是String类型,不能存放
list.add("存数据安全,取数据省心");
String s = list.get(0); //取出来的数据直接就是泛型规定的类型
System.out.println(s);
}
注意:泛型
只在编译器有效,在编译过程中,正确检验泛型
结果之后,会将泛型
的相关信息擦除,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说泛型
信息不会进入到运行时阶段。泛型类型在逻辑上可以看成是多个不同的类型,实际上都是相同的基本类型。
二、自定义泛型
1、泛型字母
- 形式类型参数(
formal type paramaters
)即泛型字母 - 命名泛型字母可以随意指定,尽量使用单个的大写字母(有时候多个泛型类型时会加上数字,比如T1,T2)
- 当类被使用时,会使用具体的数据类型参数(
actual type argument
)代替 - 常见字母(见名知意)
T Type
K V Key Value
E Element
2、泛型类
注意:泛型不能使用在静态属性上。
/**
* 自定义泛型类
*
* 定义"模版"的时候,泛型用泛型字母:T 代替
* 在使用的时候指定实际类型
*
* @author Administrator
* @param <T>
*/
public class Student<T> {
private T javase;
//private static T javaee; // 泛型不能使用在静态属性上
public Student() {
}
public Student(T javase) {
this();
this.javase = javase;
}
public T getJavase() {
return javase;
}
public void setJavase(T javase) {
this.javase = javase;
}
}
/**
* 自定义泛型的使用
* 在声明时指定具体的类型
* 不能为基本类型
* @author Administrator
*
*/
class Demo02 {
public static void main(String[] args) {
//Student<int> Student = new Student<int>(); //不能为基本类型,编译时异常
Student<Integer> student = new Student<Integer>();
student.setJavase(85);
System.out.println(student.getJavase());
}
}
3、泛型接口
/**
* 自定义泛型接口
*
* 接口中泛型字母只能使用在方法中,不能使用在全局常量中
*
* @author Administrator
* @param <T>
*/
public interface Comparator<T1,T2> {
//public static final T1 MAX_VALUE = 100; //接口中泛型字母不能使用在全局常量中
//T1 MAX_VALUE;
public static final int MAX_VALUE = 100;
void compare(T2 t);
T2 compare();
public abstract T1 compare2(T2 t);
}
4、泛型方法
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
/**
* 非泛型类中定义泛型方法
* @author Administrator
*
*/
public class Method {
// 泛型方法,在返回类型前面使用泛型字母
public static <T> void test1(T t){
System.out.println(t);
}
// T 只能是list 或者list 的子类
public static <T extends List> void test2(T t){
t.add("aa");
}
// T... 可变参数 ---> T[]
public static <T extends Closeable> void test3(T...a) {
for (T temp : a) {
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws FileNotFoundException {
test1("java 是门好语言");
test3(new FileInputStream("a.txt"));
}
}
5、泛型的继承
/**
* 泛型继承
*
* 保留父类泛型 ----》泛型子类
* 不保留父类泛型 -----》子类按需实现
*
* 子类重写父类的方法,泛型类型随父类而定 子类使用父类的属性,该属性类型随父类定义的泛型
*
* @author Administrator
*
* @param <T1>
* @param <T2>
*/
public abstract class Father<T1, T2> {
T1 age;
public abstract void test(T2 name);
}
// 保留父类泛型 ----》泛型子类
// 1)全部保留
class C1<T1, T2> extends Father<T1, T2> {
@Override
public void test(T2 name) {
}
}
// 2) 部分保留
class C2<T1> extends Father<T1, Integer> {
@Override
public void test(Integer name) {
}
}
// 不保留父类泛型 -----》子类按需实现
// 1)具体类型
class C3 extends Father<String, Integer> {
@Override
public void test(Integer name) {
}
}
// 2)没有具体类型
// 泛型擦除:实现或继承父类的子类,没有指定类型,类似于Object
class C4 extends Father {
@Override
public void test(Object name) {
}
}
/**
* 泛型擦除
* 类似于Object,不等于Object
* @author Administrator
*
*/
public class Demo03 {
public static void test(Student<Integer> student){
student.setJavase(100);
}
public static void main(String[] args) {
// 泛型擦除
Student student = new Student();
test(student);
Student<Object> student2 = new Student<Object>();
//test(student2); //编译异常
}
}
三、泛型的通配符
-
T K V E
等泛型字母为有类型,类型参数赋予具体的值 -
?
未知类型,类型参数赋予不确定的值,任意类型 - 只能在声明类型,方法参数上,不能用在定义泛型类上
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(2);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArrayList(list01);
printArrayList(list02);
ArrayList<?> list = new ArrayList<>();
}
/*
定义一个方法能遍历所有类型的集合
泛型没有继承概念
*/
public static void printArrayList(ArrayList<?> list) {
//使用迭代器
Iterator<?> it = list.iterator();
while (it.hasNext()) {
Object next = it.next();
System.out.println(next);
}
}
四、extends/super
1、上限(extends)
指定类必须时继承某个类,或者实现了某个接口,即(<=)? extends E
2、下限(super)
即父类或本身? super E
/**
* extends:泛型的上限 <= 一般用于限制操作 不能使用在添加数据上,一般都是用于数据的读取
*
* supper:泛型的上限 >= 即父类或自身。一般用于下限操作
*
* @author Administrator
* @param <T>
*/
public class Test<T extends Fruit> {
private static void test01() {
Test<Fruit> t1 = new Test<Fruit>();
Test<Apple> t2 = new Test<Apple>();
Test<Pear> t3 = new Test<Pear>();
}
private static void test02(List<? extends Fruit> list) {
}
private static void test03(List<? super Apple> list) {
}
public static void main(String[] args) {
// 调用test02(),测试 extends <=
test02(new ArrayList<Fruit>());
test02(new ArrayList<Apple>());
test02(new ArrayList<ReadApple>());
// test02(new ArrayList<Object>()); Object 不是 Fruit 的子类 ,编译不通过
// 调用test03() ,测试super >=
test03(new ArrayList<Apple>());
test03(new ArrayList<Fruit>());
//test03(new ArrayList<ReadApple>()); ReadApple < apple,所以不能放入
}
}
class Fruit {
}
class Apple extends Fruit {
}
class Pear extends Fruit {
}
class ReadApple extends Apple {
}
五、泛型嵌套
从外往里取
import java.util.Map.Entry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 泛型嵌套
* @author Administrator
*
*/
public class Demo05 {
public static void main(String[] args) {
Student2<String> student = new Student2<String>();
student.setScore("优秀");
System.out.println(student.getScore());
//泛型嵌套
School<Student2<String>> school = new School<Student2<String>>();
school.setStu(student);
String s = school.getStu().getScore(); //从外向里取
System.out.println(s);
// hashmap 使用了泛型的嵌套
Map<String, String> map = new HashMap<String,String>();
map.put("a", "张三");
map.put("b", "李四");
Set<Entry<String, String>> set = map.entrySet();
for (Entry<String, String> entry : set) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
public class School<T> {
private T stu;
public T getStu() {
return stu;
}
public void setStu(T stu) {
this.stu = stu;
}
}
六、其他
import java.util.ArrayList;
import java.util.List;
/**
* 泛型没有多态
* 泛型没有数组
* JDK1.7对泛型的简化
* @author Administrator
*
*/
public class Demo06 {
public static void main(String[] args) {
Fruit fruit = new Apple(); // 多态,父类的引用指向子类的对象
//List<Fruit> list = new ArrayList<Apple>(); //泛型没有多态
List<? extends Fruit> list = new ArrayList<Apple>();
//泛型没有数组
//Fruit<String>[] fruits = new Fruit<String>[10];
//ArrayList底层是一个Object[],它放数据的时候直接放,取数据的时候强制类型转化为泛型类型
/*public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}*/
/*E elementData(int index) {
return (E) elementData[index];
}*/
//JDK1.7泛型的简化,1.6编译通不过
List<Fruit> list2 = new ArrayList<>();
}
}