ホーム > カテゴリ > Java・Android >

Javaのクラス(基本/カプセル化/継承/多態性/テンプレート) [中級者用]

Javaの使い方(目次)

目次

1. クラスの基本
2. クラスの継承
3. 抽象クラス
4. インターフェース
5. 多態性(ポリモーフィズム)
6. ジェネリクス(テンプレート)
7. インナークラス
8. オリジナルクラスの注意事項

1. クラスの基本

次例ではコンストラクタ、コンストラクタのオーバーロード、カプセル化を設定しています。なお、Javaにはデストラクタはありません。

カプセル化とはクラスのメンバ変数(フィールド)やメンバ関数(メソッド)のアクセスを制限する事です。代表例としてメンバ変数をprivateにするプロパティ(Javaではsetter/getter)の定義です。

[Main.java]

class MyClass{

    // メンバ変数
    private String name;
    private int age;

    // コンストラクタ1
    public MyClass() {
        // 未設定の場合はコンストラクタ2を呼び出す
        this("山田太郎", 17);
    }

    // コンストラクタ2
    public MyClass(String name,int age) {
        this.name = name ;
        this.age = age ;
    }

    // プロパティ1(setter)
    public void setName(String name) {
        this.name = name;
    }

    // プロパティ1(getter)
    public String getName() {
        return this.name;
    }

    // プロパティ2(setter)
    public void setAge(int age) {
        this.age = age;
    }

    // プロパティ2(getter)
    public int getAge() {
        return this.age;
    }
    
    // メソッド
    public void run1() { 
        System.out.println("メソッドが実行されました。");
    } 
    
    // 静的メソッド
    public static void run2() { 
        System.out.println("静的メソッドが実行されました。");
    } 
}

public class Main {

    public static void main(String[] args) {
        MyClass my1 = new MyClass();
        MyClass my2 = new MyClass("山田花子",15);

        System.out.println(my1.getName() + " " + my1.getAge() + "才");
        System.out.println(my2.getName() + " " + my2.getAge() + "才");

        my2.setAge(43);
        System.out.println(my2.getName() + " " + my2.getAge() + "才");
        
        my1.run1();
        MyClass.run2();
        
    }
}

[結果]

山田太郎 17才
山田花子 15才
山田花子 43才
メソッドが実行されました。
静的メソッドが実行されました。

Javaでは1ファイル1クラスが原則ですが、1つのpublicクラス以外のクラスのアクセス修飾子を「なし」にすると、今回の例のように1ファイルに複数のクラスを定義する事が可能です。

次表はクラス、メンバ変数、メソッドで使用できるアクセス修飾子です。

名前アクセスを許可する範囲
public全てのクラス
protected同一パッケージ内のクラスまたは子クラス(サブクラス)
なし
(package private)
同一パッケージ内のクラス
private自クラスのみ

※クラスには「public」と「なし」の2種類しか使用できません。

2. クラスの継承

親クラス(Parent)を継承して子クラス(Child)を作成します。

// 親クラス(スーパークラス/基底クラス)
class Parent{

    public Parent() {
        System.out.println("Parentのコンストラクタ");
    }

    public void run1() {
        System.out.println("Parent.run1メソッド");
    }

    public void run2() {
        System.out.println("Parent.run2メソッド");
    }

    public void run3() {
        System.out.println("Parent.run3メソッド");
    }
}

// 子クラス(サブクラス/派生クラス)
class Child extends Parent{

    public Child() {
        // 親クラスのコンストラクタを呼び出す
        // ※定義しなくてもコンパイルの際に暗黙的に挿入される
        super();
        
        // Childの独自処理
        System.out.println("Childのコンストラクタ");
    }
    
    // オーバーライド
    public void run2() {
        System.out.println("Child.run2メソッド");
    }

    // オーバーライド
    public void run3() {
        // 親クラスのrun3を呼び出す
        super.run3();
        
        // Childの独自処理
        System.out.println("Child.run3メソッド");
    }
    
    // Childの独自メソッド
    public void run4() {
       System.out.println("Child.run4メソッド");
    }    
}

public class Main {

    public static void main(String[] args) {
        Child child = new Child();
        child.run1();
        child.run2();
        child.run3();
        child.run4();
    }
}

結果

Parentのコンストラクタ
Childのコンストラクタ
Parent.run1メソッド
Child.run2メソッド
Parent.run3メソッド
Child.run3メソッド
Child.run4メソッド

クラスの継承/メソッドのオーバーライドを禁止するにはfinalを付与します。

// クラス
final class Parent{
}

// メソッド
final void run() {
}

3. 抽象クラス

抽象クラスは「クラスの雛形」です。newでインスタンス化をする事はできません。また、抽象メソッドは最終的に継承先(子クラス)でオーバーライドする必要があります。

//抽象クラス
abstract class Parent{

 // 抽象メソッド(処理は定義しない)
 public abstract void run(String str);

 // 通常メソッド
 public void normal(){
     System.out.println("抽象クラスの通常メソッド");
 }
}

//子クラス(サブクラス)
class Child extends Parent{

  // オーバーライド
  public void run(String str) {
      System.out.println(str);
  }
}

public class Main {

 public static void main(String[] args) {
     Child child = new Child();
     child.run("プチモンテ");
     child.normal();
 }
}

結果

プチモンテ
抽象クラスの通常メソッド

4. インターフェース

