クラス (class)

定義

継承 (Inheritance)

Javaでは、クラスを継承するのにextends (拡張) キーワードを使用します。

class クラス名 extends 継承するクラス名 {
}

クラスによるインターフェイスの継承は、実装として定義します。

オブジェクトの生成

クラスは、new演算子によりインスタンス化できます。

new コンストラクタ;

しかしクラスの定義によっては、単純にインスタンス化できないこともあります。

class A {}
class B<E> {}       // ジェネリック クラス
abstract class C {} // 抽象クラス
interface D {}      // インターフェイス

class E { private E(){} } // privateなコンストラクタを持つクラス
new A(); // OK
new B(); // NG : B is a raw type. References to generic type B<E> should be parameterized
new C(); // NG : Cannot instantiate the type C
new D(); // NG : Cannot instantiate the type D

new E(); // NG : The constructor E() is not visible

修飾子

クラス修飾子 (class modifier)

分類 修飾子 説明
アクセス 無指定 所属するパッケージからのアクセスのみを許可する
public すべてのアクセスを許可する
継承 abstract 抽象クラスとして継承を強制する
final クラスの継承を禁止する
アノテーション @[アノテーション型] アノテーションを適用する
演算モード strictfp 浮動小数点演算を厳密に行うFP-strictモードとする

修飾子は複数指定することができ、その順序は問われません。しかしabstractとfinalは同時に指定できません。それは継承の強制と禁止という、矛盾した指示になるからです。

abstract final class Foo {}
// NG : The class Foo can be either abstract or final, not both

public

publicとしたクラスは、必ずそのクラスと同名のファイルで定義しなければなりません。つまりクラスFooを定義するファイルは、Foo.javaというファイル名にします。それを、たとえば

public class A {}

をB.javaというファイルで定義すると、「The public type A must be defined in its own file」のようにエラーとなります。

abstract (抽象)

抽象クラスはインスタンス化できません。サブクラスを定義し、それをインスタンス化します。

abstract class Foo {}
class Bar extends Foo {}
Foo foo = new Foo(); // NG : Cannot instantiate the type Foo
Bar bar = new Bar(); // OK

final

final class Foo {}
class Bar extends Foo {} // NG : The type Bar cannot subclass the final class Foo

アクセス修飾子 (access modifier)

アクセス可能な範囲
修飾子 クラス内 サブクラス 同一パッケージ 他クラス
無指定 × ×
private × × ×
protected ×
public

privateとprotectedは、メンバーにのみ使用できます。またC#とは異なり、アクセス修飾子の省略はprivateとはならず、特別な意味を持ちます。

コンストラクタ (constructor)

クラスは簡単な初期化を行うために、コンストラクタを持つことができます。

class Foo {
    Foo() {}
    Foo(int a) {}
}

コンストラクタは、クラスのメンバーではありません。

デフォルトコンストラクタ (default constructor)

コンストラクタを明示的に定義しないとき、引数なしコンストラクタが自動で定義されます。それをデフォルトコンストラクタと呼びます。

インスタンス化の防止

コンストラクタをprivateとすることで、クラスがインスタンス化されるのを防ぐことができます。Preventing Instantiation of a Class - Chapter 8. Classes

class Foo {
    private Foo() {}
}

たとえば、このクラスをインスタンス化しようとすると

new Foo(); // NG : The constructor Foo() is not visible

のようにエラーとなります。

引数付きコンストラクタ (parameterized constructors)

引数付きコンストラクタと引数なしコンストラクタを両方提供するには、両方のコンストラクタを定義する必要があります。

class Foo {
}

class Bar {
    Bar(int a) {}
}

class Baz {
    Baz() {}
    Baz(int a) {}
}
new Foo(); // OK
new Bar(); // NG : The constructor Bar() is undefined
new Baz(); // OK

コピーコンストラクタ (copy constructor)

引数にそのクラスと同じ型を受け取り、渡されたオブジェクトのコピーとなるようにオブジェクトを生成するコンストラクタを、コピーコンストラクタと呼称します。

