首页 > 编程语言 >java泛型-桥方法

java泛型-桥方法

时间:2022-12-15 16:00:34浏览次数:54  
标签:setValue java value Pair 类型 泛型 方法 public

虚拟机中没有泛型,只有普通的类和方法。
类型擦除会将类型参数替换成相应的限定类型,如果没有限定类型则替换为Object。
桥方法主要用来解决类型擦除和多态特性的冲突问题。

举例:
定义一个泛型类Pair

public class Pair<T> {
  private T value;

  public Pair() {}
  public Pair(T value) {
    this.value= value;
  }

  public T getValue { return value; }
  public void setValue(T newValue) { value = newValue; }
}

该类因为没有限定类型,所以在类型擦除后的原始类型如下:

public class Pair {
  private Object value;

  public Pair() {}
  public Pair(Object value) {
    this.value= value;
  }

  public Object getValue { return value; }
  public void setValue(Object newValue) { value = newValue; }
}

定义如上Pair类的子类Interval,重写setValue()方法:

public class Interval extends Pair<LocalDate> {
    @Override
    public void setValue(LocalDate value){
            super.setValue(second);
    }
}

如上子类进行类型擦除后的原始类型如下:

public class Interval extends Pair {
    @Override
    public void setValue(LocalDate value){
            super.setValue(second);
    }
}

在执行如下main方法时会存在问题:

public static void main(String[] args) {
    Interval interval = new Interval();
    // 父类引用指向子类对象
    Pair<LocalDate> pair = interval;
    pair.setValue(LocalDate.now());
}

父类引用pair指向子类对象interval,在调用setValue()方法时,应该首先调用子类重写父类的setValue方法,但是:
Interval类中的setValue方法参数类型为LocalDate,而父类中的setValue方法参数类型擦除后为Object,这就造成了类型擦除与多态特性的冲突。
所以Interval类中会生成如下桥方法:

public void setValue(Object newValue) {
  setValue((LocalDate) newValue); 
}

泛型约束和局限性

  1. 不能用基本类型实例化类型参数:类型擦除后变为Object,Object不能存储基本类型的值。

  2. 运行时类型查询只适用于原始类型。
    查询一个对象是否属于某个泛型类型时,使用instanceof会得到编译器错误,如果使用强制类型转换得到一个警告。如下:

if (a instanceof Pair<String>) // Error
if (a instanceof Pair<T>) // Error
Pair<St「ing> p = (Pair<String>) a; // Warning-can only test that a is a Pair

getClass方法总是返回原始类型。如下:

Pair<String> stringPair = . .
Pai「<Employee〉employeePair = . .
// 返回的都是Pair.class
if (stringPair.getClassO == employeePair.getClassO) // they are equal
  1. 不能实例化参数化类型的数组。如下:
Pair<String>[] table = new Pair<String>[10]; // Error

但是声明参数化类型数组的变量是可以的。如下:

Pair<String>[] table;

解决方法:

Pair<String>[] table = (Pair<String>[]) new Pair<?>[10];
  1. 不能实例化类型变量:不能使用像 new T(...),new T[...] 或 T.class这样的表达式中的类型变量。如下:
public Pair() { first = new T(); second = new T(); } // Error

// 解决方法如下:
Pair<String> p = Pair.makePairCString::new);
public static <T> Pair<T> makePair(Supplier<T> constr) {
return new Pair<>(constr.get0. constr.get0); }
  1. 不能构造泛型数组:就像不能实例化一个泛型实例一样,也不能实例化数组。
public static <T extends Comparable〉T[] minmax(T[] a) { T[] mm = new T[2]; . . . } // Error

解决方法如下:

public class Test {
    
    /*public static <T extends Comparable> T[] minmax(T[] a) {
        Object[] mm = new Object[2];
        return (T[]) mm;
    }*/

    public static <T extends Comparable> T[] minmax(IntFunction<T[]> constr, T... elements) {
        T[] mm = constr.apply(2);
        if (elements.length <= 2 && elements.length > 0) {
            return mm = elements;
        }
        return (T[]) mm;
    }

    public static void main(String[] args) {
        String[] strings = new String[2];
        String[] mm = minmax(String[]::new, "hello", "world");
    }
 }
  1. 泛型类静态上下文中的类型变量无效
