Апплеты в Java: что это было, почему их удалили и чем заменить

Апплеты в Java: что это было, почему их удалили и чем заменить Полезное

Апплет в Java (в запросах часто пишут «аплет») — это класс, унаследованный от java.applet.Applet или javax.swing.JApplet, который браузер скачивал со страницы и запускал в своей Java-машине через плагин Java Plug-in. У апплета нет метода main: создает объект и вызывает его методы init, start, stop, destroy и paint не программист, а браузер.

Сегодня это историческая технология. Ни один современный браузер апплеты не запускает, API помечен устаревшим в JDK 9, помечен к удалению в JDK 17 и удален в JDK 26 (JEP 504). Ниже — как апплет был устроен, почему от него отказались и что взять вместо него, если вам достался старый код.

Слово «апплет» употребляют и в других смыслах: так называют, например, модули панели управления Windows (файлы .cpl). В этой статье речь только о Java.

Апплет, приложение, сервлет, Web Start: не путать

Эти понятия часто смешивают, хотя запускаются они по-разному.

Что Где выполняется Кто запускает Точка входа Статус в 2026
Апплет JVM внутри браузера (плагин) браузер по тегу страницы init()/start() удален из JDK 26
Настольное приложение JVM на компьютере пользователя пользователь, ярлык, инсталлятор main актуально (Swing, JavaFX)
Сервлет JVM на сервере (Tomcat, Jetty) контейнер сервлетов по HTTP-запросу service()/doGet() актуально (Jakarta Servlet)
Java Web Start JVM на компьютере, приложение скачано по ссылке .jnlp лаунчер javaws main удален из Oracle JDK 11
JavaScript движок браузера браузер скрипт страницы стандарт веба

Главное отличие апплета от приложения — не код, а хозяин жизненного цикла. Приложение само решает, когда начать и закончить работу. Апплетом управлял браузер: загрузил страницу — создал объект, ушли со страницы — остановил.

Как работал апплет

Страница подключала скомпилированный класс тегом <applet>, параметры передавались тегами <param>:

<applet code="HelloApplet.class" width="300" height="100">
  <param name="name" value="Otus">
  Ваш браузер не поддерживает Java-апплеты.
</applet>

Браузер скачивал HelloApplet.class (или JAR-архив из атрибута archive) с того же сервера, что и страница, и передавал плагину. Текст между тегами показывался, если Java не было. Тег <applet> признан устаревшим еще в HTML 4.01, а в HTML5 он исключен из стандарта; позже апплеты подключали через <object> или <embed>.

Жизненный цикл выглядел так:

Метод Когда вызывал браузер Что обычно делали Аналог в Swing-приложении
init() один раз после загрузки читали параметры, создавали компоненты конструктор окна или main
start() после init() и при возврате на страницу запускали анимацию, потоки показ окна, windowActivated
paint(Graphics) когда область нужно перерисовать рисовали paintComponent в JPanel
stop() при уходе со страницы останавливали потоки windowDeactivated, сворачивание
destroy() перед выгрузкой апплета освобождали ресурсы windowClosing, завершение

Точный момент вызова stop() и destroy() зависел от браузера и версии плагина: одни выгружали апплет при уходе со страницы, другие держали его в кеше. Поэтому на «гарантированный» вызов destroy() полагаться было нельзя.

Неподписанный апплет работал в песочнице: не читал локальные файлы и соединялся по сети только с сервером, с которого был загружен. Подписанный апплет с согласия пользователя получал больше прав — и именно это стало одной из главных проблем.

Минимальный апплет и что с ним происходит сегодня

Классический пример, переписанный с явными импортами:

import java.applet.Applet;
import java.awt.Graphics;

public class HelloApplet extends Applet {
    @Override
    public void init() {
        System.out.println("init: param name = " + getParameter("name"));
    }

    @Override
    public void paint(Graphics g) {
        g.drawString("Привет, мир", 25, 50);
    }
}

В браузере с плагином на экране появлялась надпись «Привет, мир», а getParameter("name") возвращал значение из тега <param>. Проверим, что с этим кодом происходит на JDK 25 (Temurin 25.0.4, проверено 24.09.2026). Он еще компилируется, но с предупреждением:

