Как работает коммутатор Java под капотом?

Как работает оператор переключения Java под капотом? Как он сравнивает значение используемой переменной с данными, указанными в частях дела? Использует ли он == или .equals(), или это совсем другое?

Меня в основном интересуют версии до 1.7.

Ответ 1

Ни. он использует lookupswitch JVM lookupswitch, которая по сути является табличным поиском. Посмотрите на байт-код следующего примера:

public static void main(String... args) {
  switch (1) {
  case 1:
    break;
  case 2:
    break;
  }
}

public static void main(java.lang.String[]);
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   iconst_1
   1:   lookupswitch{ //2
                1: 28;
                2: 31;
                default: 31 }
   28:  goto    31
   31:  return

Ответ 2

Как видно из этого ответа, switch Java (по крайней мере, до .equals() 1.7) не всегда компилируется в == или .equals(). Вместо этого он использует поиск по таблице. Хотя это очень небольшая микрооптимизация, при большом количестве сравнений поиск таблиц почти всегда будет быстрее.

Обратите внимание, что это используется только для операторов switch которые сверяются с плотными ключами. Например, проверка значения enum для всех его возможностей, вероятно, приведет к этой первичной реализации (внутренне называемой tableswitch).

При проверке более малонаселенных наборов ключей JVM будет использовать альтернативную систему, известную как lookupswitch. Вместо этого он просто сравнивает различные ключи и значения, выполняя по существу оптимизированное сравнение == для каждой возможности. Чтобы проиллюстрировать эти два метода, рассмотрим следующие два оператора switch:

switch (value1) {
case 0:
    a();
    break;
case 1:
    b();
    break;
case 2:
    c();
    break;
case 3:
    d();
    break;
}

switch (value2) {
case 0:
    a();
    break;
case 35:
    b();
    break;
case 103:
    c();
    break;
case 1001:
    d();
    break;
}

Первый пример, скорее всего, будет использовать поиск по таблице, в то время как другой (в основном) будет использовать == сравнение.

Ответ 3

Скопировано из здесь

В байт-коде есть две формы переключателя: tableswitch и lookupswitch. Один предполагает плотный набор ключей, другой разреженный. См. Описание компилятора в спецификации JVM. Для перечислений порядковый номер найден, а затем код продолжается как случай int. Я не совсем уверен, как будет реализован предлагаемый переключатель на строковой функции в JDK7.

Однако, сильно используемый код обычно скомпилирован в любой разумной JVM. Оптимизатор не совсем глуп. Не беспокойтесь об этом и следуйте обычной эвристике для оптимизации.

Подробный ответ можно найти здесь

Ответ 4

1.По сравнению с прибытием Java 7, это было "==", потому что мы могли бы использовать целое число и char для случая коммутатора, и поскольку они были примитивными, поэтому он должен быть "==".

2. От Java 7, Строка также была разрешена в случае переключения, а используется строка object, ".equals".

Я хотел бы добавить это... что "==" используется для сравнивать Object Reference Variable, не сам объект. Используя ".equals", мы сравниваем объекты.

Ответ 5

При использовании pre 1.7 Java я предполагаю, что он использует

==

потому что для int вы не можете делать равные, например, и в случае перечисления equals и == вернут тот же

ИЗМЕНИТЬ

Мое предположение неверно, что он использует обратимую форму, в байт-код он хотел бы:

 tableswitch

который не намного быстрее, чем обычный if/else, a, как указывали другие.

Ответ 6

Если вы используете примитивные типы, такие как целые числа, тогда java будет использовать == для их сравнения. Если вы используете Strings, тогда java будет использовать метод equals() для проверки, являются ли строки равными. Если вы используете оператор switch с перечислениями, то == и equals() одинаковы, поэтому на самом деле не имеет значения, какой из них используется.

Ответ 7

Коммутатор работает с байтовыми, короткими, char и int примитивными данными типы. Он также работает с перечисляемыми типами (обсуждаются в типах Enum), класс String и несколько специальных классов, которые обертывают определенные примитивные типы: символ, байт, короткий и целочисленный. (Java 1.6)

В то время как примитивы сравниваются с ==, метод switch, безусловно, использует этот вид сравнения в Java 1.6 (и ранее).

Ответ 8

После переключения Java 1.7 также работает с String. Но это только синтаксический сахар над предыдущими функциями. Java не изменяется на уровне родного уровня. Java использует методы hashCode() и equals() для реализации этого с помощью компилятора Java. Давайте посмотрим на пример, что на самом деле делает Java, когда мы используем String в switch. У меня есть демо-код, который переключит название университета и напечатает его в случае. Я использую jdk1.7.0_79.

public class TestMain {
    public static void main(String[] args) {
        String dept = "CSE";

        switch (dept) {
            case "IT":
                System.out.println("IT");
                break;
            case "CSE":
                System.out.println("CSE");
                break;
            case "ECE":
                System.out.println("ECE");
                break;
            case "ME":
                System.out.println("ME");
                break;
        }
    }
}

Если я запустил программу, она напечатает CSE. Теперь, если я декомпилирую программу из сгенерированного файла класса TestMain.class, мы получим следующую строку кода.

public class TestMain {
    public TestMain() {
    }

    public static void main(String[] args) {
        String dept = "CSE";
        byte var3 = -1;
        switch(dept.hashCode()) {
        case 2347:
            if(dept.equals("IT")) {
                var3 = 0;
            }
            break;
        case 2456:
            if(dept.equals("ME")) {
                var3 = 3;
            }
            break;
        case 67029:
            if(dept.equals("CSE")) {
                var3 = 1;
            }
            break;
        case 68455:
            if(dept.equals("ECE")) {
                var3 = 2;
            }
        }

        switch(var3) {
        case 0:
            System.out.println("IT");
            break;
        case 1:
            System.out.println("CSE");
            break;
        case 2:
            System.out.println("ECE");
            break;
        case 3:
            System.out.println("ME");
        }
    }
}

Итак, complier изменил код, соответственно, чтобы разместить переключатель поверх String с использованием методов hashCode() и equals(). Мы знаем, что метод hashCode() возвращает int, и java использует его здесь отлично. Здесь компилятор добавляет двойную проверку с помощью метода equals() метод beacuse hashCode() может иметь хэш-конфликт (у String много конфликтов хеширования). Таким образом, корпус коммутатора над String является всего лишь синтаксическим сахаром.