class Foo {
    int a;

    Foo(Foo obj) {
        this.a = obj.a;
    }
}

継承したクラスのコンストラクタ

class Foo {
}
class Bar extends Foo {
    Bar() {} // OK
}
class Foo {
    Foo() {}
}
class Bar extends Foo {
    Bar() {} // OK
}

スーパークラスが引数付きのコンストラクタを定義しているならば、サブクラスはそのコンストラクタを呼び出し、明示的に初期化を行わなくてはなりません。

class Foo {
    Foo(int a) {}
}

// NG : Implicit super constructor Foo() is undefined for default constructor. Must define an explicit constructor
class Bar extends Foo {
}

class Baz extends Foo {
    // NG : Implicit super constructor Foo() is undefined. Must explicitly invoke another constructor
    Baz() {}
}
class Foo {
    Foo(int a) {}
}
class Bar extends Foo {
    Bar() {
        super(1); // OK
    }
    Bar(int a) {
        super(a); // OK
    }
}

フィールド (field)

初期化 (initialization)

フィールドの初期化を行う初期化子 (initializer) は、定数以外に他のフィールドやメソッドなどの式を指定できます。

class Foo {
    int a = 123;
    double b = 1.0;

    int c = a + 1;
    double d = Math.sqrt(2);
}

フィールドを初期化しなかった場合は、そのに応じて次の値に初期化されます。

初期値
boolean false
char '\u0000'
byte 0
short
int
long
float +0.0
double
オブジェクト参照 null

メソッドの呼び出し

フィールドを初期化するメソッドは、コンストラクタより先に呼ばれます。

class Foo {

    // コンストラクタ
    Foo() {
        System.out.print("Z");
    }

    int A() {
        System.out.print("A");
        return 1;
    }

    int a = A(); // 初期化子
}

public class Test {

    public static void main(String[] args) {
        new Foo(); // AZと出力
    }
}

初期化を伴わないメソッドの呼び出しはできません。これはメソッドの宣言と誤解されます。また初期化には戻り値が必要なことから、戻り値がvoidのメソッドは呼び出せません。

class Foo {

    int A() { return 1; }
    void B() {}

    int a= A();  // OK
    A();         // NG : This method requires a body instead of a semicolon
    int b = B(); // NG : Type mismatch: cannot convert from void to int
}

staticメソッドをクラス定義のブロックから呼び出そうとすると、Syntax errorとして検出されます。

class Foo {

    static int C() { return 1; }

    int c = Foo.C(); // OK
    Foo.C();         // NG : Syntax error on token "C", Identifier expected after this token

    System.out.print("A"); // NG : Syntax error on token "print", Identifier expected after this token
}

初期化ブロック (initialization block)

より複雑な初期化を行うには、初期化ブロックを使用します。これはすべてのコンストラクタの前に実行されます。

class Foo {
    int a;

    {             // ここが初期化ブロック
        a = 123;  //
    }             //
}
static初期化ブロック (static initilization block)

クラスのstaticメンバーを初期化します。

class Foo {
    static int a;

    static {
        a = 123;
    }
}

メソッド (method)

修飾子

メソッドに対しても、クラスと同様のアクセス修飾子を指定できます。

メソッドをオーバーライドするとき、スーパークラスにおける可視性 (visibility) を減少させることはできません。

class Foo {
    void A() {}
    private void B() {}
    protected void C() {}
    public void D() {}
}

class Bar extends Foo {
    void A() {super.A();} // OK
    void B() {super.B();} // NG : The method B() from the type Foo is not visible
    void C() {super.C();} // NG : Cannot reduce the visibility of the inherited method from Foo
    void D() {super.D();} // NG : Cannot reduce the visibility of the inherited method from Foo
}

abstract (抽象)

抽象メソッドを定義するならば、クラスもabstract (抽象) としなければなりません。

