使用泛型屏蔽类型的差异性在c++语言中,有个很好用的模板(template)功能,可以编写带有参数化类型的通用版本,让编译器自动生成针对不同类型的具体版本。而在java语言中,也有一个类似的功能叫泛型(generic)。在编写类和方法的时候,一般使用的是具体的类型,而用泛型可以使类型参数化,这样就可以编写更通用的代码。
许多人都认为,c++模板(template)和java泛型(generic)两个概念是等价的,其实实现机制是完全不同的。c++模板是一套宏指令集,编译器会针对每一种类型创建一份模板代码副本;java泛型的实现基于类型擦除概念,本质上是一种进行类型限制的语法糖。
1.泛型类以支撑类为例,定义泛型的通用支撑类:
/** 通用支撑类 */@getter@setter@tostringpublic class genericholder<t> { /** 通用取值 */ private t value; /** 构造函数 */ public genericholder() {} /** 构造函数 */ public genericholder(t value) { this.value = value; }}
2.泛型接口定义泛型的数据提供者接口:
/** 数据提供者接口 */public interface dataprovider<t> { /** 获取数据函数 */ public t getdata();}
3.泛型方法定义泛型的浅拷贝函数:
/** 浅拷贝函数 */public static <t> t shallowcopy(object source, class<t> clazz) throws beansexception { // 判断源对象 if (objects.isnull(source)) { return null; } // 新建目标对象 t target; try { target = clazz.newinstance(); } catch (exception e) { throw new beansexception(新建类实例异常, e); } // 拷贝对象属性 beanutils.copyproperties(source, target); // 返回目标对象 return target;}
4.泛型通配符泛型通配符一般是使用?代替具体的类型实参,可以把?看成所有类型的父类。当具体类型不确定的时候,可以使用泛型通配符 ?;当不需要使用类型的具体功能,只使用object类中的功能时,可以使用泛型通配符 ?。
/** 打印取值函数 */public static void printvalue(genericholder<?> holder) { system.out.println(holder.getvalue());}/** 主函数 */public static void main(string[] args) { printvalue(new genericholder<>(12345)); printvalue(new genericholder<>(abcde));}
在java规范中,不建议使用泛型通配符?,上面函数可以改为:
/** 打印取值函数 */public static <t> void printvalue(genericholder<t> holder) { system.out.println(holder.getvalue());}
5.泛型上下界在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类。泛型上下界的声明,必须与泛型的声明放在一起 。
上界通配符(extends):
上界通配符为”extends”,可以接受其指定类型或其子类作为泛参。其还有一种特殊的形式,可以指定其不仅要是指定类型的子类,而且还要实现某些接口。例如:list<? extends a>表明这是a某个具体子类的list,保存的对象必须是a或a的子类。对于list<? extends a>列表,不能添加a或a的子类对象,只能获取a的对象。
下界通配符(super):
下界通配符为”super”,可以接受其指定类型或其父类作为泛参。例如:list<? super a>表明这是a某个具体父类的list,保存的对象必须是a或a的超类。对于list<? super a>列表,能够添加a或a的子类对象,但只能获取object的对象。
pecs(producer extends consumer super)原则:
作为生产者提供数据(往外读取)时,适合用上界通配符(extends);
作为消费者消费数据(往里写入)时,适合用下界通配符(super)。
在日常编码中,比较常用的是上界通配符(extends),用于限定泛型类型的父类。例子代码如下:
/** 数字支撑类 */@getter@setter@tostringpublic class numberholder<t extends number> { /** 通用取值 */ private t value; /** 构造函数 */ public numberholder() {} /** 构造函数 */ public numberholder(t value) { this.value = value; }}/** 打印取值函数 */public static <t extends number> void printvalue(genericholder<t> holder) { system.out.println(holder.getvalue());}
以上就是java中泛型的类型屏蔽特性对代码有何影响?的详细内容。