

`Fn`という名前の`interface`を作ったのですが、`NoClassDefFoundError`になりました。

[code]

    interface Fn {
      void f();
    }
    
    class fn implements Fn {
      void f(){ println("default"); }
    }
    
    void setup(){
      fn _fn = new fn(){
        public void f(){ println("hello"); }
      };
    
      func(_fn);
    }
    
    void func(Fn fn){
      fn.f();
    }
    
[/code]

`interface`の名前を別のもの変えると動いたのですが、`Fn`は予約語のようなものなのでしょうか？調べてみても、ProcessingでもJavaでも`Fn`というキーワードはないように思えるのですが、これは書き方が間違っていたりするのでしょうか。それとも使えない名前なのでしょうか。  
詳しい方教えてください。


CC BY-SA 4.0
2019-03-29T21:48:19.487
53807
2019-05-02T09:09:37.810
2019-03-30T00:51:08.423
2238
29682
question
java processing
`interface Fn`について、予約語を使っていますか？


おそらくWindows環境(またはそれに類する環境)で開発をされていると推測しますが、

`Fn` という名前自体に問題があるわけではなく、 同一package(directory)内に `Fn` と `fn`
という、大文字/小文字を区別しなかった場合に、同じ文字列となる名前のclass(やinterface)が存在するためです。

そのため、`Fn`と`fN`、`F`と`f`という名前にしても同じ現象が発生します。

以下のような例で説明します。

**Main.java**

[code]

    public class Main {
        public static void main(final String[] args) {
            fn value = new fn();
    
            value.f();
        }
    }
    
    interface Fn {
        void f();
    }
    
    class fn implements Fn {
        @Override
        public void f() {
            System.out.println("default");
        }
    }
    
[/code]

これを `javac Main.java` でコンパイルすると同一ディレクトリに以下のファイルが生成されます。

[code]

    - Fn.class
    - Main.class
    
[/code]

そして `java -cp . Main` で実行すると、以下のエラーが表示されます。

[code]

    Exception in thread "main" java.lang.NoClassDefFoundError: Fn (wrong name: fn)
            at java.lang.ClassLoader.defineClass1(Native Method)
            at java.lang.ClassLoader.defineClass(Unknown Source)
            at java.security.SecureClassLoader.defineClass(Unknown Source)
            at java.net.URLClassLoader.defineClass(Unknown Source)
            at java.net.URLClassLoader.access$100(Unknown Source)
            at java.net.URLClassLoader$1.run(Unknown Source)
            at java.net.URLClassLoader$1.run(Unknown Source)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at java.lang.ClassLoader.defineClass1(Native Method)
            at java.lang.ClassLoader.defineClass(Unknown Source)
            at java.security.SecureClassLoader.defineClass(Unknown Source)
            at java.net.URLClassLoader.defineClass(Unknown Source)
            at java.net.URLClassLoader.access$100(Unknown Source)
            at java.net.URLClassLoader$1.run(Unknown Source)
            at java.net.URLClassLoader$1.run(Unknown Source)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at Main.main(Main.java:3)
    
[/code]

これは、`Main.java:3` で `fn` を使用していますが、`fn.class`というファイルが存在しないためです。

Windowsでは同一ディレクトリ内に大文字/小文字が異なるだけの同じファイル名を作れないため、`fn.class`が生成されず、`NoClassDefFoundError`が発生します。

* * *

**余談1**

Linuxやそれに類する環境では、この問題は発生しません。  
(Linux上のProcessingで発生しないかは、試してないのでわかりません)

[code]

    > docker pull java:8
    > docker run -it --name java-sand-box -v D:\Main.java:/Main.java java:8
    root@45c1697cb501:/# javac Main.java
    root@45c1697cb501:/# ls -lt | grep "\.class"
    -rw-r--r--   1 root root  389 May  2 08:50 fn.class
    -rw-r--r--   1 root root  105 May  2 08:50 Fn.class
    -rw-r--r--   1 root root  300 May  2 08:50 Main.class
    root@45c1697cb501:/# java -cp . Main
    default
    
[/code]

* * *

**余談2**

JavaのTypeは大文字の英字から始める、という規約がありますので、規約通りに命名してコーディングをしている限り、この問題が発生することはありません。


CC BY-SA 4.0
2019-05-02T09:09:37.810
54653
2019-05-02T09:09:37.810
3068
53807
answer