泛型擦除与多态的冲突与解决方法

简介: 泛型类 `Pair<T>` 在类型擦除后,其泛型变为 `Object`,子类 `DateInter` 重写 `setValue(Date)` 和 `getValue()` 时,实际覆盖的是原始方法。由于擦除后父类方法参数为 `Object`,子类 `Date` 方法看似重写,实为桥接方法实现的“伪重载”。编译器生成桥接方法以保证多态,虚拟机通过签名区分方法,实现泛型多态性。

假设有一个泛型类
class Pair {

private T value;  

public T getValue() {  
    return value;  
}  

public void setValue(T value) {  
    this.value = value;  
}  

}
然后有一个子类需要继承
class DateInter extends Pair {

@Override  
public void setValue(Date value) {  
    super.setValue(value);  
}  

@Override  
public Date getValue() {  
    return super.getValue();  
}  

}
在这个子类中,我们设定父类的泛型类型为Pair,在子类中,我们覆盖了父类的两个方法,我们的原意是这样的:将父类的泛型类型限定为Date,那么父类里面的两个方法的参数都为Date类型。
所以,我们在子类中重写这两个方法一点问题也没有,实际上,从他们的@Override标签中也可以看到,一点问题也没有,实际上是这样的吗?
分析:实际上,类型擦除后,父类的的泛型类型全部变为了原始类型Object,所以父类编译之后会变成下面的样子:
class Pair {
private Object value;

public Object getValue() {  
    return value;  
}  

public void setValue(Object  value) {  
    this.value = value;  
}  

}
而此时,子类中类型依然是Date,这如果还是在继承关系中,那么根本就不是重写,而是重载了。通过反编译会发现子类中的方法Object getValue()和Date getValue()是同 时存在的,可是如果是常规的两个方法,他们的方法签名是一样的,也就是说虚拟机根本不能分别这两个方法。如果是我们自己编写Java代码,这样的代码是无法通过编译器的检查的,但是虚拟机却是允许这样做的,因为虚拟机通过参数类型和返回类型来确定一个方法,所以编译器为了实现泛型的多态允许自己做这个看起来“不合法”的事情,然后交给虚拟器去区别。

相关文章
|
21小时前
|
Java
什么是泛型擦除
Java泛型是伪泛型,编译后泛型信息被擦除,如List&lt;Object&gt;和List&lt;String&gt;在JVM中均视为List,类型参数不保留,仅用于编译期检查,运行时无法获取泛型实际类型。
|
20小时前
|
缓存 Unix Apache
预检请求的回应
服务器收到预检请求后,校验Origin、请求方法和头字段,若允许跨域,则返回包含Access-Control-Allow-Origin等CORS头的响应。该字段指定合法源,也可设为*表示允许任意源。同时通过Allow-Methods、Allow-Headers告知支持的方法和头字段,Max-Age指定预检缓存时长,避免重复请求。
|
21小时前
|
Java
常见加载顺序
本示例展示了Java中各类代码块的执行顺序:静态代码块随类加载仅执行一次,优先于main方法;局部代码块在方法内按顺序执行;构造代码块每次创建对象前执行,再调用构造器。输出顺序体现其优先级与生命周期。
|
20小时前
|
前端开发 开发者
withCredentials 属性
跨域请求中若需发送Cookie,服务器须设置Access-Control-Allow-Credentials: true,并明确指定Access-Control-Allow-Origin为具体域名,不能为星号。前端需在XMLHttpRequest中显式设置withCredentials = true,否则浏览器不会携带Cookie。注意,Cookie遵循同源策略,仅服务器域名下的Cookie可被上传,前端无法通过document.cookie读取跨域Cookie。
|
20小时前
|
前端开发 开发者
什么是跨域
CORS需浏览器与服务器共同支持,所有现代浏览器均兼容(IE≥10)。通信由浏览器自动完成,开发者无需特殊处理。关键在于服务器需实现CORS接口。请求分为简单和非简单两类,区别在于请求方法和头信息的限制,浏览器会自动处理跨域细节。
|
20小时前
|
SQL 安全 JavaScript
黑名单和白名单
应用内防御SQL注入主要有黑名单和白名单两种输入验证方法。黑名单过滤已知恶意字符,易实现但防护有限;白名单仅允许预定义的合法字符,安全性更高。应根据输入类型定制规则,并结合警报机制及时响应异常输入,确保安全与可用性平衡。
|
20小时前
|
Java 大数据
ArrayList扩容机制
ArrayList添加元素时,先调用ensureCapacityInternal()确保容量,首次添加时默认扩容至10。每次扩容通过grow()实现,新容量为原容量的1.5倍(oldCapacity + (oldCapacity &gt;&gt; 1)),提升性能。当元素数超过当前容量时触发扩容,保证添加高效进行。length为数组属性,length()为字符串方法,size()用于集合元素计数。
|
20小时前
|
SQL 数据库 数据安全/隐私保护
用于绕过身份验证的 SQL 注入示例
SQL注入可绕过登录验证,攻击者通过提交恶意构造的用户名(如admin&#39;)--)和空密码,利用注释符使数据库忽略密码校验,从而非法登录。该技术依赖应用缺乏输入验证,凸显严格过滤与参数化查询的重要性。(238字)
|
20小时前
|
SQL 存储 Oracle
成功的 SQL 注入攻击的后果
SQL注入可导致多种安全威胁:绕过身份验证、窃取敏感信息、篡改或删除数据、破坏网页内容,甚至执行远程系统命令。利用如xp_cmdshell等存储过程,攻击者还能控制数据库服务器操作系统,造成严重危害。
|
20小时前
|
SQL Oracle 安全
了解SQL注入
SQL是用于管理数据库的标准语言,广泛应用于各类Web应用后端。由于用户输入常被用于动态构建SQL语句,若未妥善处理,攻击者可利用SQL注入插入恶意代码,导致身份绕过、数据泄露或传播恶意内容,危害严重。