Fukuoka Univ. / 中西恒夫 — Final Exam Prep

オブジェクト指向プログラミング
期末試験 対策シート

過去問2年分の全問解答+解説。参照の共有(エイリアス)==とequals抽象クラスと多態例外の4本柱が毎年出ています。

R7 / 2025-07-29 出題 R6 / 2024-07-30 出題 問1 ○× × 10 / 問2 出力予測 × 5 / 問3 穴埋め / 問4 バグ修正 2026年度 講義資料 239p 照合済
問題 1

Java・OOPの記述の ○×

2025

int型の値とdouble型の値を加算した結果はdouble型となる。

数値の二項演算では「広い方の型」に自動的に格上げされる(数値昇格)。int + double → doublebyte/short/char同士の演算はintになる点もセットで覚える。

×

if文の条件式に整数型の式を書くと、0以外なら真、0なら偽として実行される。

それはC/C++の話。Javaのbooleanは数値と完全に別の型で、if (n)コンパイルエラー(型の不一致)。if (n != 0) と書く必要がある。

×

すべてのクラスに共通の上位クラスの名前は Null である。

正しくは java.lang.Objectnull は「どのオブジェクトも指していない」参照値であってクラス名ではない。toString()/equals()/hashCode()/getClass() が全クラスで使えるのはObjectから継承しているため。

String の文字列 a と b の内容が同じか比較するには a.equals(b) と書くべきである。

==参照(アドレス)の一致を見るので、内容が同じでも別インスタンスなら false。内容比較は必ず equalsこの論点は問題4でもう一度出る。

LinkedList<Object> にはありとあらゆるクラスのインスタンスを入れることができる。

全クラスは Object の下位クラスなので、Object型の要素にはどんな参照でも代入できる。int等の基本型もオートボクシングで Integer 等になって入る。

×

クラスXの(型の)変数に、Xの上位クラスの参照を代入することは許されている。

代入できるのは 下位クラス → 上位クラス(アップキャスト)の向きだけ。逆向き(ダウンキャスト)は X x = (X) obj; と明示キャストが必要で、実体が違えば実行時に ClassCastException
「Sphere は Shape である」は成り立つが、「Shape は Sphere である」とは限らない、と日本語で唱えると間違えない。

Integer クラスは int 型のラッパクラスである。

基本型をオブジェクトとして扱うための包み。int→Integer, double→Double, char→Character, boolean→Boolean。ジェネリクス(LinkedList<Integer>)には基本型を直接書けないので必要になる。

「void foo(int a, int b)」と「void foo(int a, double b)」の2つを定義してよい。

引数の型・個数・並びが違えばオーバーロード(多重定義)として共存できる。NG例:戻り値の型だけが違う場合はコンパイルエラー。

抽象クラスのインスタンスを生成することはできない。

中身のないメソッド(抽象メソッド)を含みうるので実体化不可。new AggOp() はコンパイルエラー。ただし抽象クラス型の変数を持って下位クラスのインスタンスを入れるのはOK(これが多態の土台)。

コンストラクタ実行時、特に断らなければ上位クラスの引数なしコンストラクタが呼ばれる。

コンストラクタの先頭に super(...)this(...) も書かなければ、コンパイラが暗黙に super(); を挿入する。上位クラスに引数なしコンストラクタが無いとコンパイルエラーになる。問題2小問3がまさにこれ。

問題 2

実行結果(出力文字列)を答える

2025

小問1 — switch の複数ラベルと default

for (int i = 0; i < 8; i++) {
  switch (i) {
    case 1, 2, 4, 8: System.out.print(i);     break;
    case 3, 7:       System.out.print(i * 2); break;
    default:         System.out.print(i * 4);
  }
}
解答

01264202414

i=00default
i=11case
i=22case
i=36×2
i=44case
i=520×4
i=624×4
i=714×2

printprintlnではない)なので改行なしで全部つながる。case 1, 2, 4, 8: は Java 14 以降のカンマ区切り複数ラベル。i<8 なので case 8 には一生到達しないのがひっかけ。

ワナ:数字の並びを「0,1,2,6,4,20,24,14」とカンマ付きで書かないこと。区切り文字は出力されないので 01264202414 の11文字。

小問2 — 配列要素の参照代入(今年もほぼ確実に出る型)

Q2[] a = new Q2[4];
a[0] = new Q2("こぶた"); a[1] = new Q2("たぬき");
a[2] = new Q2("きつね"); a[3] = new Q2("ねこ");
a[1] = a[2];              // 参照のコピー:同じ1個のオブジェクトを2箇所が指す
a[1].setMessage("いぬ");  // その共有オブジェクトを書き換える
for (int i = 0; i < a.length; i++) System.out.println(a[i].getMessage());
解答

こぶた いぬ いぬ ねこ

