クラス (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(); // ERROR : B is a raw type. References to generic type B<E> should be parameterized
new C(); // ERROR : Cannot instantiate the type C
new D(); // ERROR : Cannot instantiate the type D

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

クラス修飾子 (class modifier)

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

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

abstract final class MyClass {}
// ERROR : The class MyClass can be either abstract or final, not both

public

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

public class A {}

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

abstract (抽象)

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

abstract class MyClass {}
class SubClass extends MyClass {}
MyClass myClass = new MyClass(); // ERROR : Cannot instantiate the type MyClass
SubClass subClass = new SubClass(); // OK

final

final class MyClass {}
class SubClass extends MyClass {} // ERROR : The type SubClass cannot subclass the final class MyClass

アクセス修飾子 (access modifier)

アクセスを制限する修飾子です。

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

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

コンストラクタ (constructor)

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

class MyClass {
    MyClass() {}
    MyClass(int a) {}
}

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

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

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

インスタンス化の防止

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

class MyClass {
    private MyClass() {}
}

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

new MyClass(); // ERROR : The constructor MyClass() is not visible

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

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

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

class MyClass1 {
}

class MyClass2 {
    MyClass2(int a) {}
}

class MyClass3 {
    MyClass3() {}
    MyClass3(int a) {}
}
new MyClass1(); // OK
new MyClass2(); // ERROR : The constructor MyClass2() is undefined
new MyClass3(); // OK

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

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

class MyClass {
    int a;

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

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

class MyClass {
}
class SubClass extends MyClass {
    SubClass() {} // OK
}
class MyClass {
    MyClass() {}
}
class SubClass extends MyClass {
    SubClass() {} // OK
}

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

class MyClass {
    MyClass(int a) {}
}

// ERROR : Implicit super constructor MyClass() is undefined for default constructor. Must define an explicit constructor
class SubClass1 extends MyClass {
}

class SubClass2 extends MyClass {
    // ERROR : Implicit super constructor MyClass() is undefined. Must explicitly invoke another constructor
    SubClass2() {}
}
class MyClass {
    MyClass(int a) {}
}
class SubClass extends MyClass {
    SubClass() {
        super(1); // OK
    }
    SubClass(int a) {
        super(a); // OK
    }
}

フィールド (field)

初期化 (initialization)

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

class MyClass {
    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 MyClass {

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

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

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

public class TestClass	 {

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

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

class MyClass {

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

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

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

class MyClass {

    static int C() { return 1; }

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

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

初期化ブロック (initialization block)

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

class MyClass {
    int a;

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

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

class MyClass {
    static int a;

    static {
        a = 123;
    }
}

メソッド (method)

修飾子

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

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

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

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

abstract (抽象)

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

class MyClass1 { // ERROR : The type MyClass must be an abstract class to define abstract methods
    abstract void A();
}

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

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

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

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

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

final

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

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

class SubClass extends MyClass {
    void A() {} // OK
    void B() {} // ERROR : Cannot override the final method from MyClass
}

可変長引数 (Varargs)

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

void Method(int... a) {}

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

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

可変長引数へのアクセス

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

void Method(int... a) {}

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

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

参考

アノテーション

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

内部クラス (inner class)

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

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

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

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

class MyClass {

    private int x = 1;

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

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

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

    void Method() {
        InnerClass innerClass1 = new InnerClass();

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

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

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

class MyClass {

    void Method() {

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

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

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

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

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

class MyClass {

    void Method() {

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

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

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

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

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

参考

参考書

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