OCJP Gold SE 7(1Z0-804-JPN Java SE 7 Programmer II)を受験しました【執筆中】

はじめに

OCJP Gold SE7を受験してきました。結果は不合格でした。(チーン)

受験中よくわからなかった問題、自信を持って答えられなかった問題を記憶を頼りにまとめようと思います。

私が使用している問題集の章立てに従って、出題された問題を順に説明します。記憶だけが頼りなので問題の記述は正確には違います。あしからずご容赦ください。

また、当記事はSE8ではなく、SE7についてかかれています。SE8とはinterfaceの定義の仕方など異なるところがありますのでご注意ください。

なお、解答はEclipse4.0、jdk1.7.0_80で実際にコーディングした結果です。Oracleの公式の解答ではありません。

1章 Javaクラスの設計 2章 高度なクラス設計

Interfaceで定義できるもの

[問題]コメントを外してもコンパイルエラーにならないものを3つ選んでください。

package java.programmer.ii.no01;

public interface Animal {
// int value1 = 1;                 // 1
// final int value2 = 2;           // 2
// int value3;                     // 3
// void func();                    // 4
// static void funcStatic();       // 5
// protected void funcProtected(); // 6
}

[解答]1, 2, 4 interfaceではpublic static finalなプロパティしか定義できません。1, 2はpublic static finalと書いてありませんが、コンパイラが省略されていてもpublis static final なプロパティとしてみてくれるようなのでコンパイルエラーは発生しません。3はプロパティを初期化していないのでコンパイルエラーが発生します。4も同様にpublic abstractは省略できます。5はinterfaceには実装のないstaticメソッドを定義できないのでコンパイルエラーが発生します。6はinterfaceにはpublicメソッドしか定義できないのでコンパイルエラーが発生します。

[補足]なお、以下のように変数の修飾子はpublicのみでも、staticのみでもOKです。

package java.programmer.ii.no01;

public interface Animal {
// int value1 = 1;                 // 1
// final int value2 = 2;           // 2
// int value3;                     // 3
    public int value4 = 4; // static final 省略可能
    static int value5 = 5; // public final 省略可能
    
// void func();                    // 4
// static void funcStatic();       // 5
// protected void funcProtected(); // 6
// static void funcStaticWithImpl() {} // 実装があってもcompile error。JavaSE8からはOK
}

Number, Integer, Double と instanceOf

この問題は記憶が曖昧です。

[問題]以下のコードの実行結果は次のどれですか。

package exam.no02;

public class InstanceOfTest {
    private Number value1 = 1;
    private Number value2 = 0.5;
    private Number value3 = value1 + value2; // (a)
    public void func() {
        if (value1 instanceof Integer) {
            System.out.println("Integer");
        }
        if (value2 instanceof Double) {
            System.out.println("Double");
        }
        if (value3 instanceof Double) {
            System.out.println("Double");
        }
    }
    public static void main(String[] args) {
        new InstanceOfTest().func();
    }
}
  1. コンパイルエラー
  2. Integer Double Double

[解答]1.。(a)のところでvalue1とvalue2がunboxingされずコンパイルエラーになります。なお、以下のようにすれば2.の出力結果になります。

package exam.no02;

public class InstanceOfTest {
    private Number value1 = 1;
    private Number value2 = 0.5;
    private Number value3 = value1.intValue() + value2.doubleValue();
    public void func() {
        if (value1 instanceof Integer) {
            System.out.println("Integer");
        }
        if (value2 instanceof Double) {
            System.out.println("Double");
        }
        if (value3 instanceof Double) {
            System.out.println("Double");
        }
    }
    public static void main(String[] args) {
        new InstanceOfTest().func();
    }
}

抽象クラスを作成するときのabstractとpublicの順番

実務では全く役に立たない知識ですが、abstrack public の順番でもOKというのは知りませんでした。

[問題]以下のうちコンパイルが成功するものはどれですか。

package exam.no03;
public abstract class PublicAbstractClass {} // 1
package exam.no03;
abstract public class AbstractPublicClass {} // 2
package exam.no03;
public class InvalidAbstractClass1 extends Abstract {} // 3
package exam.no03;
public class InvalidAbstractClass2 implements Abstract {} // 4

[解答]1, 2。3, 4が明らかにコンパイルエラーで、1が正しいことはわかったのですが、abstrackとpublicの順番が逆でもコンパイル成功することは知りませんでした。

interfaceのstatic finalの変数とスーパークラスの変数

私の場合、interfaceの変数が出力されるのか、スーパークラスの変数が出力されるのか、いつも混乱してしまいます。

[問題]次のコードの出力結果を選んでください。

package exam.no04;

