22

私は次のJavaソースファイル(Hello.java)を書きました:

package com;

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello!");
    }
}

これをに保存しC:/tmpjava/Hello.javaます。

コマンドラインから、そのディレクトリに移動してを実行しますjavac Hello.java。それから私は実行しますdir

  • Hello.class
  • Hello.java

次に、実行したのと同じディレクトリjavacから、次のコマンドを実行java Hello.classして取得します。

Exception in thread "main" java.lang.NoClassDefFoundError: Hello/class
Caused by: java.lang.ClassNotFoundException: Hello.class
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: Hello.class.  Program will exit.

何が起きてる?!?どのようjavacにうまく実行できますが、そうではありませんjavaか?

4

5 に答える 5

50

クラスHelloはパッケージに属していますcom。したがって、クラスの完全修飾名はですcom.Hello。コマンドラインでjavaを使用してプログラムを呼び出すときは、次のように、メソッドを含むクラスの完全修飾クラス名を指定し、 .classmainを省略する必要があります。

java com.Hello

Javaプログラムでは、参照しているクラスを理解するために、この完全修飾クラス名が必要です。

しかし、別の問題があります。Javaプログラムは、ファイルシステムを使用して、パッケージ、サブパッケージ、およびそれらに属するクラスを検索します。したがって、のようなパッケージ構造がある場合、Javaプログラムは、 com / Hello.classのように、comという名前のディレクトリでHello.classcom.Helloという名前のクラスファイルを見つけることを想定しています。実際、あなたはあなたが見るものの中でこの振る舞いを観察することができます。Javaがという名前のパッケージとして解釈しているHello.classと、という名前のクラス誤って使用し、ディレクトリ構造Hello/classを探しています。ExceptionHelloclass

java.lang.NoClassDefFoundError:Hello / class

ただし、コンパイラjavacは、デフォルトではこのディレクトリ構造を設定しません。javacのドキュメントを参照してください。ただし、重要な点は次のとおりです。コンパイルを実行するときに、-dフラグを使用して宛先ディレクトリを指定できます。

-dディレクトリ

クラスファイルの宛先ディレクトリを設定します。宛先ディレクトリはすでに存在している必要があります。javacは宛先ディレクトリを作成しません。クラスがパッケージの一部である場合、javacはクラスファイルをパッケージ名を反映するサブディレクトリに配置し、必要に応じてディレクトリを作成します。たとえば、-dc:\ myclassesを指定し、クラスの名前がcom.mypackage.MyClassの場合、クラスファイルの名前はc:\ myclasses \ com \ mypackage\MyClass.classになります。

-dが指定されていない場合、javacはクラスファイルをソースファイルと同じディレクトリに配置します。

太字の最後のビットは、初心者にとって多くの混乱の原因であり、あなた自身の問題の一部です。

したがって、2つの選択肢があります。

  1. あなたの場合、次のように現在のディレクトリを宛先ディレクトリとして指定すれば問題ありません(ピリオド.現在のディレクトリを意味します)。

    javac -d . Hello.java
    

    このようにコンパイラを呼び出すと、comディレクトリが作成され、コンパイルされたクラスファイルがその中に配置されます。これは、Javaプログラムが期待する方法です。次に、上記のようにc:\ tmpJavaからjavaを実行すると、プログラムが実行されます。

  2. パッケージ構造を反映したディレクトリ構造を使用してソースコードを設定できます。ソースファイルHello.javaをcomというディレクトリ内に配置します。この場合はc:\ tmpJava \ com\Hello.javaです。これで、 c:\ tmpJavaから、次のようにjavacコンパイルを実行できます。

    javac com\Hello.java
    

    フラグを指定していません-dが、ディレクトリ構造を自分で作成し、上記のドキュメントから再度引用しているため、問題ありません。

    -dが指定されていない場合、javacはクラスファイルをソースファイルと同じディレクトリに配置します。

    繰り返しますが、上記のようにJavaを実行すると、プログラムが実行されます。

    この2番目の選択肢は、Javaプログラマーが一般的に採用しているものであることに注意してください。ソースコードファイルは、パッケージ構造を反映したディレクトリ構造で編成されています。

この説明では、クラスパスの概念を無視しました。Javaプログラムを作成するには、それを理解する必要もありますが、現在のディレクトリでプログラムをコンパイルするだけの場合、クラスをコンパイルするときに上記の2つの方法のいずれかに従うと、クラスパスを設定せずに回避できます。 、デフォルトでは、Javaプログラムは現在のディレクトリをクラスパスとして持っています。別の引用、これはjavaのドキュメントからのものです:

-cpクラスパス

クラスファイルを検索するディレクトリ、JARアーカイブ、およびZIPアーカイブのリストを指定します。クラスパスエントリはセミコロン(;)で区切られます。-classpathまたは-cpを指定すると、CLASSPATH環境変数の設定が上書きされます。

-classpathと-cpが使用されておらず、CLASSPATHが設定されていない場合、ユーザークラスパスは現在のディレクトリ(。)で構成されます。

EclipseなどのIDEを使用してJavaコードを実行する場合、これはほとんどの場合処理されますが、クラスパスの問題が発生することに注意してください。

于 2012-08-23T16:29:31.037 に答える
14

Javaコマンドの構文は次のとおりです。

java [classname]

いいえ

java [filename]

Javaは、クラスパスで、指定した名前のクラスを探します。通常、クラスパスには現在のディレクトリが含まれているため、次のようになります。

java Hello

...現在のディレクトリでHello.classを見つけ、そのmain()メソッドを実行します。

ただし、クラスが別の場所(.jar内、またはファイルシステム内の他の場所など)にある場合は、CLASSPATH環境変数またはコマンドラインで指定できます。

java -cp build/classes Hello
java -cp build/jars/myjar.jar Hello
于 2012-08-23T16:24:43.630 に答える
4

クラスはにある必要がありますC:\tmpjava\com\Hello.class
そしてあなたはから実行する必要がありますC:\tmpjavajava -cp . com.Hello
あなたがクラスをパッケージに入れるとき、それはクラスのファイル構造を定義します。つまり、パッケージ内のクラスcomはフォルダ内にある必要がありますcom

于 2012-08-23T16:19:28.003 に答える
2

次のコマンドを実行します

java -cp . com.Hello
于 2012-08-23T16:20:25.207 に答える
1

java -classpath c:\ tmpjava com.Hello

于 2012-08-23T16:22:27.217 に答える