Java 枚举更改与添加新异常。需要重新编译吗?
这个问题基于“函数”一章“Error.java依赖磁铁”一节 作者声称,所有导入并使用此Java 枚举更改与添加新异常。需要重新编译吗?,java,exception,enums,Java,Exception,Enums,这个问题基于“函数”一章“Error.java依赖磁铁”一节 作者声称,所有导入并使用此enum的类都必须重新编译,以防发生更改。这与添加新的例外衍生品相反。在后一种情况下,无需重新编译 但是,如果您通过添加新的派生异常,在更改包后立即使用包含派生异常的包,那么如果您的代码依赖于该包,则需要重新编译,这不是吗?或者,如果代码实际使用了一个新的派生异常,您是否只需要重新编译代码?本段还有一点内容。我将引用: 像这样的类是一个依赖磁铁;许多其他类必须导入并使用它们。因此,当错误枚举更改时,所有其他类
enum
的类都必须重新编译,以防发生更改。这与添加新的例外
衍生品相反。在后一种情况下,无需重新编译
但是,如果您通过添加新的派生
异常
,在更改包后立即使用包含派生异常的包,那么如果您的代码依赖于该包,则需要重新编译,这不是吗?或者,如果代码实际使用了一个新的派生异常,您是否只需要重新编译代码?本段还有一点内容。我将引用:
像这样的类是一个依赖磁铁;许多其他类必须导入并使用它们。因此,当错误
枚举更改时,所有其他类都需要重新编译和重新部署
这起初读起来令人困惑,但事后看来是有道理的
枚举中声明了保证的枚举常量;向枚举中添加另一个值需要进行另一次编译才能获取该更改。这适用于使用枚举的所有类,即使它们不使用该值
另一方面,如果您声明了几个独立的异常
派生类,如果您的特定类不需要特定的异常
,则不需要重新编译它来使用它
这与你的下一个问题有关:
…[I]如果您通过添加新的派生的异常来更改包含派生异常的包,那么如果您的代码依赖于该包,那么是否需要重新编译
这与我在Java程序中看到的一种更常见的趋势有关(与J1中标识的代码气味相冲突):除非您需要包中的所有内容,否则不要导入整个包
我怀疑在包级依赖性方面是否有实质性的区别;我找不到任何证据表明Java有条件地编译选择类,但我也不认为它会重新编译您的类,只是为了包含您未使用的异常。这一段还有一点。我将引用:
像这样的类是一个依赖磁铁;许多其他类必须导入并使用它们。因此,当错误
枚举更改时,所有其他类都需要重新编译和重新部署
这起初读起来令人困惑,但事后看来是有道理的
枚举中声明了保证的枚举常量;向枚举中添加另一个值需要进行另一次编译才能获取该更改。这适用于使用枚举的所有类,即使它们不使用该值
另一方面,如果您声明了几个独立的异常
派生类,如果您的特定类不需要特定的异常
,则不需要重新编译它来使用它
这与你的下一个问题有关:
…[I]如果您通过添加新的派生的异常来更改包含派生异常的包,那么如果您的代码依赖于该包,那么是否需要重新编译
这与我在Java程序中看到的一种更常见的趋势有关(与J1中标识的代码气味相冲突):除非您需要包中的所有内容,否则不要导入整个包
我怀疑在包级依赖性方面是否有实质性的区别;我找不到任何证据表明Java有条件地编译选择类,但我也不相信它会重新编译您的类,只是为了包含您没有使用的异常。Java在二进制兼容性方面非常聪明,因为它使用方法签名等,所以在大多数情况下,兼容性很容易维护。您可以添加子类并将它们传递到接受其超类的方法中,即使这些方法没有使用存在的子类进行编译,您也可以将方法添加到类中并添加接口供它们实现,并且二进制兼容性在大多数情况下仍然是一样的。对于枚举,情况并非如此。枚举经常使用.ordinal()
方法(编译时)来执行某些任务(有关字节码的更多信息,请参见下文),因此,当类发生更改时,可能需要重新编译
Makoto的回答很好地涵盖了概念性内容,但直接原因与javac
生成的字节码有关
以下班级:
public class TestEnums {
public static void main(String[] args) throws Throwable {
Matter matter = Matter.SOLID;
switch (matter) {
case SOLID:
System.out.println("a");
break;
case LIQUID:
System.out.println("b");
break;
case GAS:
System.out.println("c");
break;
}
}
private enum Matter {
SOLID,
LIQUID,
GAS
}
}
生成以下字节码(在主方法中):
为了避免字节码的冗长,switch语句的主要逻辑以表开关的形式出现:
INVOKEVIRTUAL TestEnums$Matter.ordinal ()I
IALOAD
TABLESWITCH
1: L2
2: L3
3: L4
default: L5
如果查看,您会看到开关调用.ordinal()方法来确定要转到哪个值,因此如果在枚举的开头插入一个值:
private enum Matter {
PLASMA, //Lying elementary school science teachers don't tell you about this one
SOLID,
LIQUID,
GAS
}
序号已更改。由于字节码在处理枚举时经常使用序数方法,因此可能需要重新编译代码以保持与枚举的兼容性。Java在二进制兼容性方面非常聪明,因为它使用方法签名等,所以在大多数情况下,兼容性很容易保持。您可以添加子类并将它们传递到接受其超类的方法中,即使这些方法没有使用存在的子类进行编译,您也可以将方法添加到类中并添加接口供它们实现,并且二进制兼容性在大多数情况下仍然是一样的。对于枚举,情况并非如此。枚举通常使用.ordinal()
方法(当
INVOKEVIRTUAL TestEnums$Matter.ordinal ()I
IALOAD
TABLESWITCH
1: L2
2: L3
3: L4
default: L5
private enum Matter {
PLASMA, //Lying elementary school science teachers don't tell you about this one
SOLID,
LIQUID,
GAS
}