Я перешел с Java 8 на Java 17. Код теперь не компилируется
В частности, импорт из пакета com.sun.java.swing.plaf.windows
теперь недействителен.
java: пакет com.sun.java.swing.plaf.windows не существует
Однако оно существует. Просто новый компилятор неразумен. Теперь он по какой-то причине отказывается признавать свое существование.
ошибка компиляции, com.sun.java.swing.plaf.windows не существует
Эти пакеты com.sun.java.swing никогда не предназначались для использования вне самой Java, и их не следовало использовать напрямую. Java теперь обеспечивает это.
Хорошо, но мы все равно ссылаемся на пакет. Java утверждает, что обратно совместима, поэтому все, что разрешено в старой версии, должно быть разрешено и в более новой.
Так что же нам делать?
// MRE. Compilation fails. Amazon Corretto 17
package demos.button;
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
import javax.swing.*;
import java.awt.*;
public class CheckBoxDemo {
public static void main(String[] args) throws UnsupportedLookAndFeelException, ClassNotFoundException,
InstantiationException, IllegalAccessException {
// you don't expect us to pass strings directly, do you?
UIManager.setLookAndFeel(WindowsLookAndFeel.class.getName());
JFrame frame = new JFrame("Check Box demo");
JPanel mainPanel = createMainPanel();
frame.setContentPane(mainPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private static JPanel createMainPanel() {
FlowLayout layout = new FlowLayout();
layout.setAlignment(FlowLayout.CENTER);
JPanel mainPanel = new JPanel(layout);
mainPanel.add(createCheckBox());
return mainPanel;
}
private static JCheckBox createCheckBox() {
JCheckBox checkBox = new JCheckBox();
return checkBox;
}
}
Даже если я отключу опцию --release
, код все равно не компилируется. Например, потому что раньше ComboPopup
getList()
выглядело вот так
public JList getList();
и сейчас это выглядит так
public JList<Object> getList();
Так что, если ваша реализация ComboPopup
использовала какие-либо аргументы типа, не повезло.
// no longer compiles
@Override
public JList<T> getList() {
return itemList;
}
На обратную совместимость это вообще не похоже. Разве не в этом (наряду с кроссплатформенной поддержкой) весь смысл Java?
Работать в Windows или Linux?
«Java утверждает, что обратно совместима, поэтому все, что разрешено в старой версии, должно быть разрешено и в более новой». - >пожимаю плечами<. Со времени Java 8 произошло несколько кардинальных изменений. Если вас это останавливает, не обновляйтесь до Java 8.
@StephenC, но это public
, не так ли? Я смогу использовать что угодно public
хорошо
@life888888 Windows 10
Критические изменения @StephenC — это нормально. С другой стороны, несовместимые обратно не являются
Большая часть com.sun.*
была специфична для реализации Java от Sun (а позже и от Oracle) и не предназначалась для общего использования, поскольку на самом деле они не являются частью спецификации Java и, таким образом, могут измениться и исчезнуть при необходимости. Даже если они в настоящее время включены в ваш дистрибутив Java, они не экспортируются из модуля java.desktop
(модульность была введена в Java 9), поскольку вам вообще не следовало использовать их напрямую. Вы можете попробовать добавить необходимый экспорт с помощью --add-exports
в командной строке или Add-Exports
в манифесте вашего приложения.
Кстати, «Java утверждает, что она обратно совместима», да, но это действительно только для официального, поддерживаемого, общедоступного интерфейса («Пакеты java.*, javax.* и org.*, задокументированные в спецификации API Java Platform Standard Edition» )
также проверьте Миграция с JDK 8 на более поздние версии JDK
@user85421 user85421 Добавление экспорта на самом деле не обязательно, поскольку есть более эффективные способы сделать это (некоторые из них представлены в Java 9 специально по этой причине).
Его можно выбрать только в том случае, если система применима.
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
Начиная с Java 9, Java является модульной, и вещи, которые вам не следует использовать, не экспортируются из этих модулей, включая общедоступные классы, которые не являются частью API, определенного спецификацией Java. Классы в com.sun.*
в большинстве случаев относятся к реализации Java Sun/Oracle, а иногда даже зависят от платформы (как в случае с этим внешним видом), а не являются частью спецификации Java. По существу, они обычно считаются деталью реализации, а не частью какого-либо API, и, следовательно, на них не распространяются обещания Java по обратной совместимости. Если бы вы использовали реализацию Java от другого поставщика, у вас, скорее всего, не было бы к ним доступа.
Итак, начиная с Java 9, когда модули реализованы, вы больше не можете получить доступ к этим классам, даже если они все еще существуют (пакет com.sun.java.swing.plaf.windows
находится в модуле java.desktop
, по крайней мере, в сборках Windows). Теоретически вы все равно можете получить к ним доступ, если добавите необходимые экспорты (например, с помощью --add-exports
в командной строке или с помощью Add-Exports
в манифесте JAR приложения).
Однако гораздо проще заменить ваш код чем-то, что будет просто работать без экспорта, как это всегда рекомендовали Sun, а теперь и Oracle (например, см. учебник Swing Как настроить внешний вид, основанный на Ява 8).
У вас есть несколько вариантов:
Явно задайте внешний вид по имени класса:
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
Я бы не рекомендовал это, поскольку это по-прежнему привязывает вас к вариантам Java Oracle/OpenJDK.
Используйте имя внешнего вида вместо имени класса (появившегося в Java 9):
UIManager.setLookAndFeel(UIManager.createLookAndFeel("Windows");
Обратите внимание, что в руководстве упоминаются имена Windows XP
и Windows Vista
, но на самом деле это Windows Classic
и Windows
. Могу только предположить, что когда эта функция была представлена в Java 9, они посчитали имена, упомянутые в руководстве по Java 8, не подходящими для этого.
Если реализация или платформа Java на самом деле не имеет указанного внешнего вида, это приведет к появлению UnsupportedLookAndFeelException
.
Сделайте его динамическим на основе реальной системы:
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
Первый вариант всегда был лучшим решением, если вы хотели, чтобы пользовательский интерфейс выглядел как Windows. Я предполагаю, что Oracle заметил это и поэтому предоставил новый метод, который вы используете в варианте 2, я раньше его не видел. При необходимости можно использовать UIManager.getInstalledLookAndFeels()
для поиска правильного L&F Windows.
@RobSpoor Действительно, но это все еще специфично для реализаций Oracle/OpenJDK; третий вариант на самом деле самый гибкий ИМХО.
Несмотря на то, что он наиболее гибкий, его пользовательский интерфейс сильно отличается от собственных приложений. Вот почему я упомянул метод getInstalledLookAndFeels()
, его можно использовать для поиска правильного L&F Windows. Систему L&F можно использовать в качестве запасного варианта, если совпадений нет.
@RobSpoor В Windows getSystemLookAndFeelClassName()
также приведет к изменению внешнего вида Windows. Первый и второй варианты просто приведут к ошибке на платформах, которые не имеют внешнего вида Windows (это любая платформа, отличная от Windows, AFAIK).
Вы абсолютно правы, я перепутал с getCrossPlatformLookAndFeelClassName()
.
Решение состоит в том, чтобы изменить ваш код так, чтобы он не использовал классы
com.sun.java.swing.plaf.windows
напрямую. В вашем примере не похоже, что для этого есть веская причина.