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

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

ただいまの
回答率

90.48%

  • Java

    14116questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

java カプセル化について解説していただけないでしょうか

解決済

回答 5

投稿

  • 評価
  • クリップ 1
  • VIEW 2,827

BSS_sapporo

score 32

javaのカプセル化について勉強をしています。
以下の仕様で2.部分のコードを自身で記述するような問いなのですが、なぜこの仕様で2.のようなコードになるのかが理解ができないので、解説をお願いできないでしょうか。

また、このまま1.2.を繋げて記述すると、2.の2行目「public class Cat {」のところで「public型はそれ独自のファイル内に定義されなければなりません」と表示がでてしまいます。
初歩的な質問で申し訳ありませんが、こちらについても解説していただけないでしょうか。

仕様
<パッケージ名>
Shop     
<クラス名>
Cat     
<フィールド>
String syurui    猫の種類
String seibetsu    猫の性別
int toshi    猫の年
<コンストラクタ>
Cat() ・・・フィールドsyuruiは「スコティッシュフォールド」、seibetsuは「メス」、toshiは0で初期化
Cat(String tSyurui, String tSeibetsu, int tToshi) ・・・各引数でフィールドを初期化
<メソッド>
String getSyurui() 猫の種類を返す
String getSeibetsu() 猫の性別を返す
int getToshi()     猫の年を返す

1.2.の実行結果
スコティッシュフォールドのメス、0歳を買いました。
アメリカンショートヘアーのオス、0歳を買いました。
が出力される。

----------以下からコード----------
1.
package Shop;
public class CatShop {
    public static void main(String[] args) {
        Cat myCat = new Cat();
        CatShop.buyCat(myCat);

        myCat = new Cat("アメリカンショートヘアー","オス", 0);
        CatShop.buyCat(myCat);
    }

    static void buyCat(Cat tCat) {
        System.out.println(tCat.getSyurui() 
                + "の" 
                + tCat.getSeibetsu() 
                + "、" 
                + tCat.getToshi() + "歳を買いました。");
    }
}

2.
package Shop;
public class Cat {

    String syurui;      
    String seibetsu;    
    int toshi;          

    Cat() {
        syurui = "スコッティッシュフォールド";
        seibetsu = "メス";
        toshi = 0;
    }

    Cat(String tSyurui, String tSeibetsu, int tToshi) {
        syurui = tSyurui;
        seibetsu = tSeibetsu;
        toshi = tToshi;
    }

    String getSyurui() {
        return syurui;
    }

    String getSeibetsu() {
        return seibetsu;
    }

    int getToshi() {
        return toshi;
    }
}

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

+2

まず、フィールドを private にして、
public な get, set のアクセサを用意することがカプセル化ではありません。

インスタンスの実データを取得できて、実データを書き換えれるので
public なフィールドにしているのと同じことです。

今回のだと、フィールドは不変オブジェクトであるStringと
値渡しをするプリミティブ型のみ。
初期化はコンストラクタのみ。
取得はget経由で、setは用意しないとなっており、
データの保護は出来ているので、カプセル化と言えると思います。

ただし、setを用意しないからデータを保護できるとは限りません。
例えば以下。(通常こんなことはしませんが。。。)

class Pair {

    private String[] array;

    /**
     * コンストラクタ
     */
    public Pair(String first, String second) {
        this.array = new String[] { first, second };
    }

    /**
     * ペアを返す
     */
    public String[] getPair() {
        return array;
    }

    /**
     * 1つ目を返す
     */
    public String getFirst() {
        return this.array[0];
    }

    /**
     * 2つ目を返す
     */
    public String getSecond() {
        return this.array[1];
    }

    @Override
    public String toString() {
        return String.format("[%s, %s]", this.array[0], this.array[1]);
    }
}

public class Main {
    public static void main(String[] args) {
        Pair pair = new Pair("あ", "ア");
        System.out.println(pair); // [あ, ア] と表示

        pair.getPair()[0] = "か";
        System.out.println(pair); // [か, ア] と表示
    }
}

このように、参照のコピーを渡すようなもの(今回は配列)を
フィールドに持っている場合、getしか用意していなかったとしても、
インスタンスが持つ実データを返している時点で、データは書き換えられます。

カプセル化とはデータと実装の隠蔽のことです。

そのクラスを使う人は、そのクラスがどんなデータを持っていようと
どんな実装になっていようと知る必要はない。
public なメソッドの使い道だけが分かっていれば使えるクラス
がカプセル化されたクラスです。

例えば、java.lang.String を見てみると

private final char value[];


とあります。
文字列の正体は char の配列のようです。
Javaに文字列なんか存在しなかったわけです。

こんな事を知らなくても、Javadoc を見るだけで
indexOf ができたり subString ができたり、あたかも本当の文字列のように扱えている。
すごくカプセル化されたクラスです。
そして、当然この char の配列をそのまま取得できるような
メソッドはありません。

ついでに、java.util.HashMap を見てみます。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;

    略
}


