今天来学习一下泛型,为了后面找工作做准备:
泛型的出现真的是非常方便,它增加了通用性,自然也省去了很多重复工作。我主要是用到泛型类,在MVC设计模式下,使用框架开发web工程,经常要和数据库交互,而且是对多张表或几张表在联合操作,同时也想操作的时候框架自动或者稍微手动一下使操作的都是bean对象。而对于数据库常用操作增删改查,这四种操作都是相同的,所以希望能把这四种操作抽象出来,操作各种表(对象),而如果不用泛型,则操作不同表则需要传入和返回不同对像,那么就需要对每种对象操作都要重复上述四种操作。但是有了泛型就不一样了,它可以指任何一种具体的java类型。
**
Java泛型中的标记符:
**
T –Type(Java 类型)ps:这里的T是指具体的某一种类型,其实在编译结束后,类型就会被擦除,变为真正的Java类型。
K –Key(键)一般用于Java中的Map等集合中。
V–Value(值)一般用于Java中的Map等集合中。
?–不确定的Java类型,一般用在通配符或者class类型不确定。
Java泛型应用主要有:泛型类、泛型方法、泛型接口、边界符、通配符
泛型类其实即使我上面提到增删改查用到的
public class BaseDao<T>{
public void save(T o){...}
public void delete(T o){...}
public List<T> findStudents(String hql,Object param[]){...}
//注意这些方法并不是泛型方法
......
}
这个定义就可以操作很多对象表。
泛型方法
泛型方法定义也很简单,需要在方法返回类型前加上泛型标识,
public class Utils{
public <T> void compare(List<T> list){...}
//在返回值前加<T> 、<K,v>等才是泛型方法,当然如果类为泛型类Utils<T>,方法返回类型前<T>也包含类型T
}
注意:如果泛型类中有静态方法,则静态方法不能引用类中的泛型,需要引用则需要把静态方法定义为泛型方法。
泛型接口
public interface BaseDaoInterface<T>{
public void save(T o);
public void delete(T o);
.....................
}
接口使用
public class BaseDao<T> implements BaseDaoInterface<T>{
public void save(T o){...}
public void delete(T o){...}
//public List<T> findStudents(String hql,Object param[]){...}
......
}
边界符
public void getValue(ShuZhi<? extends Number> value){....}
public void fn(Fruit<? super Apple>){...}
//ShuZhi、Fruit为泛型类,这里使用?与T区别不是很明显,但是可以理解为编译后,?可以是符合多种要求的数据类型,而?只能是确切的某一种。
通配符
public void boxTest(Box<Number> n) {...}
上面这个方法是不允许传入参数Box,虽然Integer属于Number子类,但Box与Box并没有这中关系,
class Parent{}
class Son1 extends Parent{}
class Son2 extends Parent{}
这个需要我们使用通配符来解决这个问题
public class Family<T>{
T fn1(List<? extends T> list){}
String fn2(){
Family<Parent> p=new Family<Parent>();
Parent p1=p.fn1(parent);
Parent p2=p.fn1(son1);
}
public static void main(String[] args) {
f2();
}
}
PECS原则
Producer Extends, Consumer Super
具体理解可以往下看:
import java.util.Arrays;
import java.util.List;
public class GenericReading {
static List<Apple> apples=Arrays.asList(new Apple());
static List<Fruit> fruit= Arrays.asList(new Fruit());
static class Reader<T>{
T readExact(List<T> list){
return list.get(0);
}
}
static void f1(){
Reader<Fruit> fruitReader =new Reader<Fruit>();
//Fruit f = fruitReader.readExact(apples);//出错
}
static class CovariantReader<T>{
T readCovariant(List<? extends T> list) {
return list.get(0);
}
}
static void f2(){
CovariantReader<Fruit> cList=new CovariantReader<Fruit>();
Fruit f=cList.readCovariant(apples);
}
public static void main(String[] args) {
f2();
}
}
在方法f1()中,我们发现在fruitReader.readExact(List list)中不能传入参数List apples,虽然Apple是Fruit子类,但编辑器认为List apples与List list是没有关系的。所以在f2中,使用通配符readCovariant(List
import java.util.ArrayList;
import java.util.List;
public class GenericWriting {
static List<Apple> apples = new ArrayList<Apple>();
static List<Fruit> fruit = new ArrayList<Fruit>();
static <T> void writeExact(List<T> list, T item) {
list.add(item);
}
static void f1() {
writeExact(apples, new Apple());
writeExact(fruit, new Apple());
}
static <T> void writeWithWildcard(List<? super T> list, T item) {
list.add(item);
}
static void f2() {
writeWithWildcard(apples, new Apple());
writeWithWildcard(fruit, new Apple());
}
public static void main(String[] args) {
f1(); f2();
}
}
我们可以从思想或方法参数上理解:
writeWithWildcard(List