配列 a(参照の箱) ヒープ上のQ2オブジェクト a[0] a[1] a[2] a[3] msg = "こぶた" msg = "いぬ" "たぬき"(GC対象) msg = "ねこ"
a[1] = a[2]; の瞬間、「たぬき」を指す唯一の参照が消えて回収対象に。以後 a[1] と a[2] は同一の1個を指すので、片方を書き換えると両方が変わって見える。
覚え方:Javaの代入で複製されるのは矢印だけ。箱(オブジェクト)は複製されない。a[1] = a[2] は「a[2]の指す先を、a[1]にも指させる」。

小問3 — コンストラクタの連鎖(暗黙のsuper())

class Hoge {
  public Hoge()      { System.out.println("hoge1"); }
  public Hoge(int n) { System.out.printf("hoge%d\n", n); }
}
class Fuga extends Hoge {
  public Fuga()             { System.out.println("fuga1"); } // 暗黙で super() が入る
  public Fuga(int n)        { super(n); }
  public Fuga(int a,int b)  { }                              // 暗黙で super() が入る
}
Hoge h1 = new Fuga();      Hoge h2 = new Fuga(9);      Hoge h3 = new Fuga(2, 3);
解答

hoge1 fuga1 hoge9 hoge1

呼ばれる順出力
new Fuga()暗黙 super() → Hoge() を実行 → その後 Fuga() の本体hoge1 / fuga1
new Fuga(9)明示 super(9) → Hoge(int) のみ。Fuga(int) 本体は空hoge9
new Fuga(2,3)暗黙 super() → Hoge()。Fuga(int,int) 本体は空hoge1
3つの鉄則:super(...)/this(...) はコンストラクタの先頭にしか書けない ②書かなければ暗黙で super()(引数なし)が入る ③親が先、子が後に実行される。
また Hoge h1 = new Fuga(); のように変数の型は Hoge、実体は Fuga という書き方も頻出(多態)。

小問4 — static フィールドはインスタンス間で共有

class MyInt {
  private static int n = 0;   // クラスに1個しかない
  private int a;              // インスタンスごとに1個
  public MyInt(int _a) { a = _a; n++; }
  public void dump() { System.out.printf("%d,%d;", n, a); }
}
MyInt a = new MyInt(3);  MyInt b = new MyInt(7);
a.dump();  b.dump();
解答

2,3;2,7;

コンストラクタが2回呼ばれた時点で n は 2。n は static なので a からも b からも同じ 2 が見える。一方 a(インスタンス変数)は各オブジェクト固有なので 3 と 7。

ワナ:「1,3;2,7;」と答えてしまう人が多い。dump() が呼ばれるのは2個生成し終わった後。生成時点の値ではなく、出力時点の共有値を書く。

小問5 — try / catch / finally

public void check() throws Exception {
  if (n < 0) throw new Exception("負の数");
  System.out.println(n);
}
...
Q5 a = new Q5(8);  Q5 b = new Q5(-4);
try { a.check();  b.check(); }
catch (Exception ex) { System.out.println(ex.getMessage()); }
finally { System.out.println("おわり"); }
解答

8 負の数 おわり

  1. a.check() → n=8 は正なので 8 を出力して正常終了。
  2. b.check() → n=-4 で throwそこで try ブロックを即座に脱出(残りは実行されない)。
  3. catch に飛び、getMessage() が例外生成時の文字列 "負の数" を返す。
  4. finally は例外の有無にかかわらず必ず実行 → おわり
getMessage() の正体:new Exception("負の数") でコンストラクタに渡した文字列がそのまま返る。「例外クラス名」ではない。
問題 3

抽象クラス AggOp / Adder / Multiplier の穴埋め

2025

小問1:空欄①〜⑩

空欄入るコード理由
abstract「AggOp は抽象クラスである」+抽象メソッド calc() を持つため必須。
LinkedList<Integer>「リンクによる線形リスト」=LinkedList。中身は int のラッパ=Integer。
newlis = new LinkedList<Integer>(); 生成して代入。
abstract本体{}がなく;で終わっている=抽象メソッド宣言。
throws Exception「calc() は Exception を発生し得る」。宣言側・実装側の両方に同じものが入る。
extends AggOpAdder / Multiplier はいずれも AggOp から派生。
Integer a : lis拡張for文。for (Integer a : lis) で全要素を走査。
a.intValue()Adder側の result += a.intValue(); と対応させる(a だけでも自動開梱されるが、対称に書くのが模範解答)。
try下に ⑩ (Exception ex) が続くので try ブロック。
catch例外を受ける。

完成イメージ(要点だけ)

public abstract class AggOp {
  protected LinkedList<Integer> lis;
  protected static int max = 100;
  public AggOp() { lis = new LinkedList<Integer>(); }
  public abstract int calc() throws Exception;
  public void add(int a) { lis.add(new Integer(a)); }
}
public class Adder extends AggOp {
  public int calc() throws Exception {
    int result = 0;
    for (Integer a : lis) {
      result += a.intValue();
      if (result > max) throw new Exception("Too big");
    }
    return result;
  }
}
ここで落とす人が多い:③に new LinkedList<Integer>() 全部を書くと new が二重になる(空欄の直後に LinkedList<Integer>(); が既にある)。空欄の前後に既に書かれているコードを必ず読むこと。

