对Java泛型擦除的补偿
文章目录
一、泛型的擦除
在泛型代码内部,无法获得任何有关泛型参数类型的信息。
Java泛型是使用擦除实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,唯一知道的就是在使用一个对象。
1.1 为泛型类设置边界(可以设置多个边界),就可以通过泛型对象调用边界的方法
public class HasF {
public void f(){
System.out.println("HasF.f()"); } } class Manipulator<T extends HasF>{
private T t; public Manipulator(T t){
this.t = t; } public void manipulate(){
t.f(); } } // 可以自行擦除,创建出没有泛型的类 class Manipulator2{
private HasF obj; public void manipulate(){
obj.f(); } }
当希望代码能够跨多个类工作时,使用泛型才有所帮助。例如,返回T的方法,那么泛型就有所帮助,因为它们之后将返回确切的类型:
class Manipulator3<T extends HasF>{
private T t; public Manipulator3(T t){
this.t = t; } public T getT(){
return t; } }
二、擦除的补充
任何在运行时需要知道确切类型信息的操作都无法工作:
public class Erased<T>{
private final int SIZE = 100; public static void f(Object arg){
if(arg instanceof T){
} // error T var = new T(); // Error T[] array = new T[SIZE]; // Error T[] array = (T)new Object[SIZE]; // Unchecked warning } }
2.1 对instanceof的补充:引入类型标签,使用动态的isInstance()
class Building{
} class House extends Building{
} public class ClassTypeCapture<T> {
Class<T> kind; public ClassTypeCapture(Class<T> kind){
this.kind = kind; } public boolean f(Object arg){
return kind.isInstance(arg); } public static void main(String[] args) {
ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class); System.out.println(ctt1.f(new House())); System.out.println(ctt1.f(new Building())); } }
2.2 对泛型new T()对补偿:newInstance()、显式工厂
使用下面的方式,如果实际类型没有默认构造器,将会运行时出错。
class Employee{
} public class ClassAsFactory<T> {
T x; public ClassAsFactory(Class<T> kind){
try {
x = kind.newInstance(); } catch (InstantiationException|IllegalAccessException e) {
throw new RuntimeException(e); } } public static void main(String[] args) {
ClassAsFactory<Employee> fe = new ClassAsFactory<>(Employee.class); System.out.println("ClassAsFactory
succeed"
); try {
// Integer 没有默认对构造器, 因此会失败 ClassAsFactory<Integer> fi = new ClassAsFactory<>(Integer.class); }catch (Exception e){
System.out.println("ClassAsFactory
failed"
); } } }
通过显式工厂,可以获得编译期检查:
interface FactoryI<T>{
T create(); } class Foo2<T>{
private T t; public <F extends FactoryI<T>> Foo2(F f){
t = f.create(); } } class IntegerFactory implements FactoryI<Integer>{
@Override public Integer create() {
return new Integer(0); } } class Widget{
public static class Factory implements FactoryI<Widget>{
@Override public Widget create() {
return new Widget(); } } } public class FactoryConstraint {
public static void main(String[] args) {
new Foo2<Integer>(new IntegerFactory()); new Foo2<Widget>(new Widget.Factory()); } }
2.3 创建泛型数组:Array.newInstance()
没有任何方式可以推翻底层的数组类型,它只能是Object[]。
class Generic<T>{
} public class ArrayOfGeneric {
static final int SIZE = 100; static Generic<Integer>[] gia; public static void main(String[] args) {
// java.lang.ClassCastException // gia = (Generic
[]) new Object[SIZE];
gia = (Generic<Integer>[])new Generic[SIZE]; System.out.println(gia.getClass().getSimpleName()); } }
泛型T[] ,因为有了擦除,数组的运行时类型就只能是Object[]。在下面代码中调用rep() 将报错:
public class GenericArray<T> {
private T[] array; public GenericArray(int sz){
array = (T[]) new Object[sz]; } public T get(int index){
return array[index]; } public T[] rep(){
return array; } public static void main(String[] args) {
GenericArray<Integer> gai = new GenericArray<>(10); // java.lang.ClassCastException,因为实际运行的类型是Object[] Integer[] ia = gai.rep(); } }
尝试将Object[]转换成T[],将在运行时产生异常。没有任何方式可以推翻底层的数组类型,它只能是Object[]。
public class GenericArray2<T> {
private Object[] array; public GenericArray2(int sz){
array = new Object[sz]; } public void put(int index, T item){
array[index] = item; } public T get(int index){
return (T) array[index]; } public T[] rep(){
return (T[]) array; } public static void main(String[] args) {
GenericArray2<Integer> gai = new GenericArray2<>(10); for (int i = 0; i < 10; i++) {
gai.put(i, i); } for (int i = 0; i < 10; i++) {
System.out.print(gai.get(i) + " "); } System.out.println(); // java.lang.ClassCastException Integer[] ia = gai.rep(); } }
使用Array.newInstance() 创建泛型的数组:
public class GenericArrayWithTypeToken<T> {
private T[] array; public GenericArrayWithTypeToken(Class<T> type, int sz){
array = (T[]) Array.newInstance(type, sz); } public void put(int index, T item){
array[index] = item; } public T[] rep(){
return array; } public static void main(String[] args) {
GenericArrayWithTypeToken<Integer> gai = new GenericArrayWithTypeToken<>(Integer.class, 10); Integer[] ia = gai.rep(); System.out.println(ia); } }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/177149.html原文链接:https://javaforall.net