HelloApplet.java:4: warning: [removal] Applet in java.applet has been deprecated and marked for removal
public class HelloApplet extends Applet {
                                 ^
1 warning

Запустить его как обычную программу нельзя, потому что метода main нет:

Error: Main method not found in class HelloApplet, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

А если создать объект апплета в среде без экрана (сервер, контейнер, CI), конструктор Applet бросит java.awt.HeadlessException. Утилита appletviewer, которой раньше смотрели апплеты без браузера, удалена из JDK еще в версии 11. Итог: на JDK 25 код апплета компилируется, но запустить его как апплет штатными средствами уже нечем. На JDK 26 (проверено на Temurin 26.0.2) пакета java.applet больше нет, и обычная компиляция падает:

HelloApplet.java:1: error: package java.applet does not exist
import java.applet.Applet;
                  ^

С ключом javac --release 25 тот же файл на JDK 26 еще соберется (компилятор берет описание API 25-й версии), но запуск на JDK 26 закончится java.lang.NoClassDefFoundError: java/applet/Applet: классов апплета в самой среде выполнения уже нет.

Почему апплеты устарели

Причин несколько, и ни одна из них по отдельности не была бы смертельной:

  • Безопасность. Плагин Java был одной из самых атакуемых частей браузера: уязвимости позволяли выйти из песочницы и выполнить код на компьютере пользователя. Oracle ужесточала правила (по умолчанию запускались только подписанные апплеты, пользователь видел предупреждения), но это било и по легальным сайтам.
  • Конец плагинов NPAPI. Браузеры отказались от старой модели плагинов: Chrome — в 2015 году, Firefox — в 2017-м (кроме Flash), Safari — позже. Без плагина апплет просто не запускается.
  • Мобильные устройства. На iOS и Android Java-апплеты в браузере не работали никогда.
  • Веб догнал. HTML5, Canvas, WebGL, WebSocket и быстрый JavaScript закрыли почти все задачи, ради которых подключали апплеты: графику, игры, интерактивные схемы.

Хронология в самой Java:

Год Версия / событие Что произошло
1995 первая публичная Java апплеты — главный сценарий запуска Java в вебе
2017 JDK 9, JEP 289 Applet API помечен @Deprecated
2018 JDK 11 из Oracle JDK убраны Java Plug-in и Java Web Start, из JDK — appletviewer
2021 JDK 17, JEP 398 Applet API помечен к удалению (forRemoval = true)
2026 JDK 26, JEP 504 Applet API удален

По JEP 504 удаляется пакет java.applet целиком (Applet, AppletContext, AppletStub, AudioClip), классы javax.swing.JApplet и java.beans.AppletInitializer и связанные с апплетами методы в java.beans.Beans и javax.swing.RepaintManager. Еще одна причина удаления — песочница апплета держалась на Security Manager, а его окончательно отключили в JDK 24. Значит, JDK 25 — последняя LTS-версия, в которой Applet API есть в самой среде выполнения.

Чем заменить апплет сегодня

Выбор зависит от того, что апплет делал на самом деле:

Что делал апплет Что взять сейчас Когда иначе
Интерактивная графика, игра, визуализация на странице HTML5 Canvas / WebGL + JavaScript или TypeScript если логика большая и уже на Java — компиляция Java в JavaScript или WebAssembly (TeaVM, J2CL)
Форма, калькулятор, работа с данными сервера веб-приложение: фронтенд на JS, бэкенд на Java (Spring Boot, Jakarta EE) —
Полноценная программа, которую «запускали с сайта» настольное приложение на Swing или JavaFX, упакованное jpackage в инсталлятор если нужно автообновление по ссылке — сторонние реализации JNLP
Доступ к локальным файлам, устройствам, подпись документов настольное приложение или локальный агент, с которым страница общается по HTTP браузерные API (File System Access, WebUSB) — если хватает их возможностей и поддержки браузеров
Старый корпоративный апплет, который нельзя переписать сразу изолированная виртуальная машина со старыми браузером и Java 8, без выхода в интернет эмуляторы JVM в браузере — как временная мера

Последняя строка — именно временная мера. Старый плагин не получает исправлений, поэтому держать его на рабочем компьютере с доступом в интернет рискованно.

Перенос апплета в настольное приложение

Если апплет был самостоятельной программой, быстрее всего превратить его в Swing-приложение. Порядок такой:

  1. Вынести рисование из paint() в отдельный метод или в paintComponent() наследника JPanel.
  2. Код из init() перенести в конструктор или main.
  3. Параметры <param> заменить аргументами командной строки, системными свойствами или файлом настроек.
  4. Создать JFrame, задать размер, setDefaultCloseOperation и вызвать setVisible(true) — в апплете этим управлял браузер.
  5. Работу с окном выполнять в потоке событий через SwingUtilities.invokeLater.

Тот же «Привет, мир» в виде приложения:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class HelloDesktop {
    // Логика рисования вынесена из paint() апплета в отдельный метод
    static void draw(Graphics g, String name) {
        g.setColor(Color.BLACK);
        g.drawString("Привет, " + name, 25, 50);
    }

    static class HelloPanel extends JPanel {
        private final String name;
        HelloPanel(String name) { this.name = name; }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            draw(g, name);
        }
    }