小問2:実行結果

解答

55 Too big

  • adder:1+2+…+10 = 55。途中の最大値も55で、max = 100 を超えないので例外なし → 55 を出力。
  • multiplier:1→2→6→24→120 と進み、5を掛けた時点で 120 > 100throw new Exception("Too big")
  • 例外は main の try を抜けて catch へ。System.out.println(adder.calc()) は既に済んでいるので 55 は表示済み、multiplier.calc() の結果は表示されない。
ポイント:maxstatic なのは「全インスタンス共通の上限値」を表すため。adder と multiplier は別インスタンスだが同じ 100 を見ている。
問題 4

コンパイルは通るが仕様通りに動かないコードの修正

2025 / 新傾向

仕様:①10個の文字列を配列に読み込む ②入力された文字列が①の中にあれば「Found」、なければ「Not Found」 ③②を繰り返す。

バグは3か所

#該当箇所症状修正
1public App() { }配列 str が生成されていない(null)。最初の str[0]=...NullPointerExceptionstr = new String[10];
2i <= 10(2か所)0〜10 の11回回る。仕様は10個。さらに要素数10の配列に対し ArrayIndexOutOfBoundsExceptioni < 10(または i < str.length)
3str[i] == s== は参照比較。Scanner が返す文字列は毎回別インスタンスなので常に false=いつも「Not Found」。str[i].equals(s)

修正後のコード

import java.util.Scanner;
public class App {
  private String[] str;

  public App() {
    str = new String[10];            // ← 追加:配列の実体を生成
  }

  public void run() {
    Scanner scanner = new Scanner(System.in);
    String s;

    for (int i = 0; i < 10; i++) {   // ← <= を < に
      System.out.printf("%d 個目の文字列を入力してください。> ", i + 1);
      str[i] = scanner.next();
    }

    OuterLoop:
    while (true) {
      System.out.print("検索する文字列を入力してください。> ");
      s = scanner.next();
      for (int i = 0; i < 10; i++) { // ← <= を < に
        if (str[i].equals(s)) {      // ← == を equals に
          System.out.println("Found");
          continue OuterLoop;
        }
      }
      System.out.println("Not Found");
    }
  }

  public static void main(String[] arg) { new App().run(); }
}
ラベル付き continue は正しい:continue OuterLoop; は内側forを抜けて while の先頭に戻る=「Foundを表示したら次の検索へ」で仕様通り。ここは直さなくてよい。「必要最小限の変更」なので、余計な書き換えは減点対象。
答案に書くときのコツ:「どこを・どう直したか」が採点者に一目でわかるよう、該当行に矢印と修正後のコードを書き込む。3か所すべて指摘して満点。
問題 1

Java・OOPの記述の ○×

2024

Javaのプログラムは静的メソッド main から実行が開始される。

正確には public static void main(String[] args)。インスタンス生成前に呼ばれる必要があるので static。

×

Javaでは0はfalse、0以外の整数はtrueとして扱われる。

それはC言語。Javaの boolean は数値と互換性がなく、暗黙変換もされない。2025年度①②と完全に同じ論点。

int型とdouble型を掛け算した結果はdouble型となる。

数値昇格。int / int だけは int のまま切り捨てになるので要注意(問題3小問2の伏線)。

×

String型の変数 s に "Hello" が入っているか確認する条件式は s == "Hello" となる。

参照比較になってしまう。正しくは s.equals("Hello")より安全なのは "Hello".equals(s)(sがnullでも落ちない)。

×

大きさ10の配列変数を宣言するには「int a[10];」と記述する。

Javaは宣言と実体生成が分かれる。int[] a = new int[10];。宣言部に要素数は書けない(int a[]; という書き方自体は可だがサイズは不可)。

クラスXの(型の)変数に、Xの下位クラスの参照を代入することは許されている。

アップキャストは常に安全なので暗黙に可能。これが ArrayList<Shape> に Sphere も Cube も入れられる理由(問題3)。2025⑥は「上位クラス」で×。方向を必ず確認。

static でないフィールドは、new で生成されGCで消えるまでメモリ上に存在する。

インスタンス変数の寿命=オブジェクトの寿命。どこからも参照されなくなった時点でGCの回収対象になる(2025問題2小問2の「たぬき」がまさにこれ)。

クラスXのコンストラクタは、new演算子でXのインスタンスを生成したときに呼び出される。

領域確保 → フィールド初期化 → コンストラクタ実行、の順。

×

同一クラス中に comp(int,int) と comp(double,double) を定義してはならない。

引数の型が違うのでオーバーロードとして定義してよい。禁止されるのは「引数が同一で戻り値型だけ違う」ケース。

抽象クラスのインスタンスを生成することはできない。

2年連続同じ問題。確実に○。

問題 2

実行結果(出力文字列)を答える

2024

小問1 — 累積和のトレース