内部にまたクラスがありますね。このクラスは公開されていません。
この Node というクラスが key と value を持ってますね。
ついでに次の Node も持ってますね。
深く見てないので分かりませんが、
1つ1つの Node が次を持つことで、あたかも1つのものに見えているようです。
当然、getNode など公開されておりません。

こんなどうでもいい事を知らなくても、
普通に put したり get できればいいんです。
これがカプセル化です。
フィールドを private にするとか set を用意しないとかっていうのは、
カプセル化のうちの1例でしかありません。

ちなみに、この Node クラスが別の Javaファイルで public なクラスとして作成されていたら、
最悪なわけです。
こんな内部でしか使わないクラスを 公開してどうすんの?ということになります。
これは実装の隠蔽(カプセル化)ができていないということです。

カプセル化されたクラスというのは、非常に使いやすいものになるため、
プログラマーはすごく意識しなければならないところですね。
set がないからカプセル化ではありません。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/08 09:35

    詳しく解説していただいてありがとうございます。
    e-ラーニングで学習しているのですが、ご回答のように噛み砕いての説明はなかったので助かりました。

    キャンセル

  • 2016/04/08 10:05

    >当然この char の配列をそのまま取得できるようなメソッドはありません。
    toCharArray()「…」
    まあ確かにコピーですけれども

    キャンセル

checkベストアンサー

+1

カプセル化はクラス内のメソッドやフィールドにアクセス制限や更新制限を掛けることです。
例えば下記のようなコードがあったとします。

class Cat {
    public String syurui;
    public String seibetsu;
    public int toshi;
}


全てのフィールドがクラスの外から丸見えです。参照変数さえわかればアクセスができてしまいます。これではプログラム上のどこで変更されるかわからなかったり、無制限で変更することができてしまいます。

このような状況をなくすためにカプセル化を進め、下記のようなコードになりました。

class Cat {
    private String syurui;
    private String seibetsu;
    private int toshi;
}


クラスの外部からはアクセスできなくなり、情報が保護されます。しかし、カプセル化をしすぎたため、値の設定、初期化すらできません。そこでコンストラクタを使って初期化します。

class Cat {
    private String syurui;
    private String seibetsu;
    private int toshi;
    Cat(String tSyurui, String tSeibetsu, int tToshi) { 
        syurui = tSyurui; 
        seibetsu = tSeibetsu; 
        toshi = tToshi; 
    }
}


これで、各値の初期化ができるようになりました。しかし、これでカプセル化がキツすぎるため設定した値が読み取りません。

各フィールドを、読み取るだけのメソッドを追加してクラスの外にフィールドを参照できるようにします。

class Cat {
    private String syurui;
    private String seibetsu;
    private int toshi;
    Cat(String tSyurui, String tSeibetsu, int tToshi) { 
        syurui = tSyurui; 
        seibetsu = tSeibetsu; 
        toshi = tToshi; 
    }
  String getSyurui() { 
        return syurui; 
    }

    String getSeibetsu() { 
        return seibetsu; 
    }

    int getToshi() { 
        return toshi; 
    } 
}


こうして、最初は誰でも更新できたクラスが初期化時にしか値を設定できず、設定した値は変更できない読み取り専用のクラスになりました。
このようなクラス内の情報(フィールドやメソッド)の公開を最小限にした結果カプセル化されたクラスが出来上がります。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/08 09:46

    具体例まで入れて解説頂きありがとうございます。
    段階ごとに理解することができて助かりました!

    キャンセル

  • 2016/04/08 11:23

    大事なアクセス修飾子に誤記があったので修正しました。ごめんなさい

    キャンセル

+1

まずは2つ目の質問から.
1つのJavaクラスファイル(ソースコード)に対して1つのクラスというのは,Javaプログラミングで推奨されていることです.
また,クラス名とクラスファイル名は一致させるべきです.(CatクラスはCat.javaに記述)

Catクラスはsyurui,seibetsu,toshiというフィールド(変数)を持っています.
このクラスのフィールドにアクセスする方法はいくつかあります.
一番単純な例はこれです.

Cat cat = new Cat();
System.out.println("種類は" + cat.syurui + "です.");


しかしこの実装では,クラス内のフィールドを直接参照するという点で問題があります.
例えばこんなこともできてしまいます.

Cat cat = new Cat();
cat.shurui = "オランウータン";
System.out.println("種類は" + cat.syurui + "です.");


クラスが持っている値に直接アクセスできるため,その値を書き換えることもできます.
こういうことを許してしまうと,クラス外から本来想定しない値が書き込まれてしまい,
バグの原因となる可能性があります.

