Java Switchはbyte、short、およびint型をサポートしていることがわかっています。JDK1.5では列挙型がサポートされ、JDK1.7では文字列型がサポートされていました。では、なぜlong型をサポートできないのでしょうか?明らかに、byte、short、intと同じように数値型なので、なぜString型をサポートするのでしょうか。
目次
3. String型はどのようにしてint型になりましたか?
1.結論
スイッチの最下層はint型で判断され、列挙型や文字列型であっても、最終的にはint型に変換されます。long型は、範囲がint型よりも大きいことを示しているため、long型はサポートされていません。
以下は、各型がint型に変換される方法の詳細な説明です。使用されるコンパイルコマンドはjavacであり、逆コンパイルWebサイトは次のとおりです。http://javare.cn
2.列挙型はどのようにしてint型になりましたか?
実験する前は、列挙型のint型フィールドに基づいて計算されることを当然のことと思っていましたが(一般的な列挙型はint型とstring型であるため)、列挙型がない場合は考えますint型Fields。複数のintフィールドがある場合、これは絶対に当てはまりません。以下の実験を見てみましょう。
2つの列挙型クラスを定義します。1つの列挙型クラスにはint型属性と文字列型属性があり、もう1つの列挙型クラスには1つの文字列属性しかありません。
public enum SexEnum {
MALE(1, "男"),
FEMALE(0, "女");
private int type;
private String name;
SexEnum(int type, String name) {
this.type = type;
this.name = name;
}
}
public enum Sex1Enum {
MALE("男"),
FEMALE("女");
private String name;
Sex1Enum(String name) {
this.name = name;
}
}
次に、テストクラスを作成し、列挙された2つのスイッチのFEMALEとMALEの戻り値を変えます。
public class SwitchTest {
public int enumSwitch(SexEnum sex) {
switch (sex) {
case MALE:
return 1;
case FEMALE:
return 2;
default:
return 3;
}
}
public int enum1Switch(Sex1Enum sex) {
switch (sex) {
case FEMALE:
return 1;
case MALE:
return 2;
default:
return 3;
}
}
}
これらのカテゴリを逆コンパイルします。
// SexEnum.class
public enum SexEnum {
MALE(1, "鐢�"),
FEMALE(0, "濂�");
private int type;
private String name;
// $FF: synthetic field
private static final SexEnum[] $VALUES = new SexEnum[]{MALE, FEMALE};
private SexEnum(int var3, String var4) {
this.type = var3;
this.name = var4;
}
}
// Sex1Enum.class
public enum Sex1Enum {
MALE("鐢�"),
FEMALE("濂�");
private String name;
// $FF: synthetic field
private static final Sex1Enum[] $VALUES = new Sex1Enum[]{MALE, FEMALE};
private Sex1Enum(String var3) {
this.name = var3;
}
}
これらの2つの列挙型クラスを逆コンパイルし、すべての列挙値を含む追加の$ VALUES配列があることを確認します。テストクラスの逆コンパイルを続行します。
// SwitchTest$1.class
import com.example.express.test.Sex1Enum;
import com.example.express.test.SexEnum;
// $FF: synthetic class
class SwitchTest$1 {
// $FF: synthetic field
static final int[] $SwitchMap$com$example$express$test$SexEnum;
// $FF: synthetic field
static final int[] $SwitchMap$com$example$express$test$Sex1Enum = new int[Sex1Enum.values().length];
static {
try {
$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.FEMALE.ordinal()] = 1;
} catch (NoSuchFieldError var4) {
;
}
try {
$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.MALE.ordinal()] = 2;
} catch (NoSuchFieldError var3) {
;
}
$SwitchMap$com$example$express$test$SexEnum = new int[SexEnum.values().length];
try {
$SwitchMap$com$example$express$test$SexEnum[SexEnum.MALE.ordinal()] = 1;
} catch (NoSuchFieldError var2) {
;
}
try {
$SwitchMap$com$example$express$test$SexEnum[SexEnum.FEMALE.ordinal()] = 2;
} catch (NoSuchFieldError var1) {
;
}
}
}
最初に、SwitchTest $ 1.javaという名前のリンククラスが生成されます。これは、2つの列挙配列を定義します。これら2つの配列の要素が追加される順序は、テストクラスでスイッチクラスが呼び出される順序とまったく同じです。
画像
配列内の列挙型要素の添え字は、列挙型クラス内の列挙型要素のシリアル番号を返すordinal()関数によって決定されます。
ここで、実際には、switchステートメントで、列挙要素が列挙内の列挙要素の数に従ってint型に変換されることをすでに知っています。最後に、テストクラスの逆コンパイル結果を見て、次のことを確認します。
// SwitchTest.class
import com.example.express.test.Sex1Enum;
import com.example.express.test.SexEnum;
import com.example.express.test.SwitchTest.1;
public class SwitchTest {
public int enumSwitch(SexEnum var1) {
switch(1.$SwitchMap$com$example$express$test$SexEnum[var1.ordinal()]) {
case 1:
return 1;
case 2:
return 2;
default:
return 3;
}
}
public int enum1Switch(Sex1Enum var1) {
switch(1.$SwitchMap$com$example$express$test$Sex1Enum[var1.ordinal()]) {
case 1:
return 1;
case 2:
return 2;
default:
return 3;
}
}
}
3. String型はどのようにしてint型になりましたか?
まず、char型がどのようにint型になるかを最初に知っています。これは非常に単純です。ASCIIコードです。たとえば、switchステートメントがあります。
public int charSwitch(char c) {
switch (c) {
case 'a':
return 1;
case 'b':
return 2;
default:
return Integer.MAX_VALUE;
}
}
逆コンパイルの結果:
public int charSwitch(char var1) {
switch(var1) {
case 97:
return 1;
case 98:
return 2;
default:
return Integer.MAX_VALUE;
}
}
したがって、Stringの場合、hashCode()関数が使用されますが、2つの異なる文字列hashCode()が等しい場合があります。現時点では、equals()関数に依存する必要があります。たとえば、switchステートメントがあります。
public int stringSwitch(String ss) {
switch (ss) {
case "ABCDEa123abc":
return 1;
case "ABCDFB123abc":
return 2;
case "helloWorld":
return 3;
default:
return Integer.MAX_VALUE;
}
}
文字列ABCDEA123abcとABCDFB123abcのhashCodeは等しく、逆コンパイルの結果は次のとおりです。
public int stringSwitch(String var1) {
byte var3 = -1;
switch(var1.hashCode()) {
case -1554135584:
if(var1.equals("helloWorld")) {
var3 = 2;
}
break;
case 165374702:
if(var1.equals("ABCDFB123abc")) {
var3 = 1;
} else if(var1.equals("ABCDEa123abc")) {
var3 = 0;
}
}
switch(var3) {
case 0:
return 1;
case 1:
return 2;
case 2:
return 3;
default:
return Integer.MAX_VALUE;
}
}
hashCodeのequalsに対してequals()メソッドによって判断されるローカル変数var3が導入され、最後にvar3の値が判断されることがわかります。
4.パッケージタイプはサポートされていますか?
例として整数型を取り上げます。文字とバイトは同じです。たとえば、switchステートメントがあります。
public int integerSwitch(Integer c) {
switch (c) {
case 1:
return 1;
case 2:
return 2;
}
return -1;
}
逆コンパイルの結果は次のとおりです。
public int integerSwitch(Integer var1) {
switch(var1.intValue()) {
case 1:
return 1;
case 2:
return 2;
default:
return -1;
}
}
自動開梱により、梱包タイプがサポートされ、解決されていることがわかります。
パッケージタイプがNULLの場合はどうなりますか?まず、swtichの場合はnullが追加されず、コンパイルが失敗することがわかっています。nullを渡すとどうなりますか?
答えはNPEです。結局のところ、これは実際にはパッケージタイプの開封であるため、nullポインタが自然に報告されます。