class Foo { // NG : The type Foo must be an abstract class to define abstract methods
    abstract void A();
}

abstract class Bar { // OK
    abstract void A();
}

抽象メソッドには、本体を定義してはなりません。抽象メソッドでなければ当然、本体が必要です。

abstract class Foo {
    abstract void A();   // OK
    abstract void B() {} // NG : Abstract methods do not specify a body

    void C() {} // OK
    void D();   // NG : This method requires a body instead of a semicolon
}

すべてのメソッドを抽象とするならば、クラスではなくインターフェイスとして定義します。

final

finalとされたメソッドは、サブクラスでオーバーライドできません。

class Foo {
    void A() {}
    final void B() {}
}

class Bar extends Foo {
    void A() {} // OK
    void B() {} // NG : Cannot override the final method from Foo
}

可変長引数 (Varargs)

メソッドのパラメータリストの最後のパラメータは、特定の型の可変長の引数として宣言できます。そのためには、パラメータ型の後にエリプス (Ellipse) を記述します。次の例ではint...の「...」が、それにあたります。

void Foo(int... a) {}

可変長引数は、必ずパラメータの最後でなければなりません。

void Foo1(int a, int... b) {} // OK
void Foo2(int... b, int a) {} // NG:The variable argument type int of the method Foo2 must be the last parameter

可変長引数へのアクセス

可変長引数は、メソッド内では配列となります。たとえばメソッドが、

void Foo(int... a) {}

と定義されているとします。このとき次のように引数を与えて呼び出すと、メソッド側にはコメントで示すように渡されます。

Foo();    // a.lengthは0
Foo(1);   // a.lengthは1、a[0]は1
Foo(1,2); // a.lengthは2、a[0]は1、a[1]は2

参考

アノテーション

メソッドにアノテーションの@Overrideを指定することで、オーバーライドしていることを明示できます。

内部クラス (inner class)

内部クラスとは、staticではないネストしたクラス (nested classes) のことです。

ネストしたインターフェイスは暗黙的にstaticとなるため、たとえstatic修飾子を省略しても非staticとはなりません。

またネストした型を囲む (enclose) 型は、エンクロージング型 (enclosing type) と呼ばれます。そしてそれがクラスの場合にはエンクロージング クラスとなり、そのクラスのオブジェクトはエンクロージング オブジェクトと呼称されます。

内部クラスの名前は、「エンクロージング クラス名.内部クラス名」の形式で表現されます。

class Foo {

    private int x = 1;

    // ここはクラスのコードブロック内
    class Bar {

        Bar() {
            // エンクロージング オブジェクトにアクセスできる
            x++;

            // より明示的に記述すると次のようになる
            Foo.this.x++;
        }
    }

    void Method() {
        Bar bar1 = new Bar();

        // より明示的に記述すると次のようになる
        Bar bar2 = this.new Bar();
    }
}

ローカル内部クラス (local inner class)

ローカル内部クラスとは、メソッドなどのコードブロック内で定義される内部クラスです。これはクラスのメンバーではありません。

class Foo {

    void Method() {

        // ここはメソッドのコードブロック内
        class Bar {
        }

        // 定義されているコードブロック内でのみインスタンス化できる
        Bar bar = new Bar();
    }
}

無名内部クラス (anonymous inner class)

無名内部クラスとは、newでインスタンス化されるときに定義されるローカル内部クラスです。

クラスやインターフェイスを継承する必要があり、暗黙的にimplements修飾子を持っています。

class Foo {

    void Method() {

        // ここはメソッドのコードブロック内
        Object bar = new Object() {

            // ここは内部クラスのブロック内

            // 内部クラスのメソッドの定義
            @Override
            public String toString() {
                return "test";
            }
        };
    }
}

ガベージコレクタ (garbage collector)

オブジェクトは参照されなくなると、ガベージコレクタによって自動的に削除されます。ただし削除されるタイミングは、参照されなくなった時点とは限りません。

参考

参考書

Javaのドキュメントから検索