Какой тип данных реализован в стеке Java и как он рассчитывается для каждого типа?
Я имею в виду реализацию Java-компилятора здесь:
Я предполагаю, что стек реализован как структура C, но я имею в виду:
Как рассчитать Java с этой структурой? Например, если одна локальная переменная имеет тип string или указатель, а другая - тип double или int, и java должен работать с этими переменными, скажем, добавить оба, сначала он преобразует оба в один и тот же тип, а затем добавляет и вернуть значение?
Будет ли это более или менее так:
struct var {
dataType type;
union{
char c;
int i;
double d;
void *p;
} value;
}
где dataType - это перечисление типов данных.
Например: допустим, переменная A является double, а переменная B является int, а C снова является double.
Как байт-код генерируется для C = A + B? и как виртуальная машина работает с этими различными типами данных?
2 ответа
Числа с плавающей точкой (двойные числа) и целые числа являются совершенно разными типами данных, и все современные процессоры имеют специальные операции для обработки этих типов данных. Также Java-байт-код имеет операнд добавления для добавления чисел с плавающей точкой (dadd) и операнд добавления для добавления целых чисел (iadd).
Теперь к вашему вопросу:
double A = 1;
int B = 1;
double C = B + A;
Поскольку результат C является двойным, компилятор Java просто преобразует B в двойное число. Байт-код будет выглядеть примерно так:
dload_1 // load double A
iload_3 // load int B
i2d // convert int to double
dadd // add doubles
dstore 4 // store result to C
Java не приводит типы к так же свободно, как C, поэтому никогда не будет "преобразовывать строку и int таким образом, чтобы они добавлялись".
Система типов Java обычно управляется сравнением строк (однако на одном концептуальном уровне такие элементы часто оптимизируются, и этот уровень является грубым упрощением).
Таким образом, метод имеет сигнатуру, которая представлена в объекте.class в виде строки.
public static void main(String[] args) {
...
}
будет иметь подпись
main([Ljava.lang.String)V
имеется в виду имя 'main', которое принимает массив '[' объекта 'L' типа, который может быть приведен к String 'java.lang.String' и ничего не возвращает (пусто) 'V'.
Таким образом, чтобы увидеть, можно ли передать в него набор параметров во время выполнения, проверяется тип объекта, чтобы убедиться, что он "присваивается" массиву String. Присваиваемый является причудливым способом сказать, разделяет тип как суперкласс, или имеет тип как интерфейс, или один из суперклассов имеет тип как интерфейс.
Из-за этого типа проверки типа JVM фактически не использует проверку типа стиля C для элементов в JVM; тем не менее, он выполняет проверку типа стиля C для элементов, которые реализуют эту среду (если это имеет смысл для вас).
Если вам очень любопытно, вы можете прочитать спецификацию виртуальной машины и, возможно, даже загрузить исходный код JVM. Вы обнаружите, что Java (из-за polymorphisim) не может полагаться на статическую проверку типов во многих случаях, поэтому проверка типа компилятора C не будет работать в любом случае.