2013-08-08 28 views
6

私はリフレクションを試して、クラス名を入力できるところに到達できるかどうかを確認しようとしています。アプリケーションがそのクラスをロードしてそのインスタンスを作成します。いくつかの試みの後、私はちょうどそのパッケージ名なしでClass.forName()にクラス名を張ることができないことが分かったので、ロードされたすべての利用可能なパッケージのリストを取得しようとした。パッケージ名がヒットするまで。私のリフレクションが奇妙なクラスを読み込むのはなぜですか?

これは私がこれまで持っているものである:それは半非常に奇妙な方法で動作します

BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); 
    String s = ""; 
    do 
    { 
     ClassLoader clsldr = ClassLoader.getSystemClassLoader(); 
     Package[] pkgs = Package.getPackages(); 
     s = console.readLine(); 
     if(s.equals(":exit")) 
     { 
      System.exit(0); 
     } 
     boolean classFound = false; 
     Object loadedClass = null; 
     String classname = ""; 
     for (int i = 0; i < pkgs.length; i++) { 
      Package package1 = pkgs[i]; 
      try 
      { 
       classname = package1.getName().replace('/', '.') + "." + s; 
       clsldr.loadClass(classname); 
       loadedClass = Class.forName(classname); 
       classFound = true; 
      } 
      catch(Exception e) 
      { 

      } 

     } 
     System.out.println("LOADED A CLASS!!!!"); 
     System.out.println(classname); 
     System.out.println(loadedClass); 
    } 
    while(s.length() == 0); 

。たとえば、プロンプトで「Object」と入力すると、何らかの形でsun.net.util.Objectをロードすることができますが、実際のオブジェクトをプリントアウトすると、class java.lang.Objectが印刷されます。私はStringと私がタイプしたいくつかの他のものと同じことを得る。私が試した興味深いものはintでした - それはsun.net.util.intをロードし、私がオブジェクトを印刷したときにnullを返しました。私はJavaをしようとしたときには、別のことが起こっ:

Java 
LOADED A CLASS!!!! 
sun.net.util.Java 
null 

誰もがここで何が起こっている任意の手掛かりを持っていますか?この原因となっているsun.net.utilパッケージには特別なものがありますか?私のコードは私が望むように正確に動作しないことに本当に気をつけません、私はちょうどこの奇妙な振る舞いの原因を知りたいです。

Javaバージョン:

java version "1.7.0_25"           
Java(TM) SE Runtime Environment (build 1.7.0_25-b17)    
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode) 

それはすべての違いを、私は、Windows 8 64ビットによ。

答えて

0

私は何かを考えました。私はクラスを外すときにループから抜け出ることはありません。だから、実際にはjava.lang.Objectになってクラスをtrueにロードするように設定していますが、ロードされた実際のクラスを上書きするループで続き、おそらくsun.net.utilが私のシステムにロードされた最後のパッケージです。私が必要とするのは、breakステートメントだけです。この動作を停止する必要があります。

+0

"奇妙な"クラスが最初に現れた場合、そのスキームが失敗することを除いて。またはどちらのクラスも「奇妙」でない場合。例えば'java.util.Date'と' java.sql.Date'です。 –

0

sunおよびcom.sunで始まるクラスは、JVM内部で使用される、主に文書化されていない「ハウスキーピング」クラスです。それらはJava APIの一部ではなく、異なるJVMは異なるものを持っています。 Reflection APIの完全修飾名を指定する必要がある理由は、これらの異なる内部構造すべてを見ているという事実です。 ;-)

+0

私はこのことを避けるために 'sun。*'パッケージと 'com.sun。* 'を無視するのが安全だと思いましたか?クラス/パッケージのルックアップを行う良い方法はありますか? – Logan

+0

どのような目的のためにですか?ちょうど実験のために? 'com.sun'を完全に無視することはできません。なぜなら通常、これらのクラスのいくつかは、通常はインターフェイスの背後にあります(例えば、' String'ルックアップキーで選択された暗号アルゴリズムの実装)。 SCTPライブラリIIRCも 'com.sun'にあり、直接使用されます。 – chrylis

+0

ええ、かなり。私はJavaインタープリタを作成する際に刺すようにしたいと思っていました:D – Logan

3

あなたのコードは、「奇妙な」クラスを戻しています。なぜなら、それは概念的に壊れているからです。 「rt.jar」ファイル内のエントリの物理的な順序はどのようなものであるべきかを指定するものはありません。彼らはちょうどあなたが反復をやっているやり方で与えられた "奇妙な"ものを見つける結果となる順序で起こります。別のJavaのリリースでは、あなたのコードは "奇妙ではない" Objectクラスを提供するかもしれません。いずれにしても、このように「正しい」クラスを取得するという前提は...欠陥です。

あなたが実装しようとしている場合はまあ

を「私はJavaインタプリタを作るのが刺しを撮りたかった」:あなたはので、これをやっていると言う


インタプリタの場合は、Java言語を理解する必要があります。 そして、あなたが理解しなければならないことの1つは、多くのクラスがJavaで同じ単純名を持つことができるということです。つまり、与えられた単純な名前を持つクラスのクラスパスをスキャンするという考え方は実用的ではありません。一般的に使用されるクラスには、あまりにも多くの「衝突」(つまり、同じ単純名を持つクラス)が存在することがわかります。

従来のJavaでは、この衝突の問題は、クラスを完全修飾名で参照するか、またはをインポートすることによって解決されます。インタープリタを使用できるようにするには、従来のJavaのインポートメカニズムを反映するインポート方式を実装する必要があります。

要するに、上のコードを捨ててもう一度やり直してください。

+0

私はこの答えを待っていました:)私が言ったように、このコードはちょうど実験のためのものでした。私は反射の経験がほとんどないので、足を濡らしたいと思っていました。また、私の質問は「なぜこのコードは奇妙なクラスを読み込むのですか」であり、「どうすれば修正できるのか」ではありませんでした。しかし、ヒントをお寄せいただきありがとうございます。私はおそらく再びインポートスキームのヘルプを依頼してくるでしょう:) – Logan

+0

私はあなたの質問の "なぜ"の部分に対処しました。 (私はそれが冗長だと思ったので私は前にはなかったが、あなたが主張しているから...) –

関連する問題