JVMバージョンを検出するJavaコードを作成します


17

目的は、互換性の変更、副作用、バグ、および/またはあるバージョンでは別の方法で、別のバージョンでは別の方法で動作する未定義の動作に依存するJVMバージョンを検出するJavaコードを書くことです。さらに、コードは、空白や読みやすい変数名を犠牲にすることなく、少なくとも少し読みやすくする必要があります。

その目的を確実にするために、正確な正式なルールは次のとおりです。

  1. コードはjavaで記述され、実行中のJREバージョンを出力する必要があります。

  2. コードは、Javaバージョンを検出するために特別に提供されたJDKまたはJRE APIを使用したり、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. コードは、JREに存在する非パブリックAPIを使用してはなりません。

  11. コードは、実行中にNoClassDefFoundError、NoSuchMethodError、ClassNotFoundException、またはNoSuchMethodExceptionを生成してはなりません。

  12. コードは、インターネットまたはローカルネットワークから切断されたシステムで実行する必要があります。

  13. バージョンで1つの方法で動作し、別のバージョンで別の方法で動作する理由を説明する必要があります。

得点

最適なソリューションの測定に使用される方法はmax(n / s)です。nは、これらのルール(少なくともバージョン5、6、および7)に違反することなく検出された異なるJavaバージョンの数であり、sは字句トークンの数です。ソリューションで。


より良いタグを見つけることができなかったため、最後に2つ提供しなければなりませんでした。さらに、新しいタグを作成するのに十分な担当者がいません。javaの理由は、おそらく非常に移植性の高い言語であるため、それを書くことは非常に興味深いからです。さらに、Javaバージョンは、環境を検出するエントリを均一に比較できるように定義されています。オレンジとリンゴを比較する必要はありません。
ビクターStafusa

VMバージョンの検出は、システムを攻撃する際のステップであると主張する[下手な]ことを検討できます。別の提案があるとは言えません。
dmckee

@dmckee [code-golf]タグを削除しました。[underhanded]タグを追加します。[java]タグを作成してください。
ビクタースタフサ

4
このサイトでは、手に負えない課題がトピックではなくなったため、この質問をトピック外として終了することに投票しています。meta.codegolf.stackexchange.com/a/8326/20469
cat

@cat、質問に合わなかったため、代わりにタグを削除する必要があります。
ピーターテイラー

回答:


9

6/102 = 0.0588

6つのバージョンを検出します。102個の字句トークンがあります(で削除publicした後、103個から減少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

4つの古いバージョンのJavaを備えた古いPowerPC Macintoshがありました。私のOpenBSDマシンにはさらに2つのバージョンがあるため、これら6つのバージョンをテストしました。

  • Mac OS 9.2.2のMRJ 2.2.6のJava 1.1.8
  • Mac OS X Panther用のJava 1.3.1_16
  • Mac OS X Tiger用のJava 1.4.2_21
  • Mac OS X Tiger用のJava 1.5.0_19
  • OpenBSD 5.5用のOpenJDK 1.6.0_32
  • OpenBSD 5.5用のOpenJDK 1.7.0_21

このプログラムは、OpenBSDのJamVM 1.5.4およびgcj 4.8.2でも実行できますが、それらを異なる実装として識別しません。「Java 5」のみが出力されます。

Mac OS Runtime for Java

「一度書いて、どこでも実行してください!」のおかげで、このプログラムを一度書いて、一度コンパイルして、8つの仮想マシンすべてで1つのGuessVersion.classを実行できます。私のコレクションで最も古いバージョンであるJava 1.1用のコンパイラが必要です。

私のコンパイラは、javacMRJ SDK 2.2のツールです。Classic Mac OSにはコマンドラインがなかったため、javacファイルとオプションを選択して「Javacを実行」をクリックするかなりグラフィカルなツールです。コードを編集した後、もう一度「Do Javac」をクリックします。

クラシックMac OS用MRJ SDK 2.2のjavac

GuessVersion.classを実行する最も簡単な方法は、MRJ SDK 2.2の別のツールであるJBinderyで開くことです。ランタイムは、Java 1.1.8の実装であるMRJ 2.2.6です。


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互換のクラスファイルにコンパイルするコンパイラを知りません。
ピーターテイラー

いい視点ね。私はそれを忘れていました。
ビクターStafusa

1
Java 1.1.8(MRJ 2.2.6)は、17個のトークンを追加するまで、これをコンパイルできませんでしたprotected Class loadClass(String name, boolean resolve) { return Object.class; }。現在のAPIドキュメントでは、これがJava 1.2より前の抽象メソッドであることに言及することを怠っています。メソッドが「java.lang.Object」の呼び出しを1回取得するため、Object.classを返します。
カーニグ14年

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(ヌル)は、Java 5でNullPointerExceptionがスローするために使用されるが、これは、Java 6を参照してくださいに固定されたhttp://bugs.sun.com/view_bug.do?bug_id=6285370

ここで100 96 92 87 85トークン。7トークンを減らしてくれたPeter Taylorに感謝します。


1
s1にバージョン番号を保存することにより、3つのトークンを保存できます。Throwableを直接キャッチすることで、DatatypeConfigurationExceptionスローされないという仮定でさらに2を節約できます。
ピーターテイラー

1
または、int aすぐに初期化して、ifブロックが空になるようにしてください。条件を否定し、elseを削除して、へ--の直接割り当ての代わりに使用しaます。
ピーターテイラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.