interface Book {
    String category = "book";
}

class Comic implements Book {
    String category = "comic";
}

public class HunterXHunter extends Comic {
    String category;
    public HunterXHunter() {
        this.category = super.category;
    }
    public static void main(String[] args) {
        System.out.println(new HunterXHunter().category);
    }
}
  1. book
  2. comic

[解答]2。

[補足]なお、bookを出力するためには以下のようにします。Book.categoryとします。HunterXHunter.categoryでは取得できません。コンパイルエラーになります。

package exam.no04;

interface Book {
    public static final String category = "book";
}

class Comic implements Book {
    String category = "comic";
}

public class HunterXHunter extends Comic {
    String category;
    public HunterXHunter() {
        this.category = super.category;
    }
    public static void main(String[] args) {
        System.out.println(new HunterXHunter().category); // comic
//     System.out.println(HunterXHunter.category); // compile error
        System.out.println(Book.category); // book
    }
}

superclassのstaticメソッドと同じシグネチャインスタンスメソッドをsubclassで定義した場合

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no05;

class Book {
    static String category = "book";
    static void disp() {
        System.out.println(category);
    }
}

class Comic extends Book {
    String category = "comic";
    void disp() {
        System.out.println(category);
    }
}

public class HunterXHunter extends Comic {
    public static void main(String[] args) {
        new HunterXHunter().disp();
    }
}
  1. comic
  2. コンパイルエラー

[解答]2。「このインスタンス・メソッドは Book からの static メソッドをオーバーライドできません。」というメッセージとともにコンパイルエラーが発生します。

getDepth

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no06;

class Lake {
    int depth = 5;
    int getDepth() {
        return depth;
    }
}
public class SubLake extends Lake {
    int depth = 10;
    int getDepth() {
        return depth;
    }
    public static void main(String[]args) {
        Lake lake = new SubLake();
        System.out.println(lake.getDepth());
        System.out.println(lake.depth);
    }
}
  1. 10 5
  2. 10 10

[解答]1。

3章 オブジェクト指向の設計原理

Integer2つを比較→片方インクリメント→再び比較

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no07;

public class IntegerTest {
    public static void main(String[] args) {
        Integer value1 = 2001;
        Integer value2 = value1;
        System.out.print(value1 == value2);
        System.out.print(++value1); // (a)
        System.out.print(value1 == value2);
    }
}
  1. true2002true
  2. true2002false

[解答]2。value1だけがインクリメントされてもvalue1もvalue2もおなじインスタンスを参照しているはずだから両方とも2001から2002に変わると考え、私は試験時1を選択しました。しかし正しいのは2でした。これは、IntegerはImmutableなクラスであるため(a)の行でvalue1は全く別の新しいInteger(値は2002)に置き換わっているためです。(value2は2001のままです。)

f:id:machoblog:20170325184213j:plain

singletonとEnum

この問題は、4つのコードからsingletonになっているものを2つ選択するものでした。あきらかにsingletonでない選択肢2つとよくあるsingletonの実装例と以下のEnumの実装例がありました。 Enumでsingletonの実装をできるとは知らなかったので、あげました。

  • よくあるsingletonの実装
package exam.no08;

public class SingletonTest {
    private static SingletonTest instance;
    private SingletonTest() {
    }
    public static synchronized SingletonTest getInstance() {
        if (instance == null) {
            return new SingletonTest();
        } else {
            return instance;
        }
    }
}
  • Enumを利用したsingleton
package exam.no08;

public enum Singleton {
    INSTANCE;
}

4章 ジェネリックスとコレクション

set.add(null) → set.size()

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no09;

import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(null);
        System.out.println(set.size());
    }
}
  1. 2
  2. 3
  3. コンパイルエラー
  4. 実行時エラー

[解答]2。私は3を選択しました。なぜ2番になるかわかりませんでしたが、以下の配列を利用したコードも出力結果は3になりました。

package exam.no09;

public class Main3 {
    public static void main(String[] args) {
        Integer[] array = {1, 2, null};
        System.out.println(array.length);
    }
}

new E()

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no10;

public class Printer<E> {
    private E e;
    public Printer() {
        e = new E();
    }
}
  1. コンパイルエラー
  2. コンパイルエラーは発生しない

[解答] 1。new E()はできません。e = e.getClass().newInstance()もできませんでした。少し調べたところ、型引数からインスタンスを作成する方法はないようで、妥協策としてパラメーターでClassを受け取ってnewInstance()するという方法があるようです。

package exam.no10;