    public static void main(String[] args) throws Exception {
        // Бывший <param name="name" value="..."> теперь аргумент запуска
        String name = args.length > 0 ? args[0] : "мир";

        if (GraphicsEnvironment.isHeadless()) {
            // Сервер или контейнер без экрана: рисуем в картинку
            BufferedImage img = new BufferedImage(300, 100, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = img.createGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 300, 100);
            draw(g, name);
            g.dispose();
            ImageIO.write(img, "png", new File("hello.png"));
            System.out.println("headless: hello.png " + img.getWidth() + "x" + img.getHeight());
            return;
        }

        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Hello");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new HelloPanel(name));
            frame.setSize(300, 100);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

На компьютере с экраном команда java HelloDesktop.java откроет окно 300×100 с надписью «Привет, мир». В среде без экрана программа не падает, а сохраняет ту же надпись в hello.png и печатает:

headless: hello.png 300x100

Ветка без экрана добавлена специально: она показывает главный прием переноса. Логика рисования (draw) больше не привязана ни к апплету, ни к окну, поэтому ее можно вызвать и из JPanel, и для картинки, и из теста.

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

Перед переходом на JDK 26 и новее стоит проверить, не осталось ли в коде и зависимостях апплетов. В JDK есть утилита jdeprscan, которая ищет использование API, помеченного к удалению. Пример на JAR с классами из статьи (JDK 25):

jar cf legacy.jar *.class
jdeprscan --release 25 --for-removal legacy.jar
Jar file legacy.jar:
class HelloApplet extends deprecated class java/applet/Applet (forRemoval=true)
class HelloApplet uses deprecated class java/applet/Applet (forRemoval=true)

HelloDesktop в отчет не попал: он использует только Swing, который остается в JDK. Второй способ — jdeps -verbose:class legacy.jar, вывод которого можно отфильтровать по java.applet и JApplet. Сканируйте не только свой код, но и сторонние JAR: апплетный класс мог приехать с библиотекой.

Если не получилось

  • Страница показывает текст вместо апплета или пустую область. Браузер не поддерживает плагины. Это не исправить настройкой — нужен перенос или изолированная среда со старым ПО.
  • Main method not found in class .... Вы запускаете апплет как приложение. Добавьте main с JFrame, как в примере выше.
  • java.awt.HeadlessException при создании объекта. Код с окнами запущен на сервере или в контейнере без экрана. Отделите логику от окна или проверяйте GraphicsEnvironment.isHeadless().
  • После обновления JDK сборка падает на java.applet или JApplet. Вы на JDK 26 или новее. javac --release 25 поможет только собрать код: запускать его все равно придется на JDK 25 или старше, иначе будет NoClassDefFoundError: java/applet/Applet. Это временная мера, планируйте перенос: 25 — последняя LTS с этим API.

Выводы

  • Апплет — Java-класс без main, которым управлял браузер через плагин; от приложения его отличает хозяин жизненного цикла.
  • Апплеты ушли из-за уязвимостей плагина, отказа браузеров от NPAPI, отсутствия на мобильных и развития HTML5.
  • Applet API устарел в JDK 9, помечен к удалению в JDK 17 и удален в JDK 26 по JEP 504; JDK 25 — последняя LTS, где такой код и компилируется, и запускается.
  • Замена зависит от задачи: веб-интерфейс на JavaScript с бэкендом на Java, настольное приложение на Swing/JavaFX или изолированная среда для legacy.
  • Старые апплеты в проекте ищут утилитами jdeprscan и jdeps из состава JDK.

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

Апплеты сегодня встречаются только в сопровождении старых систем, но задача их переноса опирается на базовые навыки Java: классы и наследование, работа с графикой и Swing, сборка и запуск программ, понимание версий JDK. Историю языка и платформы для крупных систем можно посмотреть в статье о Java EE и ее развитии.

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

Если хотите системно освоить язык с нуля до уверенного уровня, посмотрите курс «Java разработчик. Базовый уровень». Попробовать формат и задать вопросы преподавателям можно на бесплатных открытых уроках.

FAQ

Можно ли сейчас запустить старый апплет?
Только в изолированной среде со старым браузером, поддерживающим плагины, и Java 8 с плагином, либо через эмуляторы JVM в браузере. Для рабочей эксплуатации это не годится: старый плагин не получает исправлений безопасности.

Чем апплет отличался от JavaScript?
Это разные языки и разные среды: апплет — скомпилированный байт-код Java, который выполнял плагин, JavaScript — язык самого браузера. Общее у них только то, что оба запускались со страницы.

Нужно ли изучать апплеты новичку в Java?
Нет. Достаточно знать, что это было и почему ушло, чтобы узнать апплет в старом коде. Время лучше потратить на Swing или JavaFX для настольных программ и на веб-разработку на Java.

OTUS Журнал