int sum = 0;
for (int i = 0; i <= 5; i++) {
  sum += i;
  System.out.print(sum);
  System.out.print(",");
}
解答

0,1,3,6,10,15,

i=00
i=11
i=23
i=36
i=410
i=515
ワナ2つ:i <= 5 なので6回回る ②カンマは毎回出力されるので末尾にもカンマが付く15で終わらせない。

小問2 — 参照代入と「後からの差し替え」

a = new String[3];
a[0] = "kobuta";
a[1] = a[0];      // この時点の a[0] が指す "kobuta" を a[1] も指す
a[2] = "tanuki";
a[0] = "kitsune"; // a[0] の矢印を張り替えるだけ。a[1] は無関係
for (...) System.out.print(a[i]);
解答

kitsunekobutatanuki

配列 a String オブジェクト a[0] a[1] a[2] "kitsune" "kobuta" "tanuki"
2025年度小問2の「逆パターン」。あちらは共有オブジェクトの中身を書き換え(両方変わる)、こちらは変数の矢印を張り替え(片方だけ変わる)。この2つの違いが分かれば全問正解できる。
判別法:a[0] = ...矢印の張り替え=その変数だけ変わる。a[0].setXxx(...)箱の中身の書き換え=その箱を指す全員に影響。

小問3 — 抽象クラスによる式ツリー(Compositeパターン)

ArithOp a = new Constant(3);      // 3
ArithOp b = new Constant(2);      // 2
ArithOp c = new AddOp(a, b);      // (3 + 2) = 5
ArithOp d = new MulOp(b, c);      // 2 * (3 + 2) = 10
System.out.print(d.comp());
解答

10

d.comp() は再帰的に呼ばれる:

d.comp()  = b.comp() * c.comp()
          = 2 * ( a.comp() + b.comp() )
          = 2 * ( 3 + 2 )
          = 10
着眼点:変数の型はすべて ArithOp なのに、実行される comp()実体のクラス(Constant / AddOp / MulOp)のもの。これが動的束縛(多態)。呼び出し側が種類を意識せず一律に comp() と書けるのが抽象クラスの利点。

小問4 — 例外でループが途中終了する

try {
  for (int a = 2; a >= -2; a--) {
    Division div = new Division(8, a);
    System.out.print(div.comp());   // b==0 で Exception
  }
}
catch (Exception ex) { System.out.print(ex.getMessage()); }
finally { System.out.print("finished."); }
解答

48div by zero;finished.

a8 / a出力
244
188
0例外 throw(ループ脱出)
-1, -2到達しない
ワナ:例外が出た時点でforループごと抜ける(次の周回には進まない)。-8, -4 は出力されない。最後に finally の finished.(ピリオド込み)を忘れずに。すべて print なので1行に連結。

小問5 — 同一オブジェクトを2回操作してしまう

Q5[] ary = new Q5[3];
ary[0] = new Q5(3);
ary[1] = new Q5(-3);
ary[2] = ary[1];               // ary[1] と ary[2] は同一オブジェクト
for (int i = 0; i < ary.length; i++) ary[i].inverse();   // 3回 inverse される
for (int i = 0; i < ary.length; i++) System.out.print(ary[i].getval());
解答

-3-3-3

ary[0] ary[1] ary[2] n: 3 → -3(1回) n: -3 → 3(i=1) → -3(i=2)
オブジェクトは2個しかない。2個目は inverse() を2回受けて元に戻り -3。結果、3つとも -3 を表示する。
ワナ:「-3 3 -3」と答えがち。ループ回数=配列の長さ3だが、操作されるオブジェクトは2個。2個目だけ2回叩かれる。
問題 3

抽象クラス Shape / Sphere / Cube の穴埋め

2024

小問1:空欄1〜10

空欄入るコード理由
1abstract「空間図形を表す抽象クラス」。
2abstract本体がなく ; で終わる=抽象メソッド。2か所とも同じ。
3extends Shape「Shape から派生した球」。
4throws Exceptionコンストラクタ内で throw new Exception() しており、Exception は検査例外なので宣言必須。
5super(_x, _y, _z)Shape に引数なしコンストラクタが無いので、明示的に呼ばないとコンパイルエラー。
6extends Shape「Shape から派生した立方体」。
7throws Exception4と同じ理由。
8super(_x, _y, _z)5と同じ理由。
9ArrayList<Shape> lis = new ArrayList<Shape>()「Shapeとその下位クラスを収める ArrayList を生成し、参照をローカル変数 lis に代入」。宣言も含めて書くのがポイント。
10Shape shape拡張for文。ループ内で shape.getVolume() を使っているので変数名は shape 固定。
9の型設計:ArrayList<Shape> にしておけば、Sphere も Cube も(下位クラス→上位クラスの代入が可能なので)そのまま add できる。ここが問題1⑥と直結している。

小問2:Sphere の getVolume() / getSurfaceArea() 実装