public class Printer<E> {
    private E e;
    public Printer(Class<E> clazz) throws InstantiationException, IllegalAccessException {
        e = clazz.newInstance();
    }
    void display() {
        System.out.println(e);
    }
    public static void main(String [] args) throws InstantiationException, IllegalAccessException {
        Printer<String> printer = new Printer<>(String.class);
        printer.display();
    }
}

5章 文字列処理

java.util.StringTokenizer

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no11;

import java.util.StringTokenizer;

public class Beatles {
    public static void main(String[] args) {
        String beatles = "John-.-Paul-.-Ringo-.-George";
        StringTokenizer tokenizer = new StringTokenizer(beatles, "-.-");
        while (tokenizer.hasMoreTokens()) {
            System.out.println(tokenizer.nextToken());
        }
    }
}
John
Paul
Ringo
George
  1. コンパイルエラー

[解答]1。StringTokenizerは文字列を分割するために利用するクラスです。String.splitを使えばいいではないかと思ってどんな違いがあるのかOracleAPIを確認したところ、互換性を保つために残っているクラスでString.splitを使うことが推奨されていました。

It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.

System.out.printf() 、String.format() (%n %,.0f)

[問題]以下のコードを実行した結果がどうなるか選んでください。

package exam.no12;

public class Main {
    public static void main(String[] args) {
        String city = "Tokyo";
        int population = 10000;
        double density = 75.15;
        System.out.printf("Name is %1$s.%nPopulation is %2$d.%n%,.0f:density", city, population, density);
    }
}
  1. 実行時エラー
  2. コンパイルエラー
Name is Tokyo.
Population is 10000.
75:density
Name is Tokyo.
Population is 10000.
75.15:density
Name is Tokyo.
Population is 10000.

が出力された後に実行時エラー

[解答]3。私は受験時に5を選択しました。「%,.0f」のところで実行時エラーになると思ったからです。OracleAPIを確認したところ、このカンマは整数部に3桁ごとにカンマを打つかどうかを表しています。たとえばdensityの値を以下のように帰ると出力結果は次に示すようになります。

package exam.no12;

public class Main {
    public static void main(String[] args) {
        String city = "Tokyo";
        int population = 10000;
        double density = 9975.15;
        System.out.printf("Name is %1$s.%nPopulation is %2$d.%n%3$,.0f:density", city, population, density);
    }
}
  • 出力結果
Name is Tokyo.
Population is 10000.
9,975:density

java.util.Pattern, java.util.Matcher

[問題]実行結果が"Timer time time"になる[regex]にあてはまる正規表現を以下のうちどれか選択してください。

package exam.no13;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String message = "Time time timely timer timed time";
        Pattern pattern = Pattern.compile("[regex]");
        Matcher matcher = pattern.matcher(message);
        while (matcher.find()) {
            System.out.print(matcher.group());
        }
    }
}
  1. [Tt]ime[^rd]
  2. [Tt]ime
  3. [Tt]ime\s*

[解答]不明です。あと2つ選択肢があり、そのうちいずれかが正解だと思いますが、忘れてしまいました。

NumberFormatの取得方法

[問題]NumberFormatの取得方法として正しいものを4つ選択してください。

NumberFormat numberFormat = NumberFormat.getCurrencyInstance();
NumberFormat integerFormat = NumberFormat.getIntegerInstance();
NumberFormat numberFormat = NumberFormat.getNumberInstance();
NumberFormat parcentFormat = NumberFormat.getPercentInstance();
NumberFormat decimalFormat = new DecimalFormat();
NumberFormat decimalFormat2 = new DecimalFormat("#,###.00000");

[解答]不明。実行してみると以下のようになるので、全て正しいように思えます。ここに記述した選択肢が出題された選択肢と異なっているかもしれません。

package exam.no14;

import java.text.DecimalFormat;
import java.text.NumberFormat;

public class Main {
    public static void main(String[] args) {
        NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
        NumberFormat integerFormat = NumberFormat.getIntegerInstance();
        NumberFormat numberFormat = NumberFormat.getNumberInstance();
        NumberFormat parcentFormat = NumberFormat.getPercentInstance();
        NumberFormat decimalFormat = new DecimalFormat();
        NumberFormat decimalFormat2 = new DecimalFormat("#,###.00000");
        double value = 12345.6789;
        System.out.println(currencyFormat.format(value));
        System.out.println(integerFormat.format(value));
        System.out.println(numberFormat.format(value));
        System.out.println(parcentFormat.format(value));
        System.out.println(decimalFormat.format(value));
        System.out.println(decimalFormat2.format(value));
    }
}
  • 出力結果
¥12,346
12,346
12,345.679
1,234,568%
12,345.679
12,345.67890

6章 例外とアサーション

throws句でRuntimeExceptionのサブクラスを指定し、そのメソッドをオーバーライドしたメソッドのthrows句でRuntimeExceptionを指定する。

