泛型问题的引出
为什么要用泛型?
在java集合中储存数据会被当做Object类型来存储,可能有些类型会失去原本的特性,所以可以用泛型来统一集合当中的存储类型。
class Test3 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("1212");
list.add(121);
List<String> lists = new ArrayList<String>();
lists.add("2121");
//lists.add(2121); //报错
}
}
在我看来泛型就是一个辅助我们编译的东西,在很多复杂类型中可以使用泛型来解决。
泛型的基本定义
泛型不止可以用作集合上,还能用作在参数、方法、类等…
利用泛型还可以解决ClassCastException问题.
class CeShi4<T> { //T属于类型标记,可以设置多个
//T返回的是什么数据类型,下面属性就是什么数据类型
private T x; //x轴坐标
private T y; //y轴坐标
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
class Test3 {
public static void main(String[] args) {
//实例化CeShi4对象,设置"T"数据类型
CeShi4<Integer> ceShi4 = new CeShi4<Integer>();
ceShi4.setX(10);
ceShi4.setY(20);
int x = ceShi4.getX();
int y = ceShi4.getY();
System.out.println("x轴坐标:"+x+",y轴坐标:"+y);
}
}
输出结果:
x轴坐标:10,y轴坐标:20
泛型通配符
数组的协变
例子:
Number[] nums = new Integer[10]; // OK
因为Integer是Number的子类,一个Integer对象也是一个Number对象,所以一个Integer的数组也是一个Number的数组,这就是数组的协变。
java数组的协变是有一定的缺陷的,就算是把Integer[]赋给Number[],但是数组元素类型还是Integer,智能放入Integer子类或者Integer对象。如果放入Number子类或者Number对象,那么在运行的时候JVM能够知道数组元素的类型是Integer,所以会报java.lang.ArrayStoreException错误
那么我们可以使用泛型的通配符来解决这种问题
向上转型:
List<? extends Number> nums = new ArrayList<Integer>(); // OK
无边界通配符
当你不知道泛型返回的是什么类型可以用<?>
class Test3 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("121");
list1.add("222");
show(list1);
}
public static void show(List<?> c){ //当你不知道泛型是什么类型时用?
for (Object object : c) {
System.out.println(object);
}
}
}
121
222
List<?>和List的区别
- List是表示持有某种特定类型对象的List,但是不知道是哪种类型;List是表示持有Object类型对象的List。
- List<?> 因为不知道持有的实际类型,所以不能add任何类型的对象,但是List list因为持有的是Object类型对象,所以可以add任何类型的对象。
上边界限定的通配符
< ? extends E>:接收E类型或者E的子类型对象
class Person{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
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;
}
}
class Student extends Person{
public Student(String name, int age) {
super(name, age);
}
}
class Test3 {
public static void main(String[] args) {
List<Person> list1 = new ArrayList<Person>();
list1.add(new Person("sss", 12));
List<Student> list2 = new ArrayList<Student>();
list2.add(new Student("ccc",13));
show(list1);
show(list2);
}
public static void show(List<? extends Person> c){ //当你不知道泛型是什么类型时用?
Iterator<? extends Person> it = c.iterator();
while(it.hasNext()){
Person p = it.next();
System.out.println("姓名:"+p.getName()+",年龄:"+p.getAge());
}
}
}
输出结果
姓名:sss,年龄:12
姓名:ccc,年龄:13
下边界限定的通配符
< ? super E >:接收E类型或者E的父类型
class Person{
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
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;
}
}
class Student extends Person{
public Student(String name, int age) {
super(name, age);
}
}
class Test3 {
public static void main(String[] args) {
List<Person> list1 = new ArrayList<Person>();
list1.add(new Person("sss", 12));
List<Student> list2 = new ArrayList<Student>();
list2.add(new Student("ccc",13));
show(list1);
show(list2);
}
public static void show(List<? super Student> c){ //当你不知道泛型是什么类型时用?
Iterator<? super Student> it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
输出结果
main.Person@15db9742
main.Student@6d06d69c
泛型接口
例子:
//泛型接口
interface Person<T>{
public void show(T t);
}
//子类继承泛型接口
class Student<Q> implements Person<Q>{
@Override
public void show(Q q) {
// TODO Auto-generated method stub
System.out.println("show:"+q);
}
}
class Test3 {
public static void main(String[] args) {
Person<Integer> p = new Student<Integer>();
p.show(2222);
}
}
输出结果
show:2222
泛型方法
例子:
class Person{
//泛型方法
public <T> void show(T t){
System.out.println(t);
}
public <U,T> void show(U u,T t){
System.out.println(u);
System.out.println(t);
}
}
class Test3 {
public static void main(String[] args) {
Person person = new Person();
person.show("sb");
person.show(123, "小红");
}
}
输出结果:
sb
123
小红
- 泛型方法可以让不同方法操作不同类型,且类型还不确定。
- 与泛型类不同,泛型方法的类型参数只能在它锁修饰的泛型方法中使用。