21:次のコードをコンパイル、実行したときの結果として正しいものを選びなさい。
public class Main{
public static void main(String... args) {
A a=new A("a");
A b=new A("a");
A c=new B("a");
B d=new B("b");
System.out.print(""+(a==b)+(a.equals(b)));
System.out.print(""+(c==d)+(c.equals(d)));
}
}
class A{
String i;
A(String i){
this.i=i;
}
}
class B extends A{
String i;
B(String i){
super(i);
}
public boolean equals(Object i) {
if(i instanceof B b)
return this.i==b.i;
else return false;
}
}
A:falsetruefalsefalse
B:truetruefalsefalse
C:falsefalsefalsefalse
D:falsefalsefalsetrue
E:コンパイルエラーが生じる
F:実行時にNullPointerExceptionがスローされる
正解を確認する
最初の出力: (a == b) + (a.equals(b)) a == b: aとbは異なるオブジェクトを参照しているため、結果は false です。 a.equals(b): Aクラスはequalsメソッドをオーバーライドしていません。したがって、Objectクラスのequalsメソッドが呼ばれ、これはa == bと同じように動作するため、結果は false です。 2つ目の出力: (c == d) + (c.equals(d)) c == d: cとdは異なるオブジェクトを参照しているため、結果は false です。 c.equals(d):cとdはBクラスのインスタンスであり、Bクラスでオーバーライドされたequalsメソッドが実行されます。 メソッド内のif (i instanceof B b)}はtrueです。 return this.i == b.iが評価されます。 Bクラスは、スーパークラスAと同じ名前のフィールドiを持っていますが、Bのコンストラクタ内では親クラスAのコンストラクタがsuper(i);で呼ばれA.iへの代入が行われますが、B.iへの代入が行われていません。 そのため、インスタンス変数c.iとd.iはどちらもデフォルト値の null となります。 null == null は true です。
22:次のコードを次のコマンドで実行したときの結果として正しいものを選びなさい。
>java A He llo “He llo” 1 2 3
public class A{
public static void main(String... i) {
i=replace(4,i);
for(int j=0;j<i.length;j++) {
if(i[j] instanceof String a)
System.out.print(a);
System.out.print(" ");
}
}
static String[] replace(int i, String ...j) {
if(i>j.length|i<0)i=j.length;
String[]l=new String[i];
for(int k=0;k<l.length;k++) {
l[k]=j[k].replace(" ", "");
}
return l;
}
}
A:He llo Hello 1
B:He llo Hello 1 2
C:He llo He llo 1 2 3
D:A He llo Hello
E:コンパイルエラー
F:実行時に例外がスローされる
正解を確認する
1. 引数の受け渡し
コマンド java A He llo "He llo" 1 2 3 により、mainメソッドの引数 i には、以下の6つの文字列が格納されます。
i={"He","llo","He llo","1","2","3"}
2. replaceメソッドの処理
i = replace(4, i);が実行されます。
新しい配列の生成: i の値 4 が配列のサイズとして使われ、サイズ 4 の新しい配列 l が作成されます。
要素の操作: ループにより、元の配列 i の最初の4つの要素が処理されます。j[k].replace(" ", "") により、各要素から半角スペースがすべて除去されます。
mainメソッドの i は、この {"He", "llo", "Hello", "1"} に置き換わります。
3. 出力処理
mainメソッドの for ループは、新しい 4 要素の配列を順に処理します。各要素の出力後には、必ず System.out.print(" "); により半角スペースが出力されます。
23:次のうちコンパイルエラーが生じるクラスもしくはインターフェイスはどれか。
public interface A{
A a(A a);
}
abstract class B{
abstract B b(B b);
}
abstract class C extends B implements D{
C b(B b) {
return new E();
}
}
interface D extends A{
default A a(D d) {
return new E();
}
}
class E extends C{
public A a(E e) {
return new E();
}
}
A:C
B:D
C:E
D:C、D、E
E:CとD
F:DとE
G:コンパイルエラーは生じない
正解を確認する
クラス E は C を継承しており、最終的にインターフェイス A の抽象メソッドを実装する義務を負います。 interface A で定義されている抽象メソッド: A a(A a); abstract class C はこのメソッドを実装していませんが、抽象クラスなので問題ありません。 class E は具象クラスなので、この抽象メソッドを必ず実装しなければなりません。 2. クラス E の実装 必要なシグネチャ (Aから継承): A a(A a)、定義されたシグネチャ (Eで定義): A a(E e) E のメソッドは、引数の型を A からそのサブクラスである E に変更しています。これは、オーバーライドではなく、単なるオーバーロード(新しいメソッドの定義)と見なされます。 3. コンパイルエラーの発生 E クラスは、継承した抽象メソッド A a(A a) の一致する実装を提供していません。それにも関わらず、E は abstract と宣言されていない具象クラスであるため、以下のコンパイルエラーが発生します。 エラー: クラス E は、スーパークラスから継承した抽象メソッド A a(A a) を実装するか、自身を抽象クラスとして宣言する必要があります。 その他のクラスの確認 A, B: 宣言のみで問題なし。 D: default A a(D d) は A.a(A a) とシグネチャが異なるためオーバーロードですが、インターフェイスであるため問題ありません。 C: 抽象クラスであるため、A.a(A a) を実装しなくても問題ありません。また、C b(B b) は B.b(B b) の有効なオーバーライドです(戻り値の型が共変規則により B のサブクラス C に変更可能)。
24:次のコードをコンパイル、実行したときの結果として正しいものを選びなさい。
public class Main{
public static void main(String[] args) {
int a=0b1001, b=0b101;
if((a&b++)>(a|++b)&b-->0)System.out.print(b<<2);
if((--a^b)<(~b)&&b-->0)System.out.print(b>>2);
if((-a>>2)<(-a>>>2)|a<(b<<1)|a++>3||a-->2)
System.out.print(a+b);
}
}
A:24214
B:15
C:2313
D:146
E:10
F:コンパイルエラーが生じる
正解を確認する
1. if((a & b++) > (a | ++b) & b-->0)
左辺の評価: (a & b++) > (a | ++b)
a & b++ : 1001 & 0101 → 1 後置インクリメントにより b は0110に変化。
a | ++b 前置インクリメントにより b は0111に変化。
1001 | 0111 → 1111
比較: 1 > 1111 → false
論理積 (&) の評価 & は短絡評価を行わないため、右辺も評価されます。
右辺 b-->0
0111 > 0 → true
後置デクリメントにより b は0110に変化。
最終結果 false & true → false → 最初の if 文は実行されません。
2. if((--a|b) < (~b) && b-->0)
左辺の評価:(--a|b) < (~b)
--a|b 前置デクリメントにより a は1000に変化。1000|0110 → 1110
b=110 のビット反転 →1・・・1001 32桁目が1のため負の数
比較: 1110(正の数) < (負の数) → false
論理積 (&&) の評価
左辺の結果が false です。&& は短絡評価を行うため、右辺 b-->0 は評価されません。
→ 2番目の if 文は実行されず、b の値は110のままです。
3. 3番目の if 文の評価と出力
if((-a>>2)<(-a>>>2)|a<(b<<1)|a++>3||a-->2)
論理和 (|) の評価(短絡評価なし):| は短絡評価を行わないため、最初の3つの条件が順に評価されます。
(-a >> 2) < (-a >>> 2)
-a (1・・・1000) の符号付き右シフト: -a >> 2 → 1・・・10(負の数)
ゼロ埋め右シフト: -a >>> 2 → 001・・・10(正の数)
比較: (負の数) < (正の数) → true
最初の条件が true になったため、残りの | で結合された条件も評価されますが、結果全体は true となります。
a < (b << 1)
b 110 の左シフト: b << 1 → 1100
比較: 1000 < 1100 → true
a++ > 3
1000 > 3 → true
後置インクリメントにより a は1001に変化。
論理和 (||) の評価(短絡評価あり)
(true | true | true) の時点で既に true です。|| は短絡評価を行うため、右辺の a-->2 は評価されません。
→ 3番目の if 文が実行されます。
5. 出力 System.out.print(a + b);
a の最終値: 1001=2^3+1=9、b の最終値: 110=2^4+2^1=6
a + b=9+6=15
25:次のコードをコンパイル、実行したときの結果として正しいものを選びなさい。
public class Main{
public static void main(String[] args) {
A a=new C("1");B b=new C("2");
Main c=new Main();
System.out.print(a);
System.out.print(a.toString());
System.out.print(b);
System.out.print(c);
}
}
abstract class A{
static String i;
public String toString() {
return new C("3").i;
}
}
interface B{
public default String toString() {
return "B";
}
}
class C extends A implements B{
C(String i){
super.i=i;
}
A:a@372f7a8dbc
B:@372f7a8d@372f7a8d@4517d9a3@372f7a8d
C:33B@372f7a8d
D:12B@372f7a8d
E:コンパイルエラーが生じる
F:実行時に例外がスローされる
正解を確認する
このコードがコンパイルエラーになる理由は、インターフェース B の中の toString() メソッドの宣言にあります。 Javaのルールでは、インターフェースは Object クラスのパブリックメソッド(toString(), equals(), hashCode() など)を default メソッドとして再定義することはできません。 このルールにより、interface B の default String toString() という宣言はJavaの言語仕様に違反しているため、コンパイラはこのコードをコンパイルしようとした時点でエラーを発生させます。
26:次のコードをコンパイル、実行したときの結果として正しいものを選びなさい。
public class Main{
public static void main(String[] args) {
double[]i[]= {{1.9,0.5},{5.01},{}};
for(double[]l:i) {
for(double k:l) {
new B().access((int)k);
}
}
}
}
interface A{
int i=2;
void access(int i);
}
class B implements A{
public void access(int i) {
a:switch(i*2) {
case A.i:;
case 3*3:System.out.print(1);
default: System.out.print(2);
break a;
case 1/3:System.out.print(3);
case 3:System.out.print(4);
}
}
}
A:12342
B:222
C:132
D:1222
E:何も出力されない
F:コンパイルエラー
G:実行時に例外がスローされる
正解を確認する
1. 入力値の確定 main メソッドの二重ループにより、new B().access() メソッドには、以下の3つの整数値が順番に渡されます。 1: (int)1.9、0: (int)0.5、5: (int)5.01 access(int i) メソッド内で、switch 文のキーとなるのは i * 2 の値です。 1回目: 1 * 2 = 2、2回目: 0 * 2 = 0、3回目: 5 * 2 = 10 2. switch 文の動作(出力の決定) switch 文の各caseの値はコンパイル時に確定します。 case A.i: 値は 2、case 3*3: 値は 9、case 1/3: 整数除算のため値は 0、case 3: 値は 3 1回目:i * 2 = 2 のとき (出力: 12) case 2 (case A.i) に一致し、処理が開始されます。 case 2 の直後には処理がないため、次のcase 9へフォールスルーします。 case 9 の処理 System.out.print(1); が実行され、1 が出力されます。 次に default へフォールスルーします。 default の処理 System.out.print(2); が実行され、2 が出力されます。 break a; に到達し、ラベル付きの switch 文全体から脱出してメソッドを終了します。 2回目:i * 2 = 0 のとき (出力: 2) case 0に一致し3が出力されます。 次にcase 3にフォロースルーして4が出力されます。 3回目:i * 2 = 10 のとき (出力: 2) どの case ラベルにも一致しないため、default に処理が飛びます。 default の処理 System.out.print(2); が実行され、2 が出力されます。 break a; に到達し、switch 文全体を終了します。
27:次のコードをコンパイル、実行したときの結果として正しいものを選びなさい。
public class Main{
public static void main(String[] args) {
short o=2;long p=2;
byte[]k[]=new byte[o*p][o*(int)p];
System.out.print(extractLength(k));
for(byte i=0,int j=0;i<k.length&j<k.length;i++,j++,dot()) {
System.out.print(k[i][j]);
}
}
static int extractLength(Object i) {
if(!(i instanceof byte[][] a))
return -1;
else return a[0].length;
}
static void dot(){
System.out.print(",");
}
}
A:1か所でコンパイルエラーが生じる
B:2か所でコンパイルエラーが生じる
C:3か所でコンパイルエラーが生じる
D:40,0,0,0と出力される
E:-10,0,0,0と出力される
F:4
G:実行時に例外がスローされる
正解を確認する
コンパイルエラー1:配列のサイズ指定
short o=2;long p=2;
byte[]k[]=new byte[o*p][o*(int)p]; // ← ここでエラー
o は short 型、 p は long 型です。
o * p の計算では、short 型の o が long 型に格上げ(型昇格)されてから計算されるため、結果は long 型の 4L になります。
配列のサイズを long 型で指定することはできず、int 型でなければなりません。
したがって、new byte[4L][4] のように解釈され、最初の次元のサイズ指定でコンパイルエラーが発生します。
コンパイルエラー2:for文の初期化ブロック
for(byte i=0,int j=0;i<k.length&j<k.length;i++,j++,dot()) { // ← ここでエラー
for 文の初期化ブロックで複数の変数を宣言する場合、それらはすべて同じ型である必要があります。
このコードでは byte 型の i と int 型の j という、異なる2つの型を同時に宣言しようとしているため、構文エラーとなりコンパイルできません。正しくは int i=0, j=0; や byte i=0, b=0; のように型を揃える必要があります。
28:次のコードをコンパイル、実行したときの結果として正しいものを選びなさい。
public class Main{
public static void main(String[] args) {
StringBuilder i=new StringBuilder();
StringBuilder j=new StringBuilder(17);
i.append("ab".repeat(8)).append("cd".repeat(1));
i.replace(1, 16, "").reverse();
i.deleteCharAt(1).insert(1,'e');
if(i.capacity()<j.capacity())System.out.print(i.reverse());
else System.out.println(i);
}
}
A:何も出力されない
B:aecd
C:dcea
D:dea
E:aed
F:コンパイルエラー
G:実行時に例外がスローされる
正解を確認する
1. 初期化と容量
j は new StringBuilder(17) で初期化され、その容量 (j.capacity()) は 17 です。
i は new StringBuilder() で初期化され、デフォルトの容量 (i.capacity()) は通常 16 です。
2. i の内容操作
i.append("ab".repeat(8)).append("cd".repeat(1));
"ab".repeat(8) は "abababababababab の16文字です。
"cd" の2文字が追加され、i の内容は "ababababababababcd(長さ18)となります。
長さ18は初期容量16を超えるため、i の容量は拡張されます(18以上になる)。
現在: i の内容: "ababababababababcd、容量: 34
3. 置換と反転
i.replace(1, 16, "").reverse();
i.replace(1, 16, ""):
インデックス 1 から 16までの15文字(’b’ から ’b’ まで)が削除されます。
元の文字列 a
bababababababab
cd から、インデックス 0 の ’a’、16 の ’c’、17 の ’d’ が残ります。
i の内容はacd になります。
i.reverse():i の内容は "dca になります。
4. 最終的な文字操作
i.deleteCharAt(1).insert(1,’e’);
i.deleteCharAt(1):インデックス 1 の文字 ’c’ が削除されます。i の内容はda になります。
i.insert(1, ’e’):インデックス 1 の位置に ’e’ が挿入されます。i の内容はdea になります。
5. 条件判定と出力
if(i.capacity()<j.capacity())System.out.print(i.reverse());
else System.out.println(i);
i.capacity() は 34 です。j.capacity() は 17 です。
34 < 17 は false です。
→ else ブロックが実行され、現在の i の内容dea が改行付きで出力されます。
29:次のコードの■■■■■■に記述できるコードとして正しいものを選びなさい。
public class Main{
public static void main(String[] args) {
long i=1l;float f=2f;Character c='a';Byte b=2;
■■■■■■
}
}
A:int j=switch(c){case 'a':yield 2;
case 'b':yield 1;};
B:int j=switch(i){default->1;
case 1->2;};
C:int j=switch(b){default->{System.out.print("d");yield 2;}
case 2->2;};
D:int j=switch(f){default:System.out.print(2);yield 2;
case 1:yield 1;};
E:いずれも正しくない
F:AとB
G:AとC
正解を確認する
A: 誤り(コンパイルエラー)
制御変数: c は Character(char)型です。
エラー理由: char 型は ’a’ や ’b’ 以外にも多くの値を取りうるため、default ブロックがないことで網羅性を満たせず、コンパイルエラーとなります。
B: 誤り(コンパイルエラー)
エラー理由: 制御変数 i は long 型であり、switch の制御変数として型が不適であるため、コンパイルエラーとなります。使用可能な型はint, byte, short, charとこれらのラッパークラス(Integerなど)およびString, enum。
C: 正しい(コンパイル可能)
制御変数: b は Byte 型であり、switch の制御変数として有効です。
網羅性: default ブロックが記述されているため、網羅性を満たしています。
文法: switch 式として正しい構文であり、コンパイルに成功します。{}内ではyieldを使用して値を返します。
D: 誤り(コンパイルエラー)
エラー理由 1: 制御変数 f は float 型であり、switch の制御変数として型が不適であるため、コンパイルエラーとなります。
30:■■■■■■■■■■■に記述できるものとして正しいものはどれか。
interface A{
default void a() {}
}
interface B extends A{
default void b() {}
}
abstract class C{
void c() {}
public void b(){}
}
abstract class D extends C{
}
■■■■■■■■■■■
A:final abstract class E extends D implements B{public void b(){}}
B:final interface E extends B{public void a(){}}
C:abstract class E extends D implements B{
protected void d(){super.c();B.super.b();A.super.a();}}
D:abstract interface E extends B{static void e1(){}
private void e2(){}
protected final void e3(){}}
E:abstract interface E extends B{public A(){}}
F:interface E extends B{int i;}
G:すべて正しくない
正解を確認する
A: abstract(抽象)クラスは継承されることを前提とする修飾子です。
final クラスは継承を禁止する修飾子です。これら2つの矛盾する修飾子を同時にクラスに指定することはできません。
B: インタフェースは実装されることを目的としているため、final 修飾子を付けることはできません。
C: 一見正しく見えますが、A.super.a() の呼び出しに問題があります。
InterfaceName.super.methodName() という構文でデフォルトメソッドを呼び出す場合、その InterfaceName は、呼び出し元のクラスが直接実装(implements)しているインタフェースでなければなりません。
このコードでは、class E は B を直接実装していますが、A は B が継承しているインタフェースであり、E が直接実装しているわけではありません(間接的なスーパーインタフェースです)。したがって、A.super.a() という呼び出しはコンパイルエラーとなります。
D: インタフェースのメソッドに protected や final という修飾子を付けることはできません。
E:public A(){} はコンストラクタの記述です。
インタフェースはインスタンス化できないため、コンストラクタを持つことはできません。
F: インタフェース内で宣言されたフィールド(変数)は、自動的に public static final (定数)として扱われます。
final なフィールドは宣言と同時に初期化する必要がありますが、int i; は初期化されていないためコンパイルエラーとなります。正しくは int i = 10; のように値を代入しなければなりません。
コメント