5
4

More than 1 year has passed since last update.

『徹底攻略 Java SE 11 Gold 問題集』の補足

Last updated at Posted at 2023-03-03

徹底攻略Java SE 11 Gold問題集[1Z0-816]対応で勉強した際に調べた結果を共有いたします。

1章 問題 1

解説で「static インナー クラス」という用語が使われていますが、これは厳密には不正確な表現です。Java 言語仕様には以下のように記述されています。

An inner class is a nested class that is not explicitly or implicitly declared static.

つまり、static なネステッド クラスのことを「インナー クラス」とは呼ばないのです。

本件は『プロになる Java』と説明が違っていたために気がつきました。『プロになる Java』「14.1.6 ネステッドクラスとインナークラス」では以下のように説明されていました。

クラスの中で定義するクラスをネステッドクラスといいます。

static が付いていないクラスはインスタンスクラスとは呼ばずにインナークラスといいます。static クラスは正式な用語ではありませんが、static なネステッドクラスを表す場合に使われます。

言語仕様と照らし合わせると、『プロになる Java』の説明のほうが正確な記述だと言えます。

1 章 問題 5

Java 15 までは、static でないネステッド クラスに static フィールドは持てず、コンパイル エラーになります。

class Outer {
    class Inner {
        static int field;
    }
}

詳しいことは知らないのですが、レコード クラスで問題があったため Java 16 で許容されるようになっていました。

1 章 問題 11

Java 言語仕様には以下の記述があります。

  • If the form is TypeName . super . [TypeArguments] Identifier, then:
    (中略)
    • Otherwise, TypeName denotes the interface to be searched, I.

      Let T be the type declaration immediately enclosing the method invocation. It is a compile-time error if I is not a direct superinterface of T, or if there exists some other direct superclass or direct superinterface of T, J, such that J is a subtype of I.

問題集の interface A は直接のスーパーインターフェースになっていて、他の直接のスーパーインターフェースは A のサブタイプではないので、この形式でデフォルト メソッドを呼び出すことができます。

コンパイル エラーになるのは次の2つの場合です。

I が T の直接的なスーパーインターフェースでない

以下のような場合です。JEP 330: Launch Single-File Source-Code Programs の java コマンドをインタープリターのように使う方法で試しやすいように、main クラスを一番上に書いています。

public class T implements J {
    public static void main(String[] args) {
        new T().methodAtT();
    }
    void methodAtT() {
        I.super.method();
    }
}

interface J extends I {}

interface I {
    default void method() {
        System.out.println("I");
    }
}

I 以外に T の直接的なスーパークラスか直接的なスーパーインターフェース J があり、それが I のサブタイプである。

これは以下のような場合です。

public class T implements I, J {
    public static void main(String[] args) {
        new T().methodAtT();
    }
    void methodAtT() {
        I.super.method();
    }
}

interface J extends I {}

interface I {
    default void method() {
        System.out.println("I");
    }
}

13 章 問題 8

この挙動が仕様として納得できなかったので検索してみたところ、StackOverflow に同様の質問がありました。

これはバグで、現在も open になっています。

13 章 問題 33

私は並列処理が苦手なのですが、設問のプログラムは hello メソッド内でもう一方の Sample インスタンスでロックしようとしていないので、デッドロックは起きないように思います。設問の main メソッドはスレッドの終了を待たずに正常終了してしまうので、ExecutorService を使って、shutdown() の後に awaitTermination(1L, TimeUnit.Days) としてみたのですが、手元ではデッドロックは発生しませんでした。

可能性としては、次のようにしてプログラムが止まることはあると思いますが、これはロックの取得待ちで止まっているわけではないので、デッドロックではないはずです。

  1. スレッド1が s1.hello() を実行し、s1.test が非 null になる
  2. スレッド2がスレッド1が書き換えた s1.test を参照し、非 null なので、while ループを抜けられない
  3. スレッド1が s1.bye() を実行し、スレッド1では s1.test が null に戻る
  4. スレッド2が、s1.test が volatile でないのでスレッド1が更新した値を読むことができず、非 null の値を読み続けて while ループを抜けられない

最後に

合格には上記のような知識は必要ありませんが、どなたかのお役に立てれば幸いです。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4