public class Singleton<T> {
  private static T singlelnstance; // Error
  public static T getSinglelnstanceO // Error
  {
    if (singleinstance == null) construct new instance of T
    return singlelnstance; 
  } 
}
  1. 不能抛出或捕获泛型类的实例:既不能抛出也不能捕获泛型类对象,实际上甚至泛型类扩展Throwable都是不合法的。
    错误示例:
public class Problem<T> extends Exception { /* . . . */ } // Error can't extend Throwable

// catch子句中不能使用类型变量
public static <T extends Throwable〉void doWork(Class<T> t) {
  try
  {
  do work
  }
  catch (T e) // Error can 't catch type variable
  {
  Logger,global.info(...) 
  } 
}

在异常规范中使用类型变量是允许的。

public static <T extends Throwable〉void doWork(T t) throws T // OK
{
  try {
    do work
  }
  catch (Throwable real Cause) 
  { 
    t.initCause(real Cause);
    throw t; 
  } 
}
  1. 擦除后的冲突:要想支持擦除的转换,就需要强行限制一个类或类变量不能同时成为两个接口类型的子类,而这两个接口是同一接口的不同参数化,
// Manager 会实现 Comparable<Employee> 和 Comparable<Manager>, 这是同一接口的不同参数化。
class Employee implements Coinparab1e<Emp1oyee> { . . . }
class Manager extends Employee implements Comparable<Hanager> { . . . } // Error
  1. 泛型类型继承规则
    例如:Manager是Employee的子类,但是Pair不是Pair的子类。

标签:setValue,java,value,Pair,类型,泛型,方法,public
From: https://www.cnblogs.com/fjh0512/p/16969716.html

相关文章

  • [Java SE/Junit] 基于Java的单元测试框架Mockito[转载]
    Mockito是一个模拟测试框架,主要功能是在单元测试中模拟类/对象的行为。1为什么要使用Mockito?Mock可以理解为创建一个虚假的对象,或者说模拟出一个对象.在测试环境中用......
  • CAD怎么输入命令?CAD输入命令方法
    CAD设计过程中,如果想要有效地提高绘图效率,便要能够熟练掌握CAD命令快捷键的使用。了解了这些CAD常用命令后,你知道CAD怎么输入命令吗?本文小编给大家讲解一下浩辰CAD软件中CA......
  • [Java SE/JDK]Intellij IDEA中设置JDK版本
    1IntellijIDEA修改JDK版本第1步:配置JDK环境变量装好JDK之后,要添加一个环境变量:JAVA_HOME第2步:修改Idea配置由Maven决定的版本<build><plugins><p......
  • 测试基础二之用例设计方法
    等价类划分法定义:在所有测试数据中,具有某种共同特征的数据集合进行划分而又分为:有效等价类:满足需求的数据集合无效等价类不满足需求的数据集合  等......
  • win10系统弹出“数据执行保护(DEP)”提示框的解决方法
    原文链接:https://www.xitongcheng.com/jiaocheng/win10_article_14570.html很多用户在win10系统中运行某些程序时,都遇到了“数据执行保护(DEP)”的提示窗口,该是怎么回事呢?其......
  • pycharm安装visdom失败的解决方法
    解决办法:关掉VPN后再安装。相关文章:pytorch专属可视化入门:visdom(pycharm上操作)_打史莱姆的小仙女~的博客-CSDN博客本文转载自:pytorch环境下安装visdom失败的原因_AI知......
  • 活字格调用(6612345网页打印浏览器)打印无响应的解放方法_20221215_112738
    活字格页面标签页内打印无效无响应问题解决方法:测试1:点击打开标签页,点击打印测试按钮,执行无任何响应 命令如下图:测试2.点击打开页面非标签页,点击打印测试执行成功。解决方......
  • Javascript-奖品概率算法
    constLUCKY_AIRDROP_PRIZE=[{"id":1,"prop":16.2},{"id":2,"prop":16.2},{"id":3,"prop":16.2},{"id":4,"prop":16.2},......
  • Java Socket网络编程
    1.TCP流式SocketTCP是TCP/IP体系结构中位于传输层的面向连接的协议,提供可靠的字节流传输。通信双方需要建立连接,发送端的所有数据按顺序发送,接受端按顺序接收。......
  • wordpress---wp_query的使用方法
    wp_query是一个wordpress用于复杂请求的的一个类,看到query懂开发的人就会反应这个是数据库查询的一个类,这个类可谓是非常有用的,可以帮助我们做很多复杂的查询。wp_query的......