Напишіть код java, щоб виявити версію JVM


17

Мета полягає в тому, щоб написати код Java, який виявляє версію JVM, покладаючись на зміни сумісності, побічні ефекти, помилки та / або невизначене поведінку, що працює таким чином в одній версії та іншим способом в іншій версії. Крім того, код повинен бути принаймні трохи читабельним, не жертвуючи пробілами та розбірливими назвами змінних.

Для досягнення цієї мети точними формальними правилами є:

  1. Код повинен бути написаний на Java і повинен виводити версію JRE, в якій він працює.

  2. Код не повинен використовувати жоден API JDK або JRE, передбачений спеціально для виявлення версії java або який надає версію JDK або JRE безкоштовно.

  3. Код не повинен використовувати відображення.

  4. Код необхідний лише для роботи в Hotspot Java SE 5, 6 і 7, але може працювати і в інших JVM.

  5. Код не повинен використовувати жодних сторонніх бібліотек на класі.

  6. Код не повинен починати будь-який інший процес, java чи ні.

  7. Код не повинен використовувати змінні середовища.

  8. Код не повинен шукати файлову систему, яка шукає вже наявні файли чи папки.

  9. Код повинен міститися в одному файлі і викликатись через public static void main(String[] args)або public static void main(String... args).

  10. Код не повинен використовувати жоден непублічний API, присутній у JRE.

  11. Код не повинен створювати жодних NoClassDefFoundError, NoSuchMethodError, ClassNotFoundException або NoSuchMethodException під час його виконання.

  12. Код повинен працювати в системі, відключеній від Інтернету або будь-якої локальної мережі.

  13. Вам слід надати пояснення, чому він поводиться по-одному у версії, а іншим - в іншій версії.

Оцінка балів

Метод, який використовується для вимірювання найкращого рішення, - max (n / s), де n - кількість різних версій Java, виявлених без порушення жодного з цих правил (принаймні версії 5, 6 і 7), а s - кількість лексичних лексем у розчині.


Не вдалося знайти кращого тегу, і мені довелося навести останні два. Крім того, мені не вистачає представника для створення нових тегів. Причина java в тому, що це, мабуть, дуже портативна мова, тому писати це було б дуже цікаво. Крім того, версії java визначені таким чином, що ми можемо порівнювати записи, що виявляють навколишнє середовище, з однорідністю, не закінчуючи порівнювати апельсини з яблуками.
Віктор Стафуса

Ви можете розглянути [недоцільно] аргументацію, що виявлення версії VM - це крок в атаці на систему. Я не можу сказати, що у мене є ще одна пропозиція.
dmckee

@dmckee Видалив тег [code-golf]. Додайте тег [underhanded]. Чи можете ви створити тег [java]?
Віктор Стафуса

4
Я голосую за те, щоб закрити це питання як позатематичне, тому що недостатньо важкі виклики вже не є темою на цьому сайті. meta.codegolf.stackexchange.com/a/8326/20469
кіт

@cat, ви повинні замість цього видалити тег, оскільки він не відповідав на запитання.
Пітер Тейлор

Відповіді:


9

6/102 = 0,0588

Виявляє 6 версій. Має 102 лексичні лексеми (зменшено від 103 після видалення publicв public class).

import java.security.Signature;

class GuessVersion {
        public static void main(String[] args) {
                String version = "Java 1.1";
                try {
                        "".getBytes("ISO8859_13");
                        version = "Java 1.3";

                        "".getBytes("ISO8859_15");
                        version = "Java 1.4";

                        Signature.getInstance("SHA256withRSA");
                        version = "Java 5";

                        "".getBytes("KOI8_U");
                        version = "Java 6";

                        Signature.getInstance("SHA256withECDSA");
                        version = "Java 7";
                } catch(Exception e) {}
                System.out.println(version);
        }
}

Java 1.1 представила Java кодування символів та криптографічні алгоритми. Пізніші версії додали ще кодування та алгоритми. Ця програма намагається використовувати кодування та алгоритми, поки не знайде виняток. Я очікую кидання відсутнього кодування java.io.UnsupportedEncodingExceptionта відсутній алгоритм для кидання java.security.NoSuchAlgorithmException.

У мене був старий PowerPC Macintosh з чотирма старими версіями Java. Моя машина OpenBSD має ще дві версії, тому я протестував ці шість версій:

  • Java 1.1.8 в MRJ 2.2.6 для Mac OS 9.2.2
  • Java 1.3.1_16 для Mac OS X Panther
  • Java 1.4.2_21 для Mac OS X Tiger
  • Java 1.5.0_19 для Mac OS X Tiger
  • OpenJDK 1.6.0_32 для OpenBSD 5.5
  • OpenJDK 1.7.0_21 для OpenBSD 5.5

