String.valueOf(null)がNullPointerExceptionをスローするのはなぜですか?


127

ドキュメントによると、メソッドString.valueOf(Object obj)は次を返します:

引数がの場合null、次に等しい文字列"null"。それ以外の場合は、の値obj.toString()が返されます。

しかし、私がこれをやろうとするとどうなりますか:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

代わりにNPEをスローしますか?(信じられない場合は自分で試してください!)

    スレッド「メイン」の例外java.lang.NullPointerException
    java.lang.String。(不明なソース)
    java.lang.String.valueOf(Unknown Source)で

なぜこれが起こっているのですか?ドキュメントは私に嘘をついていますか?これはJavaの大きなバグですか?

回答:


201

問題は、String.valueOfメソッドがオーバーロードされていることです。

Java仕様言語では、次のような場合に、最も具体的なオーバーロードを選択することが義務付けられています。

JLS 15.12.2.5最も具体的な方法の選択

複数のメンバーメソッドがアクセス可能であり、メソッド呼び出しに適用できる場合は、実行時メソッドディスパッチの記述子を提供するために1つを選択する必要があります。Javaプログラミング言語は、最も具体的なメソッドが選択されるという規則を使用します。

Aはchar[] -で Object、すべてではないObject です- char[]。したがって、char[]あるより具体的な以下Object、およびJava言語で指定され、String.valueOf(char[])過負荷、この場合に選択されます。

String.valueOf(char[])アレイは、非ことを期待nullし、以降nullこの場合には与えられ、それはその後、スローNullPointerException

簡単な「修正」は、次のようにnull明示的にキャストすることObjectです。

System.out.println(String.valueOf((Object) null));
// prints "null"

関連する質問


この話の教訓

重要なものがいくつかあります。

  • Effective Java 2nd Edition、Item 41:Use overloading思慮深く
    • オーバーロードできるからといって、毎回する必要があるわけではありません
    • それらは混乱を引き起こす可能性があります(特にメソッドが大きく異なることをする場合)
  • 適切なIDEを使用して、コンパイル時にどのオーバーロードが選択されているかを確認できます
    • Eclipseを使用すると、上記の式の上にマウスを置くと、実際valueOf(char[])オーバーロードが選択されていることがわかります。
  • 明示的にキャストしたい場合がありますnull(以下の例)

こちらもご覧ください


キャスト時 null

null特定の参照型に明示的にキャストする必要がある状況が少なくとも2つあります。

  • オーバーロードを選択するには(上記の例で指定)
  • 与えるにはnull可変引数パラメータに1つの引数として

後者の簡単な例は次のとおりです。

static void vararg(Object... os) {
    System.out.println(os.length);
}

次に、次のようにします。

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

こちらもご覧ください

関連する質問


5
別の提案:メソッドをオーバーロードし、2つのオーバーロード(nullこの場合など)で1つの引数を呼び出すことができる場合は、その値に関して両方のオーバーロードが同じように動作することを確認してください!
Joachim Sauer

3
@Joachim:アイテムを読んだだけで、これらの2つの方法が明示的に議論されていることを知ってうれしく思いました。Blochはさらに一歩進んで、それ以来String.valueOf(Object)valueOf(char[])とにかく完全に異なることをしていると主張しnullます。
polygenelubricants 2010年

質問があります... Objectを返すメソッドがある場合、ステートメントreturn null;return (Object) null;?とまったく同じになります。
user972276

17

問題は、あなたが電話String.valueOf(char[])をしているのであって、電話をしていない ことですString.valueOf(Object)

この理由は、Javaは常に、指定されたパラメーターで機能するオーバーロードメソッドの最も具体的なバージョンを選択するためです。nullObjectパラメーターの有効な値ですが、char[]パラメーターの有効な値でもあります。

JavaにObjectバージョンを使用させるにnullは、変数を介して渡すか、Objectへの明示的なキャストを指定します。

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));

5

2003年に、4867608の番号が付いたバグがこの方法で提出されましたが、この説明で「修正されない」と解決されました。

互換性の制約により、これを変更することはできません。呼び出されてしまうのはpublic static String valueOf(char data [])メソッドであり、null引数の「null」の置換については触れられていないことに注意してください。

@ ###。### 2003-05-23


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.