发生的环境 jdk7 tomcat7
问题描述。
1.改了一个实体类A中某一个成员变量的类型,以及受影响的引用的修改。
2.但是其中一个B类引用了实体类A,但是情况特殊,并没有受到影响报错,就没有修改该类。
3.因为迟迟不能上线,现在要对B类进行修改,修改过后,将B类的class文件单独打包上服务器。启动正常,调用修改过A类变量的时候报错。
4.也就是说实体类A在服务器上还是旧的,但是有一个引用过A的B类修改后上线出现的问题
5.最后解决是将A类退回线上版本 重新编译 重新传B.class
解决很简单,但是当时也是有点懵。
错误信息如下。
错误信息很明显,就是在调用model.setHh(D)V,没有找到这类方法,参数是double,返回值是void的方法。
如下代码 demo
package com.wpao.test.modeltype;
public class Model {
private int hh;
public int getHh() {
return hh;
}
public void setHh(int hh) {
this.hh = hh;
}
}
//这个是修改之前的实体文件是int类型
package com.wpao.test.modeltype;
public class Model {
private double hh;
public double getHh() {
return hh ;
}
public void setHh(double hh) {
this.hh = hh;
}
}
//这个是修改之后的实体类型 类型为double
package com.wpao.test.modeltype;
public class Abc {
//这个是调用类的方法
public static void main(String[] args) {
try {
Model m = new Model();
//实体改成double和int类型是不影响这句话编译的,不会报错
m.setHh(1);
System.out.println(m.getHh());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
现在运行以上代码 就会报出上述异常。
当时出现的情况获取Molde的方式是
Model model = (Model)list.get(i);
model.getXxx();
然后报错,当时也是脑子秀逗了,认为和泛型擦除有关系。所以去调查了下泛型擦除,找到一篇文档如下。
当您编写对泛型方法的调用时,编译器会插入一个casts在返回类型的时候,并将其擦除。
编译器自动插入强制转换 Employee
也就是说,编译器将方法调用转换为两个虚拟机指令
raw:这是一种规定了generic type参数,但是引用的时候却没有指明的一种引用。
1.调用了泛型方法Pair.getFirst
2.将return回来的Object强转为Employee
下面是网上摘抄的
Java的泛型是伪泛型。在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。
Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。
如在代码中定义的List<object>和List<String>等类型,在编译后都会编程List。JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转换异常的情况。
顺便回忆了一下泛型,貌似和这个地方出现的问题没有啥关系,应该是思路错了。
然后只能看下字节码,对比下A类和类的区别
右边的是原始的Model类 左边是新的Abc类,引用也是新的Model类
在Abc.class中setHh和gethh在静态编译后已经是为double 但是在旧的Model.class中hh变量还是int型
所以在运行调用时导致了NoSuchException