Java Silver試験で頻出の「クラスの定義とオブジェクト」に関する問題を10問収録しました。アクセス修飾子、コンストラクタ、staticメンバ、カプセル化、オーバーロードなど、試験で問われやすいポイントを網羅しています。
問題1 ⭐(基本)
次のコードをコンパイル・実行すると、どうなりますか?
public class Sample {
private int value;
public static void main(String[] args) {
Sample s = new Sample();
System.out.println(s.value);
}
}
- A.
0 - B.
null - C. コンパイルエラー
- D. 実行時エラー
解答と解説
正解: A
int型のインスタンス変数はデフォルト値0で初期化されます。privateフィールドであっても、同一クラス内からはアクセス可能です。mainメソッドはSampleクラス内にあるため、s.valueにアクセスできます。
プリミティブ型のデフォルト値:
-
int→0 -
double→0.0 -
boolean→false -
char→'\u0000'
参照型のデフォルト値はnullです。
問題2 ⭐⭐(応用)
次のコードをコンパイル・実行すると、どうなりますか?
public class Animal {
String name;
Animal(String name) {
this.name = name;
}
public static void main(String[] args) {
Animal a = new Animal();
System.out.println(a.name);
}
}
- A.
null - B. 空文字が出力される
- C. コンパイルエラー
- D. 実行時エラー
解答と解説
正解: C
引数ありのコンストラクタAnimal(String name)を明示的に定義しているため、コンパイラはデフォルトコンストラクタ(引数なし)を自動生成しません。new Animal()は引数なしコンストラクタを呼び出そうとしていますが、存在しないためコンパイルエラーになります。
デフォルトコンストラクタが自動生成されるのは、コンストラクタを1つも定義していない場合のみです。
問題3 ⭐⭐(応用)
次のコードをコンパイル・実行すると、どうなりますか?
public class Counter {
static int count = 0;
Counter() {
count++;
}
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
System.out.println(Counter.count);
System.out.println(c1.count);
}
}
- A.
3と1 - B.
3と3 - C.
1と1 - D. コンパイルエラー
解答と解説
正解: B
static変数はクラスに1つだけ存在し、すべてのインスタンスで共有されます。コンストラクタが3回呼ばれるためcountは3になります。
Counter.count(クラス名経由)でもc1.count(インスタンス経由)でも同じstatic変数を参照するため、どちらも3を出力します。ただし、staticメンバにはクラス名経由でアクセスするのが推奨されます。
問題4 ⭐(基本)
次のコードをコンパイル・実行すると、どうなりますか?
public class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(3, 4));
System.out.println(calc.add(1.5, 2.5));
}
}
- A.
7と4.0 - B.
7.0と4.0 - C. コンパイルエラー(オーバーロードが曖昧)
- D.
7と4
解答と解説
正解: A
これはメソッドオーバーロードの例です。calc.add(3, 4)はintリテラル同士なのでadd(int, int)が呼ばれ、結果はintの7です。calc.add(1.5, 2.5)はdoubleリテラル同士なのでadd(double, double)が呼ばれ、結果はdoubleの4.0です。
オーバーロードは引数の型・数・順序で解決されます。戻り値の型だけが異なるメソッドはオーバーロードできません。
問題5 ⭐⭐⭐(チャレンジ)
次のコードをコンパイル・実行すると、どうなりますか?
public class Builder {
String material;
Builder() {
this("wood");
System.out.println("No-arg constructor");
}
Builder(String material) {
this.material = material;
System.out.println("Parameterized constructor: " + material);
}
public static void main(String[] args) {
Builder b = new Builder();
System.out.println(b.material);
}
}
- A.
No-arg constructor→Parameterized constructor: wood→wood - B.
Parameterized constructor: wood→No-arg constructor→wood - C. コンパイルエラー(
this()呼び出しが不正) - D.
No-arg constructor→wood
解答と解説
正解: B
this("wood")により、引数なしコンストラクタから引数ありコンストラクタが呼び出されます。this()やthis(...)はコンストラクタの最初の文でなければなりません。
実行順序:
-
new Builder()→ 引数なしコンストラクタに入る -
this("wood")→ 引数ありコンストラクタが呼ばれる -
Parameterized constructor: woodを出力 - 引数なしコンストラクタに戻る
-
No-arg constructorを出力 -
mainに戻りwoodを出力
問題6 ⭐⭐(応用)
次のコードをコンパイル・実行すると、どうなりますか?
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
public static void main(String[] args) {
Person p = new Person("Taro", 25);
p.name = "Jiro";
System.out.println(p.getName());
}
}
- A.
Taro - B.
Jiro - C. コンパイルエラー
- D. 実行時エラー
解答と解説
正解: B
nameフィールドはprivateですが、mainメソッドは同一クラスPerson内にあるため、p.nameに直接アクセスできます。privateは他のクラスからのアクセスを制限しますが、同一クラス内(同一クラスの別インスタンスも含む)からはアクセス可能です。
したがってp.name = "Jiro"は有効で、getName()は"Jiro"を返します。
もしmainメソッドが別のクラスにあれば、p.name = "Jiro"はコンパイルエラーになります。
問題7 ⭐⭐⭐(チャレンジ)
次のコードをコンパイル・実行すると、どうなりますか?
public class MathUtil {
static void print(int a) {
System.out.println("int: " + a);
}
static void print(long a) {
System.out.println("long: " + a);
}
static void print(Integer a) {
System.out.println("Integer: " + a);
}
public static void main(String[] args) {
print(10);
}
}
- A.
int: 10 - B.
long: 10 - C.
Integer: 10 - D. コンパイルエラー(オーバーロードが曖昧)
解答と解説
正解: A
オーバーロード解決の優先順位は以下の通りです:
-
完全一致 →
print(int) -
暗黙の型拡大変換(widening) →
print(long) -
オートボクシング →
print(Integer) - 可変長引数
10はintリテラルなので、完全一致するprint(int)が呼ばれます。
もしprint(int)が存在しなければ、暗黙の型拡大変換によりprint(long)が呼ばれます。さらにそれもなければ、オートボクシングによりprint(Integer)が呼ばれます。
問題8 ⭐(基本)
次のコードをコンパイル・実行すると、どうなりますか?
public class StaticDemo {
int x = 10;
static void show() {
System.out.println(x);
}
public static void main(String[] args) {
show();
}
}
- A.
10 - B.
0 - C. コンパイルエラー
- D. 実行時エラー
解答と解説
正解: C
staticメソッドからインスタンス変数xに直接アクセスすることはできません。staticメソッドはインスタンスに依存しないため、インスタンスメンバ(フィールド・メソッド)を直接参照できません。
修正方法:
-
xをstatic int x = 10;にする - または
show()メソッド内でインスタンスを生成してアクセスする
問題9 ⭐⭐(応用)
次のコードをコンパイル・実行すると、どうなりますか?
public class Overload {
static String test(int a, String b) {
return "int-String";
}
static String test(String a, int b) {
return "String-int";
}
public static void main(String[] args) {
System.out.println(test(1, "hello"));
System.out.println(test("hello", 1));
}
}
- A.
int-StringとString-int - B.
int-Stringとint-String - C. コンパイルエラー(オーバーロードが曖昧)
- D.
String-intとint-String
解答と解説
正解: A
オーバーロードは引数の型の順序でも区別されます。test(1, "hello")は第1引数がint、第2引数がStringなのでtest(int, String)が呼ばれます。test("hello", 1)は第1引数がString、第2引数がintなのでtest(String, int)が呼ばれます。
オーバーロードの条件: 引数の型、数、順序のいずれかが異なること。戻り値の型だけでは区別できません。
問題10 ⭐⭐⭐(チャレンジ)
次のコードをコンパイル・実行すると、どうなりますか?
public class InitOrder {
static int x = initStatic();
int y = initInstance();
static int initStatic() {
System.out.println("static initializer");
return 1;
}
int initInstance() {
System.out.println("instance initializer");
return 2;
}
InitOrder() {
System.out.println("constructor");
}
public static void main(String[] args) {
System.out.println("main start");
InitOrder obj1 = new InitOrder();
InitOrder obj2 = new InitOrder();
}
}
- A.
main start→static initializer→instance initializer→constructor→instance initializer→constructor - B.
static initializer→main start→instance initializer→constructor→instance initializer→constructor - C.
static initializer→instance initializer→constructor→main start→instance initializer→constructor - D.
main start→instance initializer→constructor→instance initializer→constructor
解答と解説
正解: B
初期化の順序は以下の通りです:
-
クラスのロード時:
staticフィールド・static初期化ブロックが上から順に実行される mainメソッド開始- インスタンス生成時(毎回): インスタンスフィールド・インスタンス初期化ブロックが上から順に実行される → コンストラクタが実行される
staticフィールドxの初期化はmainメソッドより先に実行されます。static初期化はクラスロード時に1回だけ行われるため、2つ目のインスタンス生成時には実行されません。
出力:
static initializer
main start
instance initializer
constructor
instance initializer
constructor
参考
- Oracle Java SE 17 Language Specification - Chapter 8: Classes
- Oracle Java Tutorials - Classes and Objects
- Oracle Java Tutorials - Controlling Access to Members of a Class
@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!