第8回Java勉強会

概要

抽象クラス

  • P.69

インターフェース

  • P.106

多態性

  • P.62

詳細

抽象クラス

abstractとは「抽象的な」といった意味になります。
つまりabstractなクラスといったら抽象的なクラスといった意味になります。
抽象クラスとは、自分で処理は記述しないけど、どういった処理を記述しなければなりせんよという抽象メソッドを持ちます。
それを実装するサブクラスに処理内容の要請するクラスのことを言います。

  • abstractクラスの特徴
    • クラス定義にabstractと付く
    • abstractクラスは継承されるためにある
    • サブクラスに実装してもらいたいメソッド(抽象メソッド)を持つ
    • abstractクラスは抽象的なものなのでインスタンス化ができません。
      abstract クラス名 {
      
          // 抽象メソッドは処理内容を記述しません
          abstract 戻り値の型 メソッド名();
      }
  • abstractクラスを作る意味
    抽象クラスによって、abstractメソッドを実装しなければならないという制約をつくることで
    その抽象クラスを継承したクラス達は同じメソッドを持つことになり、それぞれのサブクラスの
    見た目をある程度そろえることができるというクラス設計の方法である。
  • 抽象クラスを実装するサンプルです。
    ファイル名:Calculation.java
    /**
     * 計算の抽象クラスです
     */
    public abstract class Calculation {
        
        // フィールド
        double x;
        double y;
        
        public Calculation(){
            this.x = 0;
            this.y = 0;
        }
        
        public Calculation(double x, double y){
            this.x = x;
            this.y = y;
        }
        
        // 抽象メソッド
        public abstract double calculate();
        
        // 抽象クラスは処理のあるメソッドを書くことができる
        public void method(){
            System.out.println("抽象クラスに書かれている処理です");
        }
    
    }
    ファイル名:Addition.java
    /**
     * 計算の抽象クラスを実装した、足し算クラスです。
     */
    public class Addition extends Calculation {
    
        /**
         * コンストラクタです
         */
        public Addition() {
            super();
        }
        
        /**
         * コンストラクタです
         */
        public Addition(double x, double y) {
            super(x,y);
        }
        
        /**
         * 抽象メソッドの実装です
         */
        public double calculate() {
            return (this.x + this.y);
        }
    
    }
    抽象クラスを実装したクラスの動作を確認します。
    ファイル名:AbstractTest?.java
    public class AbstractTest {
    
        public static void main(String[] args) {
            
            // 抽象クラスの実装を確認します
            Addition add = new Addition(10, 10);
            
            // 抽象クラスなのでインスタンス化できません
    //        Calculation calc = new Calculation();
    
            
            System.out.println("addの実行結果=" + add.calculate());
        }
    
    }

インターフェース

  • インターフェースの持つフィールドは定数となります。(public static final)
  • インターフェースのメソッドは全て抽象メソッドとなります。
  • インターフェースはインスタンス化できません。
  • 実装クラス(implementsするクラス)では複数のインターフェースを指定することができます
  • インターフェースの定義方法
    interface インターフェース名 {
        // ここに抽象メソッドやフィールドを宣言します
    }
  • インターフェースの実装方法
    class クラス名 implements インターフェース名 {
    
    }
     
  • 図形のインターフェースを定義しましす。
    ファイル名:Diagram.java
    /**
     * 図形のインターフェースです
     */
    public interface Diagram {
        
        double getArea();
        
    }
    ファイル名:Rectangle.java
    public class Rectangle implements Diagram{
    
        // フィールド宣言
        
        // 横の長さ
        double width;
        
        // 縦の長さ
        double height;
        
        
        /**
         * コンストラクタ
         */
        public Rectangle(){
            this.width = 0;
            this.height = 0;
        }
        
        /**
         * コンストラクタ
         * 横、縦の長さを設定します
         */
        public Rectangle(double width, double height){
            this.width = width;
            this.height = height;
        }
        
        /**
         * 面積を計算するメソッドです
         */
        public double getArea(){
            return (this.width * this.height);
        }
        
    }
    ファイル名:InterfaceTest?.java
    public class InterfaceTest {
    
        public static void main(String[] args) {
    
            // Rectangleを生成します
            Rectangle rectangle = new Rectangle(10, 20);
            
            // Rectangleの処理を確認
            System.out.println("rectangleの面積=" + rectangle.getArea());
            
        }
    
    }

抽象クラスとインターフェース

抽象クラスとインターフェースの違いは以下のようになります。

抽象クラスインターフェース
処理のあるメソッドを書くことができる抽象メソッドしか書くことはできない
フィールドは自由に設定できる定数しか書くことができない
extends(継承)して実装をするimplementsして実装する

多態性

継承関係やインターフェースの実装などで共通の共通のメソッドを持つクラスはスーパークラスまたは、インターフェースの変数として同じメソッドを呼び出したとしても、それぞれ異なった処理(違う振る舞い)を行うことができます。

  • 抽象クラスを使用した例
    ファイル名:Calculation.java(上記サンプルコードをそのまま使用します)
    ファイル名:Addition.java(上記サンプルコードをそのまま使用します)
     
    新たに掛け算ようのクラスを作成します。
    ファイル名:Multiplication.java
    /**
     * 計算の抽象クラスを実装した、掛け算クラスです。
     */
    public class Multiplication extends Calculation {
    
        /**
         * コンストラクタです
         */
        public Multiplication() {
            super();
        }
        
        /**
         * コンストラクタです
         */
        public Multiplication(double x, double y) {
            super(x,y);
        }
        
        /**
         * 抽象メソッドの実装です
         */
        public double calculate() {
            return (this.x * this.y);
        }
    
    }
    ファイル名:AbstractTest?.java
    public class AbstractTest {
    
        public static void main(String[] args) {
            
            // 抽象クラス型の変数に抽象クラスを実装したサブクラスのインスタンスを代入します。
            Calculation calc1 = new Addition(10, 10);
            Calculation calc2 = new Multiplication(10, 10);
    
            // 実装のことなるクラスの処理結果を確認します。
            System.out.println("calc1の実行結果=" + calc1.calculate());
            System.out.println("calc2の実行結果=" + calc2.calculate());
        }
    
    }
  • インターフェースを利用した例
    ファイル名:Diagram.java(上記で使用したサンプルコードを利用します)
    ファイル名:Rectangle.java(上記で使用したサンプルコードを利用します)
    ファイル名:Triangle.java
    public class Triangle implements Diagram {
    
        // 底辺
        double width;
        
        // 高さ
        double height;
        
        /**
         * コンストラクタ
         */
        Triangle() {
            this.width = 0;
            this.height = 0;
        }
        
        /**
         * コンストラクタ
         * 底辺・高さを設定します
         */
        public Triangle(double width, double height){
            this.width = width;
            this.height = height;
        }
        
        /**
         * 面積を計算するメソッドです
         */
        public double getArea() {
            return (width * height / 2);
        }
    
    }
    ファイル名:InterfaceTest?.java
    public class InterfaceTest {
    
        public static void main(String[] args) {
            
            // RectangleはDiagramをimplementsしているのでDigramに設定することができます
            Diagram zukei1 = new Rectangle(10, 20);
            
            // TriangleはDiagramをimplementsしているのでDigramに設定することができます
            Diagram zukei2 = new Triangle(10,20);
            
            // zukei1(Rectangle)の処理を確認
            System.out.println("zukei1の面積=" + zukei1.getArea());
            
            // zukei2(Triangle)の処理を確認
            System.out.println("zukei2の面積=" + zukei2.getArea());
        }
    
    }

キャスト

キャストとは指定した型として処理を行ってもらうことです。
クラスにおいてキャストが可能なのは、継承関係にあるクラスとの間でのみです。
継承関係のうちスーパークラスへのキャストは「アップキャスト」、サブクラスへのキャストは「ダウンキャスト」と呼ばれます。

  • アップキャスト
    サブクラスはスーパークラスに代入することができます
    RectangleのサブクラスBoxは、Rectangleとして処理を行うことができます。
    ファイル名:Rectangle.java(先ほど使用したサンプルコードをそのまま使用します)
    ファイル名:Box.java
    public class Box extends Rectangle {
    
        // フィールド
        
        // 奥行き
        double side;
        
        /**
         * コンストラクタです
         */
        public Box(){
            this.width = 0;
            this.height = 0;
            this.side = 0;
        }
        
        /**
         * コンストラクタです
         * 縦・横・奥行きを設定します。
         */
        public Box(double width, double height, double side){
            this.width = width;
            this.height = height;
            this.side = side;
        }
        
        /**
         * 体積を計算し、その結果を返します。
         */
        public double getVolume() {
            return (this.width * this.height * this.side);
        }
    }
    ファイル名:SuperAndSubTest?.java
    public class SuperAndSubTest {
    
        public static void main(String[] args) {
            
            // BoxはRectangleを継承しているのでRectangleに代入できます。
            Rectangle rec = new Box(10.0, 12.0, 15.0);
            
            // 変数の型名がRectangleなのでBox固有のメソッドは使用することができません。
            // 下の行のgetVolume()はコンパイルエラーとなります
    //        System.out.println("recの体積=" + rec.getVolume());
            
            // ただし、recはRectangleとして宣言しているのでgetArea()は呼び出すことができます。
            System.out.println("recの面積=" + rec.getArea());
            
    
        }
    
    }
  • ダウンキャスト
    サブクラスの型へキャストするには明示的にクラス名を指定する必要があります。
    代入先の変数 = (キャストしたい型) 元の変数;
     
    以下の例ではRectangleクラス(スーパークラス)にBoxクラス(サブクラス)のインスタンスを代入して
    再度Boxクラスの機能を使用する例です。
    スーパークラスをサブクラスに代入するにはキャストする必要があります。
    ただし、インスタンスが実際にBoxクラス(サブクラス)でなければプログラムは異常終了します。 ファイル名:CastTest1.java
    public class CastTest1 {
    
        public static void main(String[] args) {
            
            // RectangleにBoxのインスタンスを代入します
            Rectangle rec1 = new Box(5, 10, 20);
    
            //(以下のコメント部のようにサブクラスにスーパークラスを代入するにはそのまま代入することができません。)
            // Box box1 = rec1;
            
            // Box型へのキャスト
            Box box1 = (Box)rec1;
            System.out.println("box1の体積=" + box1.getVolume());
            
            // RectangleのインスタンスをBoxにキャストしようとするとキャストできずに異常終了します
            Rectangle rec2 = new Rectangle(8, 10);
            Box box2 = (Box)rec2;
            
        }
    
    }
     
  • instanceof
    上記サンプルのような異常終了を避けるにはinstanceofという演算子を使用します。
    instanceofは対象のインスタンスを特定することができます。
    instanceofの使用方法です。結果はbooleanの値が返ってきます。
    チェック対象となるインスタンス instanceof 特定したいクラス
     
    instanceofを使用して、キャストを確実に行うことができます。
    ファイル名:CastTest2.java
    public class CastTest2 {
        
        public static void main(String[] args) {
            
            //======================================================================
            //instanceof型チェックを行いキャストできないパターン
            // instanceofを使用してインスタンスの型をチェックできれば、例外の発生を避けることができます
            
            // 確認対象のインスタンスをRectangleで生成する
            Rectangle rec = new Rectangle(5, 6);
            
            // instanceofの結果をコンソール出力で確認
            System.out.println( "rec instanceof Box=" + (rec instanceof Box) );
            
            // この場合recはRectangleで生成しているので、if文の中の処理が実行されることはありません
            if (rec instanceof Box) {
                Box box = (Box)rec;
                System.out.println("boxの体積=" + box.getVolume());
                
            }
            
        }
    
    }

練習問題

  1. 人に関するクラスを作ってみましょう。
  • インターフェース
    • Person
      抽象メソッド - showName
  • 抽象クラス
    • NamePerson?
      Personを実装する
      フィールド - name
      コンストラクタ - nameを設定する
      抽象メソッド - showNameを実装しない
  • クラス
    • Men, Women
      NamePerson?を継承する
      showNameメソッドを実装する
    • MainPerson?
      mainメソッドを持つ実行するクラスとし、
      MenとWomenを実装しshowNameメソッドを呼び出す

Java勉強会カリキュラムに戻る


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-01-05 (月) 15:11:45 (610d)