インターフェースは抽象クラスの上位版です。抽象クラスと同じくnewでインスタンス化できません。特徴は「全てのメソッドが抽象メソッド」になります。また、Javaのクラスは多重継承ができませんが、インターフェースは多重継承が可能です。

次例ではIDog, ICatのインターフェースを多重継承しています。

// インターフェースの定義
interface IDog{

    // 抽象メソッド(public abstractは省略可能)
    void methodA(String msg);

    // 定数 (public static finalは省略可能)
    double PI = 3.14;
}

interface ICat{

    // 抽象メソッド
    void methodB(String msg);
}

// インターフェイスを実装する(今回は多重継承)
class MyClass implements IDog, ICat{

    // IDogの抽象メソッドのオーバーライド
    public void methodA(String msg){
        System.out.println("methodA : " + msg);
    }

    // ICatの抽象メソッドのオーバーライド
    public void methodB(String msg){
       System.out.println("methodB : " + msg);
    }
}

public class Main {

    public static void main(String[] args) {
        MyClass my = new MyClass();
        my.methodA("メソッドA");
        my.methodB("メソッドB");
        System.out.println(my.PI);
    }
}

結果

methodA : メソッドA
methodB : メソッドB
3.14

今度はインターフェースを継承します。

// インターフェースの定義
interface IDog{
    void methodA(String msg);
}

// インターフェースの継承
interface IRabbit extends IDog{
    void methodB(String msg);
}

// インターフェイスを実装する
class MyClass implements IRabbit{

    public void methodA(String msg){
        System.out.println("methodA : " + msg);
    }

    public void methodB(String msg){
       System.out.println("methodB : " + msg);
    }
}

public class Main {

    public static void main(String[] args) {
        MyClass my = new MyClass();
        my.methodA("メソッドA");
        my.methodB("メソッドB");
    }
}

結果

methodA : メソッドA
methodB : メソッドB

5. 多態性(ポリモーフィズム)

次例では子クラスを親クラスで操作します。

多態性とは主にオブジェクトで同系列の別の型に属する事が可能である事。

abstract class Animal{
    public abstract void run();
}

class Dog extends Animal{
    public void run() {
        System.out.println("Dog.runが呼び出されました。");
    }
}

class Cat extends Animal{
    public void run() {
        System.out.println("Cat.runが呼び出されました。");
    }
    
    // Catの独自メソッド
    public void nail() {
        System.out.println("Cat.nailが呼び出されました。");
    }
}

public class Main {

    public static void main(String[] args) {
        Animal obj1 = new Dog();
        Animal obj2 = new Cat();
    
        obj1.run();
        obj2.run();
    
        // obj2がCatクラスならば
        if (obj2 instanceof Cat) {
            // Catクラスに型変換を行い、Catクラスのnailメソッドを呼び出す
            ((Cat)obj2).nail();    
        } 
    }
}

結果

Dog.runが呼び出されました。
Cat.runが呼び出されました。
Cat.nailが呼び出されました。

6. ジェネリクス(テンプレート)

C++言語のようにJavaにもテンプレートがあります。

class MyTemplate<E>{
    private E data;
    
    public void set(E data) {
        this.data =data;
    }
    public E get() {
        return this.data;
    }
}

public class Main {

    public static void main(String[] args) {;
    
        MyTemplate<String> my = new MyTemplate<String>();
        
        my.set("プチモンテ");
        System.out.println(my.get());
    }    
}

<E>にStringを使用していますが、他のクラスを使用する事も可能です。

結果

プチモンテ

7. インナークラス

Javaには「メンバクラス、ローカルクラス、匿名クラス」の3種類の「インナークラス」(クラスの中にクラスを定義)があります。

メンバクラスメンバとして定義する。
ローカルクラスメソッド内にクラスを定義する。
匿名クラスメソッド内で無名のクラスを即時使用(定義+使用)する。

public class Main {
    
    // メンバクラス
    // ※解説の都合上、staticにしています。
    static class MyMember{
        public static void run() {
            System.out.println("メンバクラスの実行");
        }        
    }
    
    public static void main(String[] args) {;
        
        // メンバクラス
        MyMember.run();
    
        // ローカルクラス
        class MyLocal{
            public void run() {
                System.out.println("ローカルクラスの実行");
            }        
        }
        
        MyLocal my = new MyLocal();
        my.run();
    
        // 匿名クラス
        System.out.println(new Object(){
            String str = "匿名クラス";

            // printlnで文字列を出力する為に
            // Object.toStringをオーバーライド
            public String toString() {
                return str + "の実行";
            }
        });
    }
}

結果

メンバクラスの実行
ローカルクラスの実行
匿名クラスの実行

8. オリジナルクラスの注意事項

オーバーライド

オリジナルクラスをコレクションで使用する際には次のメソッドのオーバーライドが必要です。

Object.toString()
Object.equals()
Object.hashCode()

※コレクションの内部でこれらのメソッドを使用してオブジェクトを判定しています。

インターフェースの実装

オリジナルクラスでCollections.sort()を使用する際にはインターフェース(Comparable)のcompareTo()の実装が必要です。
オリジナルクラスでオブジェクトを複製する際にはインターフェース(Cloneable)のclone()の実装が必要です。
※実装する際には「this.xxx.clone()」で実体を新規作成して渡して下さい。





関連記事



公開日:2018年05月01日 最終更新日:2018年05月04日
記事NO:02642