public double getVolume() {
  return 4.0 / 3.0 * Math.PI * radius * radius * radius;
}
public double getSurfaceArea() {
  return 4.0 * Math.PI * radius * radius;
}
これが小問2の主題:4 / 3 と書くと int ÷ int = 1(切り捨て)になり、体積が 3/4 に化ける。必ず 4.0 / 3.0(片方だけ小数でも可)と書くこと。
あるいは Math.pow(radius, 3) でもよいが、掛け算を並べる方が安全。

小問3:実行結果(Math.PI = 3.14 とする)

解答

4.186666666666667 12.56 1.0 6.0

対象
Sphere 体積4/3 × 3.14 × 1³4.18666…
Sphere 表面積4 × 3.14 × 1²12.56
Cube 体積1 × 1 × 11.0
Cube 表面積6 × 1 × 16.0
最大のワナ:new Cube(2.0, 2.0, -2.0, 1.0)-2.0 は z 座標であって一辺の長さではない。一辺は 1.0 なので例外は発生せず、"error" は出力されない。ここで「error」と答えると小問3が全滅する。
戻り値は doubleなので、整数値でも 1.0 6.0 と小数点付きで表示される。1 6 と書かないこと。
4.1866…は答案では 4.1866666… と書けば十分。

小問4:Cube を「外接球の半径 radius」で保持するよう改造

関係式 r = (√3 / 2) × a より a = 2r / √3。コンストラクタは今まで通り一辺の長さを受け取るので、受け取った値を radius に変換して保存し、各メソッドでは radius から一辺を復元する。

public class Cube extends Shape {
  private double radius;                       // sideLength を削除して追加

  public Cube(double _x, double _y, double _z, double _l) throws Exception {
    super(_x, _y, _z);
    if (_l < 0) throw new Exception();
    radius = 1.7320508 / 2.0 * _l;             // r = (√3/2)a
  }

  public double getVolume() {
    double a = 2.0 * radius / 1.7320508;       // a = 2r/√3
    return a * a * a;
  }

  public double getSurfaceArea() {
    double a = 2.0 * radius / 1.7320508;
    return 6.0 * a * a;
  }
}
設計上の意味:フィールドの持ち方(内部表現)を変えても、getVolume()/getSurfaceArea() という公開インタフェースは不変なので App 側は一切書き換え不要。これがカプセル化の利点。記述問題で問われたらこの一文を書けば得点になる。
ワナ:2 * radius / 1.7320508 のように整数リテラルを混ぜても radius が double なので今回は結果は double になり大丈夫。ただし 4/3 型のミスと混同しないよう、迷ったら すべて .0 を付けるのが安全策。
照合

2026年度 講義資料 × 過去問 カバレッジマップ

全239枚

2026年度の講義資料は最終ページが「総復習」で、新しい章の追加はありません。範囲=Javaの基本 → 制御構造 → データ型と式 → クラスとインスタンス → 差分プログラミング(継承・抽象クラス・ポリモーフィズム) → コレクションと総称型 → 文字列 → 例外処理成績は期末試験のみで評価と明記されています(課題は成績に加味されない)。

講義範囲スライド20242025今年の危険度
Javaの基本・出力・変数10–33
制御構造 if / switch / 新switch34–56問2小問1★★★ アロー構文が未出
ループ・break・continue・ラベル57–76問2小問1問4★★
メソッドの定義と呼出77–85
データ型・演算子・型変換86–112問1③問1①★★★ インクリメント/三項が未出
クラス・カプセル化・アクセス修飾子113–162問1⑦⑧問1⑩・問2小問4★★★
参照・配列163–173問2小問2・5問2小問2★★★★ 毎年出る
継承・super・差分プログラミング174–193問3問2小問3・問3★★★★ super.method()が未出
抽象クラス・ポリモーフィズム194–203問2小問3・問3問3★★★★ 「Fanの例」が未出
コレクション・総称型・ラッパ・Object204–218問3(ArrayList)問1⑤⑦・問3(LinkedList)★★★ Set系が完全未出
String・文字列比較219–223問1④問1④・問4★★★
例外処理224–238問2小問4・問3問2小問5・問3★★★★ 複数catchが未出
結論:過去問2年で作った土台はそのまま有効。ただし講義で明示的に強調されているのに一度も出題されていない項目が8つあります。以下、そこだけ潰せば穴がなくなります。
狙い目 1

ArrayList と LinkedList の性能特性(○×最有力)

p.205–210
ArrayListLinkedList
内部実装配列(自動で伸縮)リンク(連結)
指定位置の取り出し速い遅い
追加・削除遅い(要素を詰め直す)速い

順番があるとき=List系、順番がないとき=Set系(HashSet / TreeSet、いずれも重複を許さない)という使い分けも明示されています。

主要メソッド(そのまま穴埋めに出る)

メソッド働き
add(x)末尾に追加
size()要素数
indexOf(x)先頭から探して最初の位置。無ければ −1
lastIndexOf(x)末尾から探した位置
get(i) / set(i,x) / remove(i) / clear()取得/置換/削除/全消去(先頭は0番目)
contains(x)Set系の所属検査(boolean)

