質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.23%

コンストラクタの役割、説明

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 654

rin_rin0000

score 6

java SE8
コンストラクタの仕組みがいまいちわからないままプログラミングをしています。
コンストラクタってなにが便利なのか?なんで使うのか??いらないんじゃない??
とか思ってしまいます
ちなみにカプセル化の理解度も低めです。 下記はカプセル化できていると思いますがあっていますか?

コンストラクタ意味を調べたのですが初期化するとか定義するとか書いてあって頭の悪い私では理解できなかった為、わかりやすい説明を求めます。
ちょっとしたソースコード例を記載するのでそれを説明に入れてもらっても大丈夫です。
小学生でも理解できるように教えてもらえれば幸いです。宜しくお願いします。

class Card
class CardNumber

2ファイルで記載します

public class Card {

    public static void main(String[] args) {
        // TODO 自動生成されたメソッド・スタブ

        CardNumber card = new CardNumber("キング", 10, 3);

        String str = card.getName();
        int n = card.getNumber();
        int s = card.getSheets();


        System.out.println(str);
        System.out.println(n);
        System.out.println(s);

    }

}

public class CardNumber {
    private String name;
    private int number;
    private int sheets;

    public  CardNumber(String name,int number, int sheets) {
        this.name = name;
        this.number = number;
        this.sheets = sheets;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getSheets() {
        return sheets;
    }

    public void setSheets(int sheets) {
        this.sheets = sheets;
    }

以上です。
宜しくお願いします。

※ 余談ですがGithubとかSlackって流行っているんですね

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • swordone

    2018/08/09 23:40

    sheetsではなくsuitsでは?

    キャンセル

回答 5

+5

コンストラクタが便利なのではありません。
クラスが便利なのです。

クラスとは小さな「データとアルゴリズムの集まり」であり、単体で完結する「小さなプログラム」でもあります。
例えばいわゆるトランプのカードのクラスを例に取れば、カードには
・数値(A,2~10,J,Q,K)
・マーク(スペード・ハート・ダイヤ・クラブ)
・自身が「表か裏か」
があり、また行える操作として
・裏返す
・数値を返す(裏なら分からない)
・マークを返す(裏なら分からない)
・自身を表示する(表裏によって表示が異なる)
といった操作が行えるでしょう。

しかしよく考えてください。カードは一度作成したら、数値もマークも変化しませんね?(マジシャンがマジックで使うのは別ですが)
ということは、数値にせよマークにせよ、「作る時に決まれば、あとは変更させない」方がよくなります。
そこで「カードを作る時に数値とマークを設定すればいい」となり、そのためにコンストラクタが活躍します。

まずはクラスをはじめとするオブジェクト指向の基礎をしっかりと学びましょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/11 23:13

    まずはクラスをはじめとするオブジェクト指向の基礎をしっかりと学びましょう。ということでしっかりとオブジェクト指向の基礎を学び、理解した上で多言語もどんどん学んで使えるように頑張ります!ありがとうございました。

    キャンセル

checkベストアンサー

+3

コンストラクタの役割としては、クラスの初期化(初期状態の決定)で良いと思います。

提示のCardNumberクラスの前提条件としてnamenumbersheetsが必ず指定されていないといけない場合はコンストラクタで設定させるようにクラス設計します。

引数なしのコンストラクタでインスタンス化(new CardNumber())した後にsetterで値をセットする方法だと、setterでセットし忘れたり、複数人で開発する場合にルールを守らない人が出てきて、中途半端な状態のCardNumberインスタンスが存在してしまう可能性が出てきてしまいます。(nameの無いCardNumberとか)

下記はカプセル化できていると思いますがあっていますか?

文法上はカプセル化出来ていますが、用途から考えた場合はカプセル化出来ていないかもしれません。
例えばCardNumberクラスのインスタンスは実際のカードと同じ用途のため、「インスタンス化した後に内容を変更させない」場合は以下のように色々と外からのアクセスを制限(カプセル化)します。

public class CardNumber {
    private String name;
    private int number;
    private int sheets;

    private CardNumber() {
        // 引数なしでインスタンス化されることを防ぐ
        throw new AssertionError();
    }

    public  CardNumber(String name,int number, int sheets) {
        this.name = name;
        this.number = number;
        this.sheets = sheets;
    }

    public String getName() {
        return name;
    }

    public int getNumber() {
        return number;
    }

    public int getSheets() {
        return sheets;
    }

    // カードの内容を変更させないため
    // setterは提供しない


    // CardNumberに行えるアクション(裏返す、向きを変えるなど)は
    // publicメソッドとして実装する

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

クラスを使う側の立場に立って考えると理解しやすいかもしれません。  
カプセル化にかかわることなのですが、オブジェクト指向の本質の一つはそのクラスを使う側が使いやすいようにして、間違った使い方をしないようにする、ということです(もちろんこれは一つの側面に過ぎないのですが)。
それであまりいい例が思い浮かばなかったのですが、古くからあるJavaの標準ライブラリのjava.io.Fileクラスだと、

import java.io.File;

public class MyClass {
    public static void main(String args[]) {
        File file = new File("C:/tmp/text1.txt");  // C:\\tmp\\text1.txtでも良いが、こちらがおすすめ(/はWindows/Linuxで通用する)
        if (file.exists()) {   // ファイルがあるか?
            System.out.println("file exists.");
            file.delete();  // ファイルを消す
        } else {
            System.out.println("file is not found.");
        }
        System.out.println(file.getParent());   // 一つ上の階層のパスを表示 => C:/tmp
    }
}


という感じで使って、コンストラクタで一旦パスを設定する。
そのあと、そのファイル(またはディレクトリ)に対して、やりたい操作(メソッド)を呼び出す。  
という使い方になります。

上記のようにコンストラクタでファイルの場所を指定します。
もし、コンストラクタがなければ、

File file = new File();
file.setPath("C:/tmp/text1.txt");


と冗長になってしまいますし、
途中で、file.setPath("C:/tmp/text2.txt");と誤って書き換えることがあるかもしれません。

一旦パスを指定すれば、あとはexists()メソッドで存在を確認したり、delete()メソッドでそのパスのもの(ファイルやディレクトリ)を消すことができます。
逆にsetPath()のようなメソッドはなくて、使う側にむやみやたらに無用にパスなどを書き換えられないようにカプセル化して、クラスの詳細を知らずとも、とりあえずこれを使えばこういうことができる、というようにクラスが設計されています。

実際のソースコードはこんな感じで、知らなくてもよい(または外から書き換える必要がない)ようなものはprivateになっています。
Open JDK 1.8 Fileクラス

備考: 今回の件とは関係ないですが画面などユーザの目に触れる部分ではC:/tmp/text1.txtのようなスラッシュ表記は使ってはいけないです。参考

あと、カプセル化に関してですが、
フィールドすべてにgetter/setterをつけるなら最初からすべてフィールドをpublicにしてしまえば実はよいのです(ただし、getXXX()/setXXX()があるのを前提としているフレームワーク等が存在するので伝統的にそうしていることが多いです。このあたりはJavaBeansというのが背景にあって、興味があれば調べてみてください(もう知らなくてもいいかもしれません))。最近だとこの辺りは非常にだるいのでLombokというライブラリで逃げます。

オブジェクト指向が一般的になってから出始めた言語なのでこの辺りは結構古い思想でできてしまっています。ちなみにRubyやPythonだと基本public扱いでフィールドを露出したままのことが多いです(言語仕様的にやりにくいし、思想的に不要というのもある)。

要は、カプセル化は、使う側の人が明示的に書き換える必要のないものはprivateにして書き換え不可にしてしまって、最小限の情報だけ開示するってものです。この辺まともに説明している書籍は昔はあまりなかったです。

余談ですが、あまりコンストラクタを提供するパターンのクラスを見ないぞ?と思って、かつこの辺が理解できましたら、デザインパターンを勉強してみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/11 23:12

    java.io.Fileクラスを使っての説明をしていただきありがとうございます。ファイル入出力filereader等で使用することが多々あるので合わせて学ばせていただき勉強になりました。

    キャンセル

+1

コンストラクタが無ければ以下のように書かねばならず面倒臭いからです。

CardNumber card = new CardNumber();
card.setName("キング");
card.setNumber(10);
card.setSheets(3);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

カプセル化に関して答えます。
カプセル化は変数名を変えると利用されるクラスに想定される影響を考慮されて作られたものではないかと考えています。

ソース1はソース2を抜粋したものです。コメントの意味を考えてください。

///ソース1
private static String name;///この名前をname_1にするとした時を考えてみると?①
static String name2;//この名前をname_2にするとtest2クラスはどうなる?②


①特に何の影響もない
②test2クラスがコンパイルエラー
となります。

余談なんですけど久しぶりにEclipse起動してJava書いてたら細かい文法の制約多すぎやなと思いました。
そのてんPythonはいいね。
そもそもEclipse起動したのJavaSilverの勉強して以来なんやけど・・・

///ソース2
package test;

public class test{

    private static String name;///この名前をname_1にするとした時を考えてみると?
    static String name2;//この名前をname_2にするとtest2クラスはどうなる?
    public static String getName() {
        return name;
    }

    public static void SetName(String name) {

        return name = name ;
    }

}
class test1{

    String  name = test.getName();
}

class test2{

    String s = test.name2;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/11 23:10

    ソース例を挙げていただきありがとうございました。現在java silver参考書を購入し資格へ向けて勉強中です。pythonもjavaが使えるようになったら勉強していきたいと思っています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる