Java и C: в чем разница и что значит Java Core в вакансиях

Java и C: в чем разница и что значит Java Core в вакансиях Полезное

Java и C — два языка с похожим синтаксисом (фигурные скобки, for, if, типы int и long), но с разной моделью исполнения. Программа на C компилируется в машинный код конкретного процессора и сама управляет памятью. Программа на Java компилируется в байткод, который выполняет виртуальная машина JVM, а память освобождает сборщик мусора.

Ниже разберем главные отличия на одном и том же примере, сведем их в таблицу и отдельно объясним, что работодатели имеют в виду под Java Core — это не отдельный язык, а обозначение базового уровня Java. Примеры проверены 23.09.2026: C — Apple clang 21 (macOS, arm64), Java — OpenJDK 25.0.4 (образ eclipse-temurin:25-jdk).

Короткий словарь перед сравнением

  • Машинный код — инструкции конкретного процессора (x86-64, ARM64). Исполняемый файл под одну архитектуру и ОС на другой не запустится.
  • Байткод — инструкции виртуальной машины Java, одинаковые для всех платформ. Файл .class запускается там, где есть JVM подходящей версии.
  • JVM, JRE, JDK — JVM исполняет байткод; JRE — JVM плюс стандартная библиотека для запуска; JDK — JRE плюс инструменты разработчика (компилятор javac, javap, jar). Для разработки ставят JDK.
  • Указатель (C) — переменная, хранящая адрес в памяти, с которым можно делать арифметику. Ссылка (Java) — способ обратиться к объекту без доступа к адресу.

Один пример на двух языках

Задача: выделить массив из 5 чисел, заполнить квадратами индексов и посчитать сумму. Сначала C:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n = 5;
    int *a = malloc(n * sizeof *a);   /* память под 5 int - вручную */
    if (a == NULL) {
        return 1;                     /* malloc может вернуть NULL */
    }
    for (int i = 0; i < n; i++) {
        a[i] = i * i;
    }
    long sum = 0;
    for (int i = 0; i < n; i++) {
        sum += a[i];
    }
    printf("sum = %ld\n", sum);
    free(a);                          /* и освободить - тоже вручную */
    return 0;
}

Сборка и запуск: cc -std=c17 -Wall -Wextra -o sum sum.c && ./sum. Программа выведет sum = 30 (0 + 1 + 4 + 9 + 16). Тот же алгоритм на Java:

public class Sum {
    public static void main(String[] args) {
        int n = 5;
        int[] a = new int[n];          // память выделяет JVM
        for (int i = 0; i < n; i++) {
            a[i] = i * i;
        }
        long sum = 0;
        for (int i = 0; i < n; i++) {
            sum += a[i];
        }
        System.out.println("sum = " + sum);
    }                                  // free не нужен: объект соберет GC
}

Запуск: javac Sum.java && java Sum, результат тот же — sum = 30. Синтаксис почти совпадает, различия — вокруг кода.

Отличие 1: память — вручную или сборщик мусора

В C программист сам запрашивает память (malloc) и сам ее возвращает (free). Забыл free — утечка. Вызвал free дважды или обратился к памяти после free — неопределенное поведение: программа может упасть, а может работать и портить данные.

В Java объект создается через new, а освобождает память сборщик мусора (GC), когда на объект не осталось ссылок. Граница упрощения: утечки в Java тоже бывают — если объект держит, например, статическая коллекция, GC его не соберет. Java избавляет от ручного free, но не от необходимости думать о памяти.

Отличие 2: проверка границ массива

Внесем одну ошибку в оба примера — во втором цикле условие i <= n вместо i < n, то есть обращение к несуществующему a[5].

Результат в C (clang 21, macOS arm64, без дополнительных флагов): программа молча вывела sum = 30 и завершилась с кодом 0. Ошибка есть, но не видна: C не проверяет границы, чтение за концом массива — неопределенное поведение, и на другой машине или с другим компилятором результат может быть иным. Найти такую ошибку помогает сборка с санитайзером -fsanitize=address:

==91029==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000001c74 ...
READ of size 4 at 0x603000001c74 thread T0
    #0 0x000100c5896c in main bad.c:15

Результат в Java — та же ошибка останавливает программу с понятным сообщением:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
    at Sum.main(Sum.java:10)

Исправление в обоих языках — вернуть i < n. Разница в том, что JVM проверяет индекс при обращении к массиву, а C оставляет это программисту и инструментам.

Отличие 3: машинный код и байткод

Компилятор C превращает sum.c в исполняемый файл под конкретную платформу. Команда file sum на Mac с процессором Apple показывает Mach-O 64-bit executable arm64 — этот файл не запустится ни на Windows, ни на Linux x86-64. Исходник C переносим, если не использует платформенных API, но его надо пересобрать под каждую целевую систему.

javac создает Sum.class с байткодом. Посмотреть его можно командой javap -c Sum, начало метода main выглядит так:

  public static void main(java.lang.String[]);
    Code:
         0: iconst_5
         1: istore_1
         2: iload_1
         3: newarray       int

Это инструкции JVM, а не процессора: тот же .class запускается на Windows, Linux и macOS с JVM подходящей версии. Внутри JVM байткод сначала интерпретируется, а часто исполняемые участки JIT-компилятор переводит в машинный код во время работы программы. Поэтому корректнее говорить не «Java интерпретируемая», а «Java компилируется в байткод, который JVM исполняет с JIT-компиляцией».

Отличие 4: указатели и ссылки

В C можно получить адрес переменной и изменить ее через этот адрес — так функция меняет значения вызывающего кода:

#include <stdio.h>

void swap(int *x, int *y) {    /* получаем адреса переменных */
    int t = *x;
    *x = *y;
    *y = t;
}

int main(void) {
    int a = 1, b = 2;
    swap(&a, &b);              /* передаем адреса a и b */
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

Вывод: a = 2, b = 1. В Java указателей нет: адрес объекта не получить, арифметику над ссылкой не сделать. Все аргументы передаются по значению, для объектов копируется ссылка. Поэтому метод может изменить поля объекта, но не может заменить сам объект у вызывающего:

public class Box {
    int value;

    static void set(Box b) { b.value = 42; }   // меняем объект по ссылке
    static void replace(Box b) { b = new Box(); b.value = 7; } // меняем копию ссылки

    public static void main(String[] args) {
        Box box = new Box();
        set(box);
        replace(box);
        System.out.println(box.value);
    }
}

Программа печатает 42: set изменил объект, а replace поменял только свою локальную копию ссылки. Написать swap для двух int на Java так, как в C, нельзя.

Таблица различий Java и C

Критерий C Java
Результат компиляции Машинный код под ОС и процессор Байткод для JVM
Переносимость Исходника — при пересборке; бинарника — нет .class работает на любой JVM подходящей версии
Память Вручную: malloc / free new + сборщик мусора
Указатели Есть, с арифметикой Нет, только ссылки на объекты
Границы массива Не проверяются (неопределенное поведение) Проверяются, ArrayIndexOutOfBoundsException
Размер int Зависит от реализации (минимум 16 бит) Всегда 32 бита
Парадигма Процедурная, классов нет Объектно-ориентированная, есть лямбды и Stream API
Обработка ошибок Коды возврата, errno Исключения try / catch
goto Есть Зарезервированное слово, не используется
Типичные задачи ОС, драйверы, встраиваемые системы, среды исполнения Серверные приложения, корпоративные системы, Android, обработка данных

Про скорость без абсолютов: у программы на C обычно меньше время старта и расход памяти, долго работающий сервис на Java после прогрева JIT часто приближается к нативному коду. Итог зависит от задачи, и его измеряют, а не выводят из названия языка.

Что такое Java Core в вакансиях

Java Core — неофициальное название базового уровня Java, которым пользуются работодатели и курсы. В документации Oracle такого термина нет: официально платформа называется Java SE (Standard Edition), корпоративные спецификации — Jakarta EE (раньше Java EE). «Знание Java Core» в вакансии обычно означает уверенную работу с языком и стандартной библиотекой без фреймворков.

Что под этим чаще всего проверяют на собеседовании:

Блок Что нужно уметь
Синтаксис и типы Примитивы и ссылочные типы, String и его неизменяемость, equals / hashCode
ООП Классы, интерфейсы, наследование, инкапсуляция, полиморфизм
Исключения Checked и unchecked, try-with-resources
Коллекции List, Set, Map, выбор реализации, обобщенные типы (generics)
Функциональный стиль Лямбды, Stream API, Optional
Многопоточность Thread, ExecutorService, синхронизация, java.util.concurrent
JVM Стек и куча, сборка мусора на уровне понятий, путь от .java до .class

Состав у компаний разный: где-то добавляют ввод-вывод и java.time, где-то многопоточность выносят отдельно. После Java Core обычно идут фреймворки (Spring), базы данных и сборка проекта (Maven, Gradle). Встречающееся в поиске сочетание «Java C» языком не является — так ищут либо сравнение Java и C, либо C#.

Выводы

  • C компилируется в машинный код под конкретную платформу, Java — в байткод, который исполняет JVM с JIT-компиляцией.
  • В C память освобождают вручную, в Java — сборщик мусора, но утечки через забытые ссылки в Java тоже возможны.
  • C не проверяет границы массива и позволяет работать с адресами через указатели; Java проверяет индексы и дает только ссылки.
  • Java Core — неофициальное название базового уровня Java SE: синтаксис, ООП, исключения, коллекции, лямбды и Stream API, многопоточность, основы JVM.

Где применяется / связь с практикой

Понимание, что делает за программиста JVM, помогает на собеседованиях и при поиске ошибок с памятью. Если цель — работать на Java, логичный старт — блоки из таблицы Java Core, закрепленные на небольших проектах. Подробнее о самом языке — в статье Java: что это за язык и зачем он нужен, а про то, как исходный код превращается в исполняемый, — в материале Компиляторы: этапы компиляции и виды.

Освойте тему на практике

Базу Java с практикой и проверкой заданий разбирают на курсе Java Developer. Basic. Чтобы сначала посмотреть формат, подойдут бесплатные открытые уроки Otus.

FAQ

Можно ли вызвать код на C из Java?
Да. Исторически для этого служит JNI, а в современных версиях есть Foreign Function & Memory API (финальный с Java 22), который позволяет вызывать нативные функции без написания C-оберток.

Нужно ли знать C, чтобы учить Java?
Нет, Java можно учить первым языком. Знание C помогает понять, что происходит с памятью и почему JVM проверяет границы массивов, но это не обязательное условие.

Java Core и Java SE — одно и то же?
Близко, но не совсем. Java SE — официальная платформа со всей стандартной библиотекой, а Java Core — разговорное обозначение той ее части, которую ждут от начинающего разработчика.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)