Ця програма також може працювати в JamVM 1.5.4 та gcj 4.8.2 для OpenBSD, але не визначає їх як різні реалізації. Він друкує лише "Java 5".

Виконання Mac OS для Java

Завдяки "Пишіть один раз, запускайте всюди!", Я можу написати цю програму один раз, скласти її один раз і запустити один GuessVersion.class на всіх восьми віртуальних машинах. Мені потрібен компілятор для Java 1.1, найстаріша версія моєї колекції.

Мій компілятор - це javacінструмент MRJ SDK 2.2. Оскільки у класичної Mac OS не було командного рядка, javacце досить графічний інструмент, де я вибираю файли та параметри та натискаю "Do Javac". Після редагування коду я просто знову натискаю "Do Javac".

javac від MRJ SDK 2.2 для Classic Mac OS

Найпростіший спосіб запустити GuessVersion.class - це відкрити його в JBindery, іншому інструменті MRJ SDK 2.2. Виконання - MRJ 2.2.6, реалізація Java 1.1.8.


22

Я не впевнений, який мій бал, тому що це залежить від того, що саме ви вважаєте лексичним ознакою, але я намагаюсь зловживати цією системою підрахунку максимально довгим рядком ...

Це також залежить від того, чи вважаєте ви це ідентифікацією 7 різних версій або 16 ... (Це може тривіально розширитися до 190).

class V extends ClassLoader
{
    public static void main(String[]args)
    {
        for(byte b=60;;)
            try {
                byte[]buf="\u00ca\u00fe\u00ba\u00be\u0000\u0000\u00002\u0000\u0005\u0007\u0000\u0003\u0007\u0000\u0004\u0001\u0000\u0001A\u0001\u0000\u0010java/lang/Object\u0006\u0000\u0000\u0001\u0000\u0002\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000".getBytes("ISO-8859-1");
                buf[7]=b--;
                new V().defineClass(buf,0,53);
                System.out.println(b-43);
                break;
            }
            catch(Throwable t){}
    }
}

Це працює, намагаючись визначити інтерфейс у користувальницькому завантажувачі класів із низхідними основними номерами версій формату класу. Перший, який не кидає, java.lang.UnsupportedClassVersionErrorвідповідає версії VM.


Налічувало 84 лексеми. Досі не перевіряв цього.
Віктор Стафуса

Ваша відповідь геніальна. Можна тривіально зменшити до 83 лексем за допомогою String... args.
Віктор Стафуса

@Victor, це ускладнить питання про те, чи підтримує він 7 різних версій ще більше. Мені невідомо жодного компілятора, який підтримує синтаксис Java 5 і компілює файли класу, сумісні з Java 1.
Пітер Тейлор

Гарна думка. Я про це забув.
Віктор Стафуса

1
Java 1.1.8 (в MRJ 2.2.6) не вдалося зібрати це, поки я додав ще 17 маркерів: protected Class loadClass(String name, boolean resolve) { return Object.class; }. Поточні документи API нехтують згадувати, як це був абстрактний метод до Java 1.2. Я повертаю Object.class, оскільки метод отримує один виклик для "java.lang.Object".
kernigh

8
class Evil {
    public static void main(String... args) {
        String s1 = "Good";
        s1 += "morning";
        int a = 7;
        if (s1 != s1.intern())
            try {
                a--;
                javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar().equals(null);
            } catch (Throwable e) {
                a--;
            }
        System.out.println(a);
    }
}

Алгоритм інтернування змінився між Java 6 та 7. Див Https://stackoverflow.com/a/7224864/540552

XMLGregorianCalendar.equals (null), який використовується для викидання NullPointerException в java 5, але це було виправлено у Java 6. Див. Http://bugs.sun.com/view_bug.do?bug_id=6285370

100 96 92 87 85 лексем тут. Завдяки Пітеру Тейлору за зменшення 7 жетонів.


1
Ви можете зберегти 3 жетони, зберігаючи номер версії в s1. Ви, ймовірно, можете зберегти ще 2, скориставшись Throwable безпосередньо, за умови, що DatatypeConfigurationExceptionне буде кинуто.
Пітер Тейлор

1
Або краще тримати, int aале ініціалізуйте його негайно, щоб ifблок став порожнім. Відкиньте умову, видаліть інше та використовуйте --замість прямого призначення a.
Пітер Тейлор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.