7章 Java I/Oの基礎

BufferedReader.skip

BufferedReader(fileReader(

Console.getPassword

RandomAccessFile

try-with-resource文で利用できるようにするには

try-with-resource文でクローズ後の例外を表示するには

JavaファイルI/O(NIO.2)

ファイルの移動FileChannel,Files.copy,BufferedReader

ファイルの検索(glob:*.html,htm,xml)

ファイルの監視(プラットフォームによってイベントの種類、順番は異なるか)

attr.getOwner

JDBCによるデータベースアプリケーションの作成

Connection,Statement,ResultSetはclose必要か

getConnectionのパラメーター

Statement.setMaxRows

rollback,savePoint,setAutoCommit

RowSet WebRowSet, CachedRowSet

10章 スレッド 11章 並列処理

CallableとRunnableの違い

[問題]CallableとRunnableの違いについて述べた記述のうち、正しいものを選択してください。

  1. CallableはExecutorService.execute()のパラメーターにできるが、Runnableはできない。
  2. Callableのcall()では例外をスローできるが、Runnableのrun()ではスローできない。
  3. Callableのcall()では戻り値を返せるが、Runnableのrun()では返せない。

[解答]3。

Thread.start2回

[問題]次のコードの実行結果として正しいものを選択してください。

package exam.no18;

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                System.out.print("run ");
            }
        });

        t.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.start();
    }
}
  1. run runが出力される。
  2. runの後に実行時エラーが発生する。

[解答]2。Threadには状態があり、一度終了したThreadは再びstartできません。なお、上のコードの実行結果は以下のようになります。

run
Exception in thread "main" java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:705)
    at exam.no18.Main.main(Main.java:17

また次のように実行中のThreadに対しstartを実行した場合も同様に実行時エラーとなります。

package exam.no18;

public class Main2 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                System.out.println("run");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t.start();
        t.start();
    }
}
runException in thread "main" 
java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:705)
    at exam.no18.Main2.main(Main2.java:17)

Thread.start join start

上の問題と似ていますが、joinする点で異なっています。

[問題]次のコードの実行結果として正しいものを選択してください。

package exam.no19;

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                System.out.print("run ");
            }
        });
        
        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.start();
    }

}
  1. run runが出力される。
  2. runの後に実行時エラーが発生する。

[解答]2。Threadには状態があり、一度終了したThreadは再びstartできません。なお、上のコードの実行結果は以下のようになります。

run
Exception in thread "main" java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:705)
    at exam.no19.Main.main(Main.java:17)

CopyOnWriterArrayList

ローカライゼーション

Localeの取得方法(new Locale.Builder()….)

よくある問題ですが、new Locale.Builder()….という方法を始めて見たのでここで紹介しようと思います。

[問題]Localeの取得の仕方で正しいものを3つ選択してください。

1.Locale locale = new Locale("en", "US");

2.Locale locale = Locale.US;

3.Locale locale = new Locale.Builder().setLanguage("en").setRegion("US").build();

4.Locale locale = Locale.getInstance();

[解答]1, 2, 3。なお、取得したLocaleを使って、リソースを読み込むと以下のようになります。

package exam.no;

import java.util.Locale;
import java.util.ResourceBundle;

public class Main {
    public static void main(String[] args) {
        Locale locale1 = Locale.US;
        Locale locale2 = new Locale("en", "US");
        Locale locale3 = new Locale.Builder().setLanguage("en").setRegion("US").build();
        Locale locale4 = new Locale("en");
        Locale locale5 = new Locale("US");

        ResourceBundle rs1 = ResourceBundle.getBundle("exam/no/greeting", locale1);
        System.out.println(rs1.getString("morning"));
        ResourceBundle rs2 = ResourceBundle.getBundle("exam/no/greeting", locale2);
        System.out.println(rs2.getString("morning"));
        ResourceBundle rs3 = ResourceBundle.getBundle("exam/no/greeting", locale3);
        System.out.println(rs3.getString("morning"));
        ResourceBundle rs4 = ResourceBundle.getBundle("exam/no/greeting", locale4);
        System.out.println(rs4.getString("morning"));
        ResourceBundle rs5 = ResourceBundle.getBundle("exam/no/greeting", locale5);
        System.out.println(rs5.getString("morning"));
    }
}
  • greeting.properties
morning=こんにちは
evening=こんばんは
  • greeting_en.properties
morning=Good morning.(without region)
evening=Good evening.(without region)
  • greeting_en_US.properties
morning=Good morning.
evening=Good evening.
  • 出力結果
Good morning.
Good morning.
Good morning.
Good morning.(without region)
こんにちは