方法的参数及返回值一般是具体的某个类或某个接口。 (接口的好处是多态)。
当方法的参数或返回值是允许是多种不同的类型时,只能使用Object对象。
如:实例化某一个类:
public Object createJavaBean(Class classz) throws Exception{
return classz.newInstance();
}
//调用时需使用 Person person =(Person)createJavaBean(Person.class);
// Dog dog= (Dog)createJavaBean(Dog.class);
// Cat cat = (Cat)creatJavaBean(Cat.clas);
// createJavaBean 可以生成不同类型的实例,在调用时才能根据参数确定其正确的返回值类型。
返回值为Object ,需要将类型强制转换为实际的类型。
如果这是一个常被调用的方法,其他人调用时,需要查看方法代码才能明白返回的Object是什么。
因此最好使用泛型:IDE能够提示传入或返回正确的类型,而不用强制类型转换。
泛型类:一个类可以操作多个不同类型对象时(每个类实例对应的类型固定),类定义时不能明确的方法的参与返回值类型,则可以将不确定的类型定义为类型参数(代替了Object),定义了类型参数的类为泛型类。
泛型类说明它操作或方法返回的类型不确定,直到实例化时(传入实际的类型参数值)才确定,该实例的所有方法都能明确其返回值或参数值的类型(写代码时IDE直接提示该类型是什么了),而不是Object。
泛型方法:方法的参数或返回值的类型不确定,可以定义为类型参数(而不是Object),直到方法调用时,传入实际的参数类型,从而推导出实际的返回值类型,或推导出其它的参数的类型(写代码时IDE直接提示该类型是什么了),而不是Object。
泛型方法:
方法的返回值前定义泛型说明: < 类型参数A[A extends 类或另一类型参数][,类型参数B[B extends 类或另一类型参数]....]>,方法参数类型或返回值类型 定义好的类型参数A或B了。
public <T> T createJavaBean(Class<T> classz) throws Exception{
return classz.newInstance();
}
//定义了T类型,说明参数是某一类的Class对象,返回值类型则为该类型的实例。
//那么传入的参数类型一确定,那么它的返回值类型也就确定了。所以返回值不是Object,而是实际的类型。
//调用时:Person person = createPerson(Person.class);而不需要类型转换
如果createJavaBean 只能够创建Person 及其子类型 ,其它的类型不能创建 。那么就应该定义T类型的范围 : T extends Person,说明T只能是Person 或其子类型。
public <T extends Person> T createPerson(Class<T> classz) throws Exception{
return classz.newInstance();
}
调用:BlackPerson blacPerson = createPerson(BlackPerson.class);
//BlackPerson是Person 的子类。
createPerson(String.class);//这行编译报错
泛型类:
在类名后面加上泛型说明: < 类型参数A[A extends 类或另一类型参数][,类型参数B[B extends 类或另一类型参数]....]>,类中的任意方法的参数或返回值就可以使用类型参数A或B了。
类型参数值在泛型类实例化时确定: new 泛型类<实际类型参数A,实际类型参数B....>(构建器参数)。
实例化之后,方法的参数与返回值是类型参数的,都已明确它的类型=实际传入的类型
在实例化泛型类时,也可以不传入实际的类型参数,那么类中定义的类型参数就自动为Object.
泛型类的子类:
第一种方式,扩展父类,给出实际的参数类型:
第二种方式:继续使用参数类型
类型通配符:?
代表任意类型。
一般用于泛形类实例变量。
List<?> list ;//不明确类型的List,
list = new ArrayList<String>();//正确
list = new ArrayList<Integer>();//正确
list = new ArrayList<Object>();//正确
可以用于方法参数中,实现对某一个类的不同泛型类实例的通用操作,但只能调用泛型实例的非泛型参数的方法,因为泛型参数是?,无法确定其类型,参数传递不进去。
void test(List<?> list){
Object obj = list.get(0);//调用非泛型方法,返回值类型为?,未明确的类型,上溯到所有类型的父类Object
list.add(new String(""));//调用泛型方法,参数类型是?,未明确的类型,可能是String、Integer等等,这行代码中给?赋值为String,编译不过去
}
void test(List<? extends Person> list){
Person person = list.get(0);//调用非泛型方法,返回值类型为?,未明确的类型,上溯到类型上限 Person
//list.add(new Person());//调用泛型方法,编译不过去
}
AbstractCollection 源码:
public abstract class AbstractCollection<E> implements Collection<E> {
public boolean containsAll(Collection<?> c) {
Iterator<?> e = c.iterator();
while (e.hasNext())
if (!contains(e.next()))
return false;
return true;
}
public boolean contains(Object o) {
Iterator<E> e = iterator();
if (o==null) {
while (e.hasNext())
if (e.next()==null)
return true;
} else {
while (e.hasNext())
if (o.equals(e.next()))
return true;
}
return false;
}
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
Iterator<? extends E> e = c.iterator();
while (e.hasNext()) {
if (add(e.next()))
modified = true;
}
return modified;
}
}
源码中:
1.方法 containsAll(Collection<?> c) ,参数可以是任意类型的 Collection。
2.方法addAll(Collection<? extends E> c),可以接受E类型或E子类型的Collection.
获取泛型实例的实际类型:
方式一:
父类 TypeReference ,来源于 MyBatis3.2.3
public abstract class TypeReference<T> {
private final Type rawType;//T的实际类型
protected TypeReference() {
rawType = getSuperclassTypeParameter(getClass());
}
Type getSuperclassTypeParameter(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof Class) {
// try to climb up the hierarchy until meet something useful
if (TypeReference.class != genericSuperclass) {
return getSuperclassTypeParameter(clazz.getSuperclass());
}
throw new RuntimeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
+ "Remove the extension or add a type parameter to it.");
}
Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
// TODO remove this when Reflector is fixed to return Types
if (rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType) rawType).getRawType();
}
return rawType;
}
public final Type getRawType() {
return rawType;
}
@Override
public String toString() {
return rawType.toString();
}
}
DAO 类扩展 TypeReference:
public class Dao<T,PK> extends TypeReference<T>{
public T queryOne() throws Exception{
T t = ((Class<T>)this.getRawType()).newInstance();
Map dataMap = new HashMap();//数据查询结果
dataMap.put("name", "ll");//模拟数据
BeanUtils.populate(t, dataMap);
return t;
}
}
PersonDao 扩展了 Dao:
public class PersonDao extends Dao<Person, String> {//这里指明T的类型,要不然获取不到
public static void main(String args []){
try{
PersonDao personDao = new PersonDao();
Person person = personDao.queryOne();
System.out.println(person);//输出:Person [name=ll]
}catch(Exception e){
e.printStackTrace();
}
}
}