「単純な」Javaに関する2つの質問



読者の皆様、ご挨拶。

Javaは興味深く、美しい言語です。 しかし時々、それを見ない方が良いと書かれていることがあります。 しかし、そのような曲線、ケースで何が起こるかを知ることは依然として有用です。

きれいなコードの愛好者、すみません。



むかしむかし、ハブに関する記事がいくつかありました -興味深いJavaの問題があるJava書かないこと

パート1パート2

それらは非常に興味深いものですが、残念ながら、著者は継続しませんでした。



さらに2つのタスクを紹介します(それ以上の強度はありませんでした。記事を書くのはそれほど簡単ではないことがわかりました)。



もちろん、記事の最後には、説明を含む回答と、最強のための追加のタスクがあります。





最初のタスクは、Joshua Bloch Java Puzzlersによる素晴らしい本からきれいに取り上げられています。 この本はコードの書き方を教えているのではなく(むしろ、逆に、どうして必要ないのか、なぜか)、教えているわけではありませんが、個人的にそれを読むのはとても面白かったです。 ただ楽しみのために。 お勧めです。





それでは始めましょう。



条件



1.実行は許されません


public class A { public static class X { public static class Y { public static String Z = "life is good"; } public static CY; } public static class C { public static String Z = "life is pain"; } public static void main(String[] args) { System.out.println(XYZ); } }
      
      





どうなるの?
  1. コンパイルエラー
  2. ランタイムエラー
  3. 人生をもたらすでしょう良いです
  4. 人生は痛みをもたらすでしょう
これに加えて、名前を変更せずに、[答えが1/2の場合はエラーを修正して] 両方の行を印刷する方法







2.ジェネリックはそのようなジェネリックです




  public class B { public static <T> T foo() { try { return (T) new Integer(42); } catch (ClassCastException e) { return (T) "habr"; } } public static void main(String[] args) { System.out.println(B.<String>foo()); } }
      
      





どうなるの?
  1. コンパイルエラー
  2. ランタイムエラー
  3. 出力42
  4. habrを出力します








そして今、正しい答え:





1.実行は許されません


 public class A { public static class X { public static class Y { public static String Z = "life is good"; } public static CY; } public static class C { public static String Z = "life is pain"; } public static void main(String[] args) { System.out.println(XYZ); } }
      
      



人生は痛みをもたらすでしょう

すべてがワイルドですが、シンプルです。 はい、jlsはこれを許可します。 優先順位は常にフィールドにあります。



さらに興味深いのは、これを回避し、人生を豊かにする方法です。 私は3つの解決策を知っています:

トップ5の探求


後者の方法は優れていますが、オブジェクトを作成する必要があり、これは悪いことです。 プライベートコンストラクターを追加します。 (反射および静的インポートなし)
  public static class X { public static class Y { private Y() {} public static String Z = "life is good"; } public static CY; }
      
      



答えは:
非表示のテキスト
  ((XY)null).Z; //   ,  Java.
      
      









2.ジェネリックはそのようなジェネリックです
  public class B { public static <T> T foo() { try { return (T) new Integer(42); } catch (ClassCastException e) { return (T) "habr"; } } public static void main(String[] args) { System.out.println(B.<String>foo()); } }
      
      



ランタイムエラー 、またはClassCastException



そのため、javaジェネリックでは構文糖にすぎないことを知っています 。これにより、 機能制限されコンパイラが追加の型チェックを実行できるようになります。 しかし、プログラムが起動されるとすぐに、パラメータークラスに関するすべての情報が失われます。 悲しいかな、これはc ++でもc#でもありません。



コードをよく見てください:



 System.out.println(B.<String>foo());
      
      





コンパイラは、引数の型がStringであることを理解しているため、最適なprintlnを置き換えます。



 public void println(String x)
      
      





使用するオーバーロードメソッドのバージョンを決定することは、ランタイムではなくコンパイルレベルのタスクであることが重要です。



どうぞ



 return (T) new Integer(42);
      
      





キャストは、ジェネリックがなくなったときに実行時に発生します。

どうなるの?

なし。 整数は単に戻ります。



さて、ここにあります-printfを呼び出します。これはStringを受け取り、Integerを渡します。



未来への教訓


トップ5の探求


thowsまたはtry-catchを必要としない任意のThrowable(チェック済み例外を含む)をスローするメソッドを実装します。



 public static void throwWithoutCheck(Throwable t) { //  ,  .  throwWithoutCheck(new Exception()) -   throws! }
      
      



答えは:
非表示のテキスト
  private static <T extends Throwable> void castAndThrow(Throwable t) throws T { throw (T) t; } public static void throwWithoutCheck(Throwable t) { B.<RuntimeException>castAndThrow(t); }
      
      







UPD:

チェックせずに出口をスローする方法はまだあります。 これらは答えを意味するものではありませんでしたが、もっと「正直」に言ってみましょう。



 Thread.currentThread().stop(new IOException());
      
      





stopは@deprecatedであることに注意してください。 ストリームでの作業の概念は大幅に変更され、 草は緑になり、空気はきれいになりました

停止の引数として、停止の「理由」を渡すことができます。 Javaでは、原則として、try catchブロックでこれを結論付けることはできません。ここですべてが明確であることを願っています。

について orionllに感謝します。





または:

 Unsafe.getUnsafe().throwException(new IOException());
      
      





ここでもすべてが明らかです。Unsafeで作業することは不可能であり、この場合、すべてが完全に正当化されます。

についてはミスハドフに感謝します。



All Articles