想定問題

ArrayList<String> lis = new ArrayList<String>();
lis.add("a"); lis.add("b"); lis.add("a");
System.out.print(lis.indexOf("a"));
System.out.print(lis.lastIndexOf("a"));
System.out.print(lis.indexOf("z"));
System.out.print(lis.size());
解答

02-13

indexOf("z")−1 を返すのがポイント。0でもnullでもない。

狙い目 2

HashSet / TreeSet(過去問に一度も出ていない)

p.211–213
  • HashSet:ハッシュ関数で格納位置を決める集合。追加・削除・変更が定数時間。順序は保たれない
  • TreeSet:二分探索木の集合。HashSetより追加・削除は遅いが、要素が大小順に格納される
  • どちらも重複を許さない(同じものを2回addしても1個)。

想定問題

HashSet<String> h = new HashSet<String>();
h.add("apple"); h.add("banana"); h.add("apple");
System.out.println(h.size());
System.out.println(h.contains("cherry"));

TreeSet<String> t = new TreeSet<String>();
t.add("banana"); t.add("apple"); t.add("cherry");
for (String s : t) System.out.print(s + " ");
解答

2 false apple banana cherry

TreeSet は入れた順ではなく大小順に並ぶ。ここが HashSet/List との決定的な違いで、出力予測にすると差がつく。

○×で出そうな形:「HashSet は要素を大小順に格納する」→ ×(それは TreeSet)。「TreeSet は HashSet より要素の追加が速い」→ ×(逆)。
狙い目 3

ポリモーフィズム:下位に無ければ「直近上位」のメソッド

p.202–203

講義資料に Fan クラス(draw を定義していない) の例がわざわざ1枚使って書かれています。ルールは2行だけ:

  • そのオブジェクトの実体のクラスにメソッドが定義されていれば、それが呼ばれる。
  • 定義されていなければ、直近上位のクラスで定義されたものが呼ばれる。

想定問題

class A       { public void p() { System.out.print("A"); } }
class B extends A { public void p() { System.out.print("B"); } }
class C extends B { }                    // p を定義していない

A[] ary = { new A(), new B(), new C() };
for (A x : ary) x.p();
解答

ABB

C は自前の p() を持たないので、直近上位の Bp() が実行される(Aまでは遡らない)。変数の型がすべて A でも、呼ばれるのは実体側なのが多態。

狙い目 4

super.method() で上位クラスの実装を使う

p.183

過去問では super(...)(コンストラクタ呼出)だけが出ていますが、講義には super.メソッド名() も別枠で載っています。「上位クラスの実装を利用しつつ、自クラスで追加の実装を行う場合に使う」=差分プログラミングの典型形。

class Figure {
  void printInfo() { System.out.print("図形"); }
}
class Circle extends Figure {
  private int radius = 5;
  void printInfo() {
    super.printInfo();          // 上位の実装を先に実行
    System.out.print("/半径=" + radius);
  }
}
new Circle().printInfo();
解答

図形/半径=5

ワナ:super. を付けずに printInfo(); と書くと自分自身が呼ばれて無限再帰(StackOverflowError)。ここを問う出題もありえます。
狙い目 5

前置/後置インクリメントと三項演算子・論理演算子

p.96–110

インクリメント(出力予測の定番だが過去2年とも未出)

  • ++a(前置):先に増やしてから、その値を式の値とする。
  • a++(後置):増やす前の値を式の値とし、その後に増やす。
int a = 3, b;
b = a++;  System.out.print(b);  System.out.print(a);
b = ++a;  System.out.print(b);  System.out.print(a);
解答

3455

b = a++ → b は3(増える前)、a は 4。b = ++a → a が 5 になってから b に入るので両方 5。

論理演算子(C言語と定義が違うものがある)

演算子意味短絡評価
&& / ||かつ/またはする(左辺で結果が決まれば右辺を評価しない)
& / |かつ/または(boolean同士)しない(両辺を必ず評価)
^排他的論理和:どちらか一方だけtrue なら true

三項演算子

条件式 ? 式1 : 式2。条件が true なら式1、false なら式2の値。式1と式2の型は同じでなければならない(講義で明記)。

型変換のルール(p.103)

  • 型の上下:double > float > long > int > short > bytechar は int の下に接続。
  • byte, char, short演算する前に必ず int に変換される。
  • 二項算術(+ - * / %)の結果はより上位の型
  • 代入演算(= += -= …)の結果は左辺の型に合わせられる。
狙い目 6

新しい switch 文(アロー構文)

p.54–56

2025年度はswitch のカンマ区切り複数ラベルが出ました。講義には旧・新の両方があり、課題3-4は「旧を新に書き換えよ」という内容。新構文の出力予測、または書き換え問題が出る余地があります。

for (int i = 0; i < 4; i++) {
  switch (i) {
    case 0, 1 -> System.out.print("A");
    case 2    -> System.out.print("B");
    default   -> System.out.print("C");
  }
}
解答

AABC

旧 switch新 switch(->
break必要(無いと下へ流れる=フォールスルー)不要(そのcaseだけ実行)
複数値case 1, 2, 4:case 1, 2 ->
使用可能従来からJava 12 以降
中括弧不要文がひとつなら省略可
旧switchの最大のワナは今年も健在:break を書かないと次のcaseの中身まで続けて実行される(フォールスルー)。出力予測で break の有無を必ず指差し確認。
狙い目 7

アクセス修飾子(private / なし / protected / public)

p.146, 180
修飾子自クラス同一パッケージ下位クラスそれ以外
private×××
(なし)××
protected×
public
試験で問われる一点:「private のフィールドは自分の下位クラスからでもアクセスできない」。だから過去問の ShapeAggOp もフィールドが protected になっている。穴埋めで修飾子を答えさせる形もありえます。
狙い目 8

複数catchと例外クラスの階層

p.228–235
  • Exception:あらゆる例外クラスの共通の上位クラス。
  • ArithmeticException0除算で投げられる。
  • ArrayIndexOutOfBoundsException配列の範囲外アクセスで投げられる。
  • 投げられた例外のクラス、またはその上位クラスを指定した catch に飛ぶ。書いた順ではなく型で選ばれる
  • 例外処理構文はループを何段でも、メソッド呼出を何段でも飛び出せる。
  • 入れ子の場合はもっとも近い、適合するcatchに飛ぶ。

想定問題

int[] a = new int[3];
try {
  System.out.println(a[1] / 0);
  System.out.println(a[5]);
}
catch (ArrayIndexOutOfBoundsException ex) { System.out.println("配列"); }
catch (ArithmeticException ex)            { System.out.println("算術"); }
finally                                   { System.out.println("終了"); }
解答

算術 終了

a[1] / 0ArithmeticException が発生 → 先に書かれている「配列」の catch は型が合わないので素通りし、2つ目の catch に飛ぶ。その瞬間 try の残り(a[5])は放棄されるので「配列」は永遠に出力されない。finally は必ず実行。

おまけルール:catch (Exception ex) は上位クラスなのでどの例外でも受けられる。だから catch (Exception ex) を先に書くと後続の catch は到達不能になる。
記述

「カプセル化のメリットを説明せよ」への解答テンプレ

p.153–160

講義で6枚使って ClockTime クラスの例が展開されている=記述問題で問われる可能性が高い箇所です。以下がそのまま答案になります。

模範解答(3文で足りる)

フィールドを private にし、操作を public メソッドとして提供しておけば、クラスの内部表現を変更しても利用側のコードを変更せずに済む。例えば ClockTime クラスで am_or_pm を public にしていると、利用側が直接 t.am_or_pm == 0 と書いてしまうため、12時間制を24時間制に変更した瞬間に利用側が全て壊れる。一方 isBeforeNoon() のようなメソッド経由にしておけば、変更はクラスの内部だけで完結する

  • 方針①:フィールドは極力 privateにせよ(外から直接変更させない)。
  • 方針②:必要最小限のメソッドのみ publicにせよ。
  • 方針③:外から読む必要があれば getter、設定する必要があれば setter を用意せよ。
2024年度 問3小問4と同じ話:Cube の内部表現を「一辺の長さ」から「外接球の半径」に変えても、getVolume() / getSurfaceArea() という公開インタフェースが同じなので App 側は無修正。この一文を書ければ加点されます。
補強

String と総称型まわりの取りこぼし防止

p.215–222

String の主要メソッド

結果(s = "Hello, world!")
s.length()13
s.charAt(3)'l'(最初の文字が0番目)
s.substring(2, 5)"llo"
s1 + s2連結した新しいインスタンスを生成
s1.equals(s2)中身が同じかを boolean で返す
substring(a, b) の範囲:Java の実際の動作は「a番目からb番目の手前まで」(bは含まない)。講義スライドの文言は「2番目から5番目の文字まで」と読めますが、"Hello, world!".substring(2,5)"llo"(2,3,4番目)です。答案では実際の動作で書くのが安全。

== と equals の講義スライド例(p.222)— 出題されたらこう答える

String s1 = "Hello, world!";
String s2 = "Hello, world!";
String s3 = "Hello, ";  String s4 = "world!";
s3 = s3 + s4;   // 連結は新しいインスタンスを生む
if (s1 == s2)        ... // 表示される(同じリテラル=同じインスタンス)
if (s1.equals(s2))   ... // 表示される
if (s1 == s3)        ... // 表示されない(別インスタンス)
if (s1.equals(s3))   ... // 表示される(中身は同じ)
結論だけ覚える:リテラル同士はたまたま同じインスタンスになるので == が true になることもある。しかし連結・Scanner・new で作った文字列は必ず別インスタンスなので == は false。だから常に equals

ラッパクラスとオートボクシング

基本型charbyteintfloatbooleanshortlongdouble
ラッパCharacterByteIntegerFloatBooleanShortLongDouble

総称型(<>)の型パラメータに基本型は書けないので必ずラッパクラスを指定する。Integer r = 100;int v = n; はコンパイラが new Integer(100) / n.intValue() に自動変換してくれる(オートボクシング/アンボクシング)。
new ArrayList<>() のように右辺の型引数を省略する書き方も講義に載っています。

Object クラス:配列も含めて全クラスの最上位。ArrayList<Object> にはどんなクラスのオブジェクトでも入る(2025年度 問1⑤の根拠)。
総括

残り時間別・優先順位

残り時間やること
30分「直前チェック」タブの4本柱(参照/==とequals/継承・抽象・多態/例外とstatic)だけ通読。過去問の問2を紙に書いて再現。
1時間上記+このタブの狙い目1・2・3・8(List/Set・多態の直近上位・複数catch)。○×で確実に差がつく。
2時間以上上記+狙い目4〜7とカプセル化の記述テンプレ。2024・2025の問3を白紙から穴埋めし直す。
最後に:出力予測は必ず紙にトレース表を書くこと。頭の中だけでやると、参照の共有・後置インクリメント・finally の3つで必ずどれか落とします。
直前 60分

この4つだけ完璧にすれば大半が取れる

1. 参照とオブジェクトの区別(配点が一番大きい)

書き方何が起きるか他の変数への影響
b = a;a の矢印だけを b にコピー。オブジェクトは増えない以後 a/b は同一の箱を指す
a = new X();a の矢印を新しい箱に張り替えるb は影響を受けない
b.setXxx(v);箱の中身を書き換えるその箱を指す全員に影響
解き方の型:①オブジェクトを箱で描く ②変数から矢印を引く ③代入のたびに矢印を書き直す ④メソッド呼び出しは箱の中身を書き換える。紙の余白に図を描くのが最短ルート。

2. == と equals

  • ==:参照(アドレス)が同じか。基本型(int, double…)では値の比較になる。
  • equals:内容が同じか。String / Integer などは中身で比較してくれる。
  • Scanner や new で作った文字列は必ず別インスタンスなので == は false。

3. 継承・抽象クラス・多態

キーワード意味・ルール
abstract classインスタンス化不可。抽象メソッドを持てる。変数の型としては使える
abstract 戻り値 m();本体なし・末尾は ;。下位クラスで必ず実装
extends単一継承のみ(多重継承は interface で)
super(...)親のコンストラクタ呼び出し。先頭のみ。省略時は暗黙の super()
アップキャスト親 p = new 子(); は常にOK。逆は明示キャストが必要
動的束縛変数の型ではなく実体の型のメソッドが呼ばれる
オーバーロード同じクラス内・同名・引数が違う。戻り値型だけ違うのは不可
オーバーライド下位クラスで・同名・引数も同じで上書き

4. 例外と static

  • throw new Exception("メッセージ")ex.getMessage() がその文字列を返す。
  • throw した瞬間にループも含めてそのブロックを脱出。以降は実行されない。
  • finally は例外の有無に関係なく必ず実行される(出力の最後に忘れがち)。
  • Exception は検査例外 → 投げうるメソッドは throws Exception の宣言が必要。
  • static フィールドはクラスに1つ。全インスタンスで共有。出力時点の値を答える。

出力を書くときのチェックリスト

確認内容
print / printlnprint なら改行なしで全部つながる。println なら1行ずつ
ループ回数<=< か。i <= 5 は6回
double 表示整数値でも 1.0 6.0 と小数点が付く
int ÷ int切り捨て。4/3 = 1
区切り文字末尾のカンマ・セミコロンまで再現する
finally最後の1行を書き忘れていないか

出題パターンの比較(2026年度の予想)

大問2024年度2025年度今年の対策
問1○×10(型変換/boolean/==/配列宣言/継承の向き/オーバーロード/抽象)ほぼ同じ論点。⑥だけ「上位/下位」が反転選択肢の向き(上位・下位)「してはならない」の否定形を丁寧に読む
問2ループ/参照の張り替え/式ツリー多態/例外+finally/エイリアスswitch/エイリアス+書き換え/コンストラクタ連鎖/static/例外+finally参照の図示例外+finallyは2年連続。ほぼ確実に出る
問3abstract+ArrayList+Shape階層+数式実装abstract+LinkedList+ラッパクラス+throws骨格は同一。abstract / extends / super(...) / throws Exception / new / 拡張for / ジェネリクス付き宣言の7語を即答できるように
問4なしバグ修正(配列未生成/境界/==)新傾向なので今年も出る可能性が高い。「配列の生成忘れ・off-by-one・==での文字列比較」の3点セットを最初に疑う

よくある取りこぼし

  • 問3小問3で error と書いてしまう(座標の負値と長さの負値を混同)。
  • static の値を「生成時点」で答える(正しくは出力時点)。
  • 例外発生後のループ残りも出力してしまう。
  • 穴埋めで空欄の前後を読まず、new; を重複させる。
  • 問4で「必要最小限」を超えて全面書き直しする。