1. 泛型出现的背景
- 集合容器在设计阶段不能明确这容器到底实际存储的是什么类型的对象,因此把元素的类型设计成一个参,这个参数就叫做泛型,比如在Collection<E>中这个E就是类型参数,也叫泛型
- 为什么要有泛型?Object不可以吗?
- 解决元素存储的安全性问题
- 解决获取数据元素时需要强制转化的问题
- 泛型可以保证程序在编译时不会发出警告
2.在集合中使用泛型
package javabasis.chapter12;
import java.util.ArrayList;
import java.util.Iterator;
public class ListDemo {
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println("遍历方式1");
for(Integer i:list)
System.out.print(i+" ");
System.out.println("\n遍历方式2");
Iterator<Integer> it=list.iterator();
while(it.hasNext())
{
System.out.print(it.next()+" ");
}
}
}
package javabasis.chapter12;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
public class MapDemo {
public static void main(String[] args) {
Map<String,Integer> map=new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
map.put("D", 4);
Set<Entry<String,Integer>> entrySet=map.entrySet();
Iterator<Entry<String,Integer>> it=entrySet.iterator();
while(it.hasNext())
{
Entry<String,Integer> key_value=it.next();
System.out.println(key_value.getKey()+"--->"+key_value.getValue());
}
}
}
A--->1
B--->2
C--->3
D--->4
2.自定义泛型结构
2.1 泛型类
- 泛型中的T只能是类或包装类型
- 子父类泛型的继承
class Father<T1,T2>{
}
//1.子类不保留父类的类型
class Son1 extends Father{
}
//2.子类具体化父类的泛型
class Son2 extends Father<Integer,String>{
}
//3.子类保留父类的全部泛型
class Son3<T1,T2> extends Father<T1,T2>{
}
//4.子类保留父类的部分泛型
class Son4<T2> extends Father<Integer,T2>{
}
package javabasis.chapter12;
public class PersonTest<T> {
private T info;
private T getInfo()
{
return info;
}
private void setInfo(T info)
{
this.info=info;
}
public PersonTest()
{
}
public PersonTest(T info)
{
this.info=info;
}
public static void main(String[] args) {
PersonTest<String> p1=new PersonTest<>();
p1.setInfo("hello world");
System.out.println(p1.getInfo());
PersonTest<Integer> p2=new PersonTest<>();
p2.setInfo(123);
System.out.println(p2.getInfo());
}
}
hello world
123
2.2 泛型方法
【访问权限】【泛型】【返回类型】【方法名】(泛型标识 参数名称)
public class DAO{
pulic <E> E get(int id,E e)
{
E result=null;
return result;
}
package javabasis.chapter12;
public class MethodTest {
public <T> T getMessage(T message)
{
T ans=message;
return ans;
}
public <T> void print(T info)
{
T mess=info;
System.out.println(mess);
}
public static void main(String[] args) {
MethodTest m=new MethodTest();
System.out.println(m.getMessage("message"));
System.out.println(m.getMessage(123));
m.print("message");
m.print(new int[]{1,2,3,4});//可以传数组类型
}
}
message
123
message
[I@4c98385c
3. 泛型在继承上的体现
- 如果B是A的子类,G是泛型类或泛型接口,但是G<B>不是G<A>的子类,比如List<String>不是List<Object>的子类
public void testGenericAndSubClass() {
Person[] persons = null;
Man[] mans = null;
// 而 Person[] 是 Man[] 的父类.
persons = mans;
Person p = mans[0];
// 在泛型的集合上
List<Person> personList = null;
List<Man> manList = null;
// personList = manList;(报错)
}
4.通配符的使用
- 读取List<?>的对象中的元素永远是安全的,list包含的是Object
- 写入List<?>的元素不行,null除外,它是所有类型的成员
- 将任意元素加入到集合中是不安全的(null除外)
package javabasis.chapter12;
import java.util.ArrayList;
import java.util.List;
public class Demo1 {
public static void read(List<?> list)
{
for(Object o:list)
System.out.println(o);
}
public static void main(String[] args) {
List<?> list=null;
list=new ArrayList<String>();
list.add(null);//只能加入null
//list.add("abc"); //编译不通过
read(list);
List<String> list2=new ArrayList<String>();
list2.add("111");
list2.add("222");
list2.add("333");
read(list2);
List list3=new ArrayList<>();
list3.add(1);//没有使用?通配符时可以通过 但是不建议这样做
list3.add("abc");
read(list3);
}
}
null
111
222
333
1
abc
- 通配符使用注意事项
//1. 编译错误,不能用在泛型方法上,返回值前面不能使用
public static <?> void test(ArrayList<?> list)
{
}
//2.编译错误,不能用在泛型类的声明上
class A<?>
{
}
//3.编译错误 不能用在创建对象上,右边是创建对象,右边的?改成具体类型可以通过
ArrayList<?> list=new ArrayList<?>();
5.有限制的泛型/通配符
< ?/T extends ClassA>
只允许泛型是A和A的子类< ?/T super ClassA>
只允许泛型是A和A的父类< ?/T extends Comparable>
只允许泛型实现Comparable接口的实现类