Fukuoka Univ. / 中西恒夫 — Final Exam Prep
過去問2年分の全問解答+解説。参照の共有(エイリアス)・==とequals・抽象クラスと多態・例外の4本柱が毎年出ています。
① int型の値とdouble型の値を加算した結果はdouble型となる。
数値の二項演算では「広い方の型」に自動的に格上げされる(数値昇格)。int + double → double。byte/short/char同士の演算はintになる点もセットで覚える。
② if文の条件式に整数型の式を書くと、0以外なら真、0なら偽として実行される。
それはC/C++の話。Javaのbooleanは数値と完全に別の型で、if (n) は コンパイルエラー(型の不一致)。if (n != 0) と書く必要がある。
③ すべてのクラスに共通の上位クラスの名前は Null である。
正しくは java.lang.Object。null は「どのオブジェクトも指していない」参照値であってクラス名ではない。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がまさにこれ。
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
print(printlnではない)なので改行なしで全部つながる。case 1, 2, 4, 8: は Java 14 以降のカンマ区切り複数ラベル。i<8 なので case 8 には一生到達しないのがひっかけ。
01264202414 の11文字。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[1] = a[2]; の瞬間、「たぬき」を指す唯一の参照が消えて回収対象に。以後 a[1] と a[2] は同一の1個を指すので、片方を書き換えると両方が変わって見える。a[1] = a[2] は「a[2]の指す先を、a[1]にも指させる」。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 |
super(...)/this(...) はコンストラクタの先頭にしか書けない ②書かなければ暗黙で super()(引数なし)が入る ③親が先、子が後に実行される。Hoge h1 = new Fuga(); のように変数の型は Hoge、実体は Fuga という書き方も頻出(多態)。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。
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 負の数 おわり
a.check() → n=8 は正なので 8 を出力して正常終了。b.check() → n=-4 で throw。そこで try ブロックを即座に脱出(残りは実行されない)。getMessage() が例外生成時の文字列 "負の数" を返す。おわり。new Exception("負の数") でコンストラクタに渡した文字列がそのまま返る。「例外クラス名」ではない。| 空欄 | 入るコード | 理由 |
|---|---|---|
| ① | abstract | 「AggOp は抽象クラスである」+抽象メソッド calc() を持つため必須。 |
| ② | LinkedList<Integer> | 「リンクによる線形リスト」=LinkedList。中身は int のラッパ=Integer。 |
| ③ | new | lis = new LinkedList<Integer>(); 生成して代入。 |
| ④ | abstract | 本体{}がなく;で終わっている=抽象メソッド宣言。 |
| ⑤ | throws Exception | 「calc() は Exception を発生し得る」。宣言側・実装側の両方に同じものが入る。 |
| ⑥ | extends AggOp | Adder / 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>(); が既にある)。空欄の前後に既に書かれているコードを必ず読むこと。55 Too big
max = 100 を超えないので例外なし → 55 を出力。120 > 100 → throw new Exception("Too big")。System.out.println(adder.calc()) は既に済んでいるので 55 は表示済み、multiplier.calc() の結果は表示されない。max が static なのは「全インスタンス共通の上限値」を表すため。adder と multiplier は別インスタンスだが同じ 100 を見ている。仕様:①10個の文字列を配列に読み込む ②入力された文字列が①の中にあれば「Found」、なければ「Not Found」 ③②を繰り返す。
| # | 該当箇所 | 症状 | 修正 |
|---|---|---|---|
| 1 | public App() { } | 配列 str が生成されていない(null)。最初の str[0]=... で NullPointerException。 | str = new String[10]; |
| 2 | i <= 10(2か所) | 0〜10 の11回回る。仕様は10個。さらに要素数10の配列に対し ArrayIndexOutOfBoundsException。 | i < 10(または i < str.length) |
| 3 | str[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 OuterLoop; は内側forを抜けて while の先頭に戻る=「Foundを表示したら次の検索へ」で仕様通り。ここは直さなくてよい。「必要最小限の変更」なので、余計な書き換えは減点対象。① 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年連続同じ問題。確実に○。
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 <= 5 なので6回回る ②カンマは毎回出力されるので末尾にもカンマが付く。15で終わらせない。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[0] = ... は矢印の張り替え=その変数だけ変わる。a[0].setXxx(...) は箱の中身の書き換え=その箱を指す全員に影響。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() と書けるのが抽象クラスの利点。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.
| a | 8 / a | 出力 |
|---|---|---|
| 2 | 4 | 4 |
| 1 | 8 | 8 |
| 0 | 例外 throw | (ループ脱出) |
| -1, -2 | 到達しない | |
finished.(ピリオド込み)を忘れずに。すべて print なので1行に連結。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
| 空欄 | 入るコード | 理由 |
|---|---|---|
| 1 | abstract | 「空間図形を表す抽象クラス」。 |
| 2 | abstract | 本体がなく ; で終わる=抽象メソッド。2か所とも同じ。 |
| 3 | extends Shape | 「Shape から派生した球」。 |
| 4 | throws Exception | コンストラクタ内で throw new Exception() しており、Exception は検査例外なので宣言必須。 |
| 5 | super(_x, _y, _z) | Shape に引数なしコンストラクタが無いので、明示的に呼ばないとコンパイルエラー。 |
| 6 | extends Shape | 「Shape から派生した立方体」。 |
| 7 | throws Exception | 4と同じ理由。 |
| 8 | super(_x, _y, _z) | 5と同じ理由。 |
| 9 | ArrayList<Shape> lis = new ArrayList<Shape>() | 「Shapeとその下位クラスを収める ArrayList を生成し、参照をローカル変数 lis に代入」。宣言も含めて書くのがポイント。 |
| 10 | Shape shape | 拡張for文。ループ内で shape.getVolume() を使っているので変数名は shape 固定。 |
ArrayList<Shape> にしておけば、Sphere も Cube も(下位クラス→上位クラスの代入が可能なので)そのまま add できる。ここが問題1⑥と直結している。public double getVolume() {
return 4.0 / 3.0 * Math.PI * radius * radius * radius;
}
public double getSurfaceArea() {
return 4.0 * Math.PI * radius * radius;
}
4 / 3 と書くと int ÷ int = 1(切り捨て)になり、体積が 3/4 に化ける。必ず 4.0 / 3.0(片方だけ小数でも可)と書くこと。Math.pow(radius, 3) でもよいが、掛け算を並べる方が安全。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 × 1 | 1.0 |
| Cube 表面積 | 6 × 1 × 1 | 6.0 |
new Cube(2.0, 2.0, -2.0, 1.0) の -2.0 は z 座標であって一辺の長さではない。一辺は 1.0 なので例外は発生せず、"error" は出力されない。ここで「error」と答えると小問3が全滅する。1.0 6.0 と小数点付きで表示される。1 6 と書かないこと。4.1866666… と書けば十分。関係式 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年度の講義資料は最終ページが「総復習」で、新しい章の追加はありません。範囲=Javaの基本 → 制御構造 → データ型と式 → クラスとインスタンス → 差分プログラミング(継承・抽象クラス・ポリモーフィズム) → コレクションと総称型 → 文字列 → 例外処理。成績は期末試験のみで評価と明記されています(課題は成績に加味されない)。
| 講義範囲 | スライド | 2024 | 2025 | 今年の危険度 |
|---|---|---|---|---|
| Javaの基本・出力・変数 | 10–33 | — | — | ★ |
| 制御構造 if / switch / 新switch | 34–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の例」が未出 |
| コレクション・総称型・ラッパ・Object | 204–218 | 問3(ArrayList) | 問1⑤⑦・問3(LinkedList) | ★★★ Set系が完全未出 |
| String・文字列比較 | 219–223 | 問1④ | 問1④・問4 | ★★★ |
| 例外処理 | 224–238 | 問2小問4・問3 | 問2小問5・問3 | ★★★★ 複数catchが未出 |
| ArrayList | LinkedList | |
|---|---|---|
| 内部実装 | 配列(自動で伸縮) | リンク(連結) |
| 指定位置の取り出し | 速い | 遅い |
| 追加・削除 | 遅い(要素を詰め直す) | 速い |
順番があるとき=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でもない。
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 との決定的な違いで、出力予測にすると差がつく。
講義資料に 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() を持たないので、直近上位の B の p() が実行される(Aまでは遡らない)。変数の型がすべて A でも、呼ばれるのは実体側なのが多態。
過去問では 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)。ここを問う出題もありえます。++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。
| 演算子 | 意味 | 短絡評価 |
|---|---|---|
| && / || | かつ/または | する(左辺で結果が決まれば右辺を評価しない) |
| & / | | かつ/または(boolean同士) | しない(両辺を必ず評価) |
| ^ | 排他的論理和:どちらか一方だけtrue なら true | — |
条件式 ? 式1 : 式2。条件が true なら式1、false なら式2の値。式1と式2の型は同じでなければならない(講義で明記)。
double > float > long > int > short > byte、char は int の下に接続。byte, char, short は演算する前に必ず int に変換される。+ - * / %)の結果はより上位の型。= += -= …)の結果は左辺の型に合わせられる。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 以降 |
| 中括弧 | 不要 | 文がひとつなら省略可 |
| 修飾子 | 自クラス | 同一パッケージ | 下位クラス | それ以外 |
|---|---|---|---|---|
| private | ○ | × | × | × |
| (なし) | ○ | ○ | × | × |
| protected | ○ | ○ | ○ | × |
| public | ○ | ○ | ○ | ○ |
Shape も AggOp もフィールドが protected になっている。穴埋めで修飾子を答えさせる形もありえます。Exception:あらゆる例外クラスの共通の上位クラス。ArithmeticException:0除算で投げられる。ArrayIndexOutOfBoundsException:配列の範囲外アクセスで投げられる。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] / 0 で ArithmeticException が発生 → 先に書かれている「配列」の catch は型が合わないので素通りし、2つ目の catch に飛ぶ。その瞬間 try の残り(a[5])は放棄されるので「配列」は永遠に出力されない。finally は必ず実行。
catch (Exception ex) は上位クラスなのでどの例外でも受けられる。だから catch (Exception ex) を先に書くと後続の catch は到達不能になる。講義で6枚使って ClockTime クラスの例が展開されている=記述問題で問われる可能性が高い箇所です。以下がそのまま答案になります。
フィールドを private にし、操作を public メソッドとして提供しておけば、クラスの内部表現を変更しても利用側のコードを変更せずに済む。例えば ClockTime クラスで am_or_pm を public にしていると、利用側が直接 t.am_or_pm == 0 と書いてしまうため、12時間制を24時間制に変更した瞬間に利用側が全て壊れる。一方 isBeforeNoon() のようなメソッド経由にしておけば、変更はクラスの内部だけで完結する。
getVolume() / getSurfaceArea() という公開インタフェースが同じなので App 側は無修正。この一文を書ければ加点されます。| 式 | 結果(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番目)です。答案では実際の動作で書くのが安全。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。| 基本型 | char | byte | int | float | boolean | short | long | double |
|---|---|---|---|---|---|---|---|---|
| ラッパ | Character | Byte | Integer | Float | Boolean | Short | Long | Double |
総称型(<>)の型パラメータに基本型は書けないので必ずラッパクラスを指定する。Integer r = 100; や int v = n; はコンパイラが new Integer(100) / n.intValue() に自動変換してくれる(オートボクシング/アンボクシング)。new ArrayList<>() のように右辺の型引数を省略する書き方も講義に載っています。
ArrayList<Object> にはどんなクラスのオブジェクトでも入る(2025年度 問1⑤の根拠)。| 残り時間 | やること |
|---|---|
| 30分 | 「直前チェック」タブの4本柱(参照/==とequals/継承・抽象・多態/例外とstatic)だけ通読。過去問の問2を紙に書いて再現。 |
| 1時間 | 上記+このタブの狙い目1・2・3・8(List/Set・多態の直近上位・複数catch)。○×で確実に差がつく。 |
| 2時間以上 | 上記+狙い目4〜7とカプセル化の記述テンプレ。2024・2025の問3を白紙から穴埋めし直す。 |
| 書き方 | 何が起きるか | 他の変数への影響 |
|---|---|---|
| b = a; | a の矢印だけを b にコピー。オブジェクトは増えない | 以後 a/b は同一の箱を指す |
| a = new X(); | a の矢印を新しい箱に張り替える | b は影響を受けない |
| b.setXxx(v); | 箱の中身を書き換える | その箱を指す全員に影響 |
==:参照(アドレス)が同じか。基本型(int, double…)では値の比較になる。equals:内容が同じか。String / Integer などは中身で比較してくれる。== は false。| キーワード | 意味・ルール |
|---|---|
| abstract class | インスタンス化不可。抽象メソッドを持てる。変数の型としては使える |
| abstract 戻り値 m(); | 本体なし・末尾は ;。下位クラスで必ず実装 |
| extends | 単一継承のみ(多重継承は interface で) |
| super(...) | 親のコンストラクタ呼び出し。先頭のみ。省略時は暗黙の super() |
| アップキャスト | 親 p = new 子(); は常にOK。逆は明示キャストが必要 |
| 動的束縛 | 変数の型ではなく実体の型のメソッドが呼ばれる |
| オーバーロード | 同じクラス内・同名・引数が違う。戻り値型だけ違うのは不可 |
| オーバーライド | 下位クラスで・同名・引数も同じで上書き |
throw new Exception("メッセージ") → ex.getMessage() がその文字列を返す。finally は例外の有無に関係なく必ず実行される(出力の最後に忘れがち)。throws Exception の宣言が必要。static フィールドはクラスに1つ。全インスタンスで共有。出力時点の値を答える。| 確認 | 内容 |
|---|---|
| print / println | print なら改行なしで全部つながる。println なら1行ずつ |
| ループ回数 | <= か < か。i <= 5 は6回 |
| double 表示 | 整数値でも 1.0 6.0 と小数点が付く |
| int ÷ int | 切り捨て。4/3 = 1 |
| 区切り文字 | 末尾のカンマ・セミコロンまで再現する |
| finally | 最後の1行を書き忘れていないか |
| 大問 | 2024年度 | 2025年度 | 今年の対策 |
|---|---|---|---|
| 問1 | ○×10(型変換/boolean/==/配列宣言/継承の向き/オーバーロード/抽象) | ほぼ同じ論点。⑥だけ「上位/下位」が反転 | 選択肢の向き(上位・下位)と「してはならない」の否定形を丁寧に読む |
| 問2 | ループ/参照の張り替え/式ツリー多態/例外+finally/エイリアス | switch/エイリアス+書き換え/コンストラクタ連鎖/static/例外+finally | 参照の図示と例外+finallyは2年連続。ほぼ確実に出る |
| 問3 | abstract+ArrayList+Shape階層+数式実装 | abstract+LinkedList+ラッパクラス+throws | 骨格は同一。abstract / extends / super(...) / throws Exception / new / 拡張for / ジェネリクス付き宣言の7語を即答できるように |
| 問4 | なし | バグ修正(配列未生成/境界/==) | 新傾向なので今年も出る可能性が高い。「配列の生成忘れ・off-by-one・==での文字列比較」の3点セットを最初に疑う |
error と書いてしまう(座標の負値と長さの負値を混同)。new や ; を重複させる。