このようなことを防ぐために,カプセル化という手法が存在します.
①クラス外から直接値を変更されたくないフィールドには「private」「protected」などを付ける
②クラス外から値を取得する場合はgetXxx(),変更する場合はsetXxx()を経由させる
setXxx()では想定しない値が書き込まれないようにチェックする
(コンストラクタでも同様に値のチェックを行う)
この2つの原則によって,他のクラスやパッケージからのアクセスが
直接フィールドに行くのではなく,メソッドを通して行われるようにする,
というのがカプセル化です.
フィールドをメソッドというカプセルによって守っているわけです.

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/08 09:52

    カプセル化とは他のクラスなどから直接アクセスできないように守る、ということなのですね。
    ご丁寧に解説いただきましてありがとうございました!

    キャンセル

0

このまま1.2.を繋げて記述すると

public classはクラスと同名のソースファイルに1つしか定義できないので、

//public class Cat {
class Cat {

とすれば無問題。

■追記:

<フィールド> 

フィールドの各変数がコンストラクタの引数と同じ内容であるので、「フィールドってのはstaticじゃないんだな」と判断できるので、

//static String syurui; //<- ではなく
String syurui; // 猫の種類

となるのです。

<コンストラクタ>
Cat() ・・・フィールドsyuruiは「スコティッシュフォールド」、seibetsuは「メス」、toshiは0で初期化 
Cat(String tSyurui, String tSeibetsu, int tToshi) ・・・各引数でフィールドを初期化

引数つきのコンストラクタでは各フィールドの値を引数から、、引数なしのコンストラクタでは各フィールドの値を初期値設定しろってことですよ。

※引数なしのほうではつい

Cat(){
  this("スコティッシュフォールド", "メス", "0");
}


とか書きたくなりますが。

<メソッド> 
String getSyurui() 猫の種類を返す 
(以下略)

各フィールドの値を「返す」と言われてますね。
返すんだから「return」でしょ?

String getSyurui() {
  return syurui; // <-猫の種類という意味のフィールド「shurui」を「return」してますね。 
}

。。。こんな感じでいいですかね?

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/08 09:59

    public classについて存じ上げませんでした。
    ご回答ありがとうございます。大変助かりました!

    キャンセル

0

あえて、一言でそれぞれをまとめてみました。

カプセル化

カプセル化は、外部に見せたくないものを隠し、外部から受け付けたくない入力は受け付けないようにする仕組みと思ってもらっていいです。(深く理解するのは、そのあとでも。)

publicなクラス

publicなクラス定義は1つのJavaファイルに1つというJavaの決まりです。
publicなクラスを複数定義するときは、その数だけ、ファイルを分ける必要があります。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/08 09:25

    publicなクラス定義は1つのファイルにつき1つという決まりだったのですね。
    そのため質問に記載したようなエラーが出ると…。
    カプセル化についても理解できました!
    ご回答ありがとうございました。

    キャンセル

関連した質問

  • 解決済

    配列priceから消費税を載せて、配列price2を返すメソッド

    課題の以下の問いに挑んでいます。 大体は出来たと思うのですが、消費税をprice2に載せた配列で上に返す事が出来ません。 ここの処理を上手く出来る方法を教えていただけないでしょうか

  • 解決済

    java 北ソフト工房

    java 北ソフト工房なんですが 最後の問題8-4がわかりません dogのところでシンボルが見つかりませんと出ます 解答例から引っ張ってきたものでも通らず なにをどうすればいい

  • 解決済

    Javaにおいてmain関数以外が書けません

    mainクラスと実行結果が与えられていて、その他のクラスなどをつくらなければならないのですが、いまいちやり方がつかめません。 countNameのように途中から大文字になるものが入

  • 解決済

    プログラムを書き換えたい

    たびたび失礼します。 教科書の問題を解いていたのですが、他の書き方でも練習したいと思いました。 前の単元でローカル変数、メンバ変数などの違いを学んだので、それに基づいて やろうと思

  • 解決済

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

    java SE8 コンストラクタの仕組みがいまいちわからないままプログラミングをしています。 コンストラクタってなにが便利なのか?なんで使うのか??いらないんじゃない?? とか思っ

  • 解決済

    java 配列の出力

    3、6種類のアルファベット "u,d,c,s,t,b" から成るn文字の文字列のうち、"uud"という並びが含まれる文字列を全て列挙するプログラムを作成してください この問題が

  • 解決済

    カプセル化のやり方 get set

    下記のプロググラムで すべてのフィールドをカプセル化したいのですが どのようにコーディングしていいか分かりません。 private を型の前に付けた後のget setのつけ方がわか

  • 解決済

    Java 引数によってクラスフィールドを変える処理について switch文

    Javaのプログラミングについて質問です。 idによってクラスフィールドを変える方法を知りたいです。 現在は下記のプログラムのようにSwitch文を用いてフィールドの変更を行ってい

同じタグがついた質問を見る

  • Java

    14116questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。