20190530のJavaに関する記事は10件です。

トポロジカルソートがわからなかったので調べてBFSで実装したのち、AtCoderの問題を解いてみた。

トポロジカルソート

実装できたけどワカッテハイナイ

トポロジカルソートとは

閉路がない有向グラフの各有向辺が順方向になるようにソートすること

有向非巡回グラフ(DAG)とは
DAGとは、有向グラフ且つ閉路のないグラフのことである。これは、ある操作の手順を表す時に用いられたりする。DAGはトポロジカルソートをすることができる。

参考サイト

トポロジカルソート
動的計画法によるトポロジカルソートの数え上げとπDDの構築
動的計画法入門
アルゴリズムとデータ構造

トポロジカルソートとは、下図のような木を順に並べたものらしい

※トポロジカルソートの結果は、複数存在する場合がある(図ではトポロジカルソートの結果として、423651と426135の二つを記載)

写真.png

  • 上図の423615という木を例に、並べる順としては以下のようになる
    1. どこにも依存していないものが一番左(4)
      1. 隣接リストを作成した段階で入次数(いりじすう と読むらしい)が0のものが根
    2. その次は、(4)のみに依存しているもの(2)
      1. (4)をリザルト用のListにaddし、(4)から(2)への辺を削除した結果、(2)の入次数は0になる
        1. (4)から(2)への辺を削除とは、「(4)をリザルトリストへaddする際に、(4)から他の頂点へののびている辺を隣接リストから探し、次の接続先の入次数をマイナスする」ことを指している。
    3. その次は、(2)のみに依存しているもの(3 または 6)
      1. (2)をリザルト用のListにaddし、(2)から(3)および(6)への辺を削除した結果、(3)および(6)の入次数は0になる
    4. その次は、(3) または (6)のみに依存しているもの([3]で(3)を選択しているなら(6)、[3]で(6)を選択しているなら、(2)のみに依存している(3)((6)と同列のもの)または(6)のみに依存している(1)または(5))
    5. 以下、全ての依存関係を確認していく

BFSで実装してみる

※実装したら下記のAOJのサイトで確認することができる
GRL_4_B | トポロジカルソート | グラフ | Aizu Online Judge

    private void solveA2() {
        int v = nextInt();
        int e = nextInt();

        /*
         *隣接リストの作成
         */
        List<List<Integer>> adj = new ArrayList<List<Integer>>();
        for (int i = 0; i < v; i++) {
            adj.add(new ArrayList<Integer>());
        }

        for (int i = 0; i < e; i++) {
            int from = nextInt();
            int to = nextInt();
            adj.get(from).add(to);
        }
        // 入次数が0のものを判定するための配列
        int indegree[] = new int[v];
        // 入次数0を判定
        for (int i = 0; i < v; i++) {
            List<Integer> temp = adj.get(i);
            //iをfromとするnode達
            for (int node : temp) {
                //入次数の個数
                indegree[node]++;
            }
        }

        /*
         * queueの作成
         * 入次数0のものをqueueに詰める
         * 入次数0から調査していく
         */
        ArrayDeque<Integer> q = new ArrayDeque<Integer>();
        for (int i = 0; i < v; i++) {
            if (indegree[i] == 0) {
                q.addLast(i);
            }
        }

        //訪問済み頂点数
        int cnt = 0;

        // トポロジカルソートの結果
        List<Integer> res = new ArrayList<Integer>();

        /*
         * BFS
         */
        while (!q.isEmpty()) {
            // 接続先の頂点を探索開始
            int u = q.removeFirst();
            //入次数0なのでリザルトにadd
            res.add(u);

            /*
             * この頂点の次の接続先の入次数を-する
             * その結果、入次数=0となる場合はソートリザルトに追加し、次の探索に利用する
             */
            for (int node : adj.get(u)) {

                indegree[node]--;
                if (indegree[node] == 0) {
                    q.addFirst(node);
                }
            }
            cnt++;
            if (cnt > v) {
                System.out.println("graph内に循環有");
                return;
            }
        }

        for (int i : res) {
            out.println(i);
        }
    }

AtCoderの問題を解いてみる

D - Restore the Tree

トポロジカルソートを使う問題ということでチャレンジしてみる

結論としては、トポロジカルソートのロジックをほぼ改変なしで解けた

写真 (1).png

  • 入力例 2 の構造は上記
    • 黒い辺が本来の木構造で、赤い辺はあとから足された辺
    • 元の木構造は「根以外の各頂点には、その親から一本の有向辺が伸びています」との記述があるので特定できる
  • トポロジカルソートで並べるときに、自分の入次数が0になる時(自分に向かっている辺を削除した時)の頂点が親(うまい言い回しがわからない。。。)
    • 例えば、隣接リストを作成した時の(1)の入次数は3
      • (1)への辺があるのは(4)(2)(6)だが、トポロジカルソートしていくと、
      • (4)(2)(6)の順で(1)への辺を削除していく
      • (6)→(1)の辺を削除した時に(1)への入次数は0になる
      • (1)への入次数が0になった時の(6)が自分の親となる(複数の親がいるときは、根から一番遠い親が元の木構造の時の親)

AtCoder:全国統一プログラミング王決定戦予選(D - Restore the Tree)

    private void solveA() {
        int v = nextInt();
        int e = nextInt();

        List<List<Integer>> rinsetuList = new ArrayList<List<Integer>>();

        for (int i = 0; i < v; i++) {
            rinsetuList.add(new ArrayList<Integer>());
        }

        int[] indegrees = new int[v];
        for (int i = 0; i < v - 1 + e; i++) {
            int from = nextInt() - 1;
            int to = nextInt() - 1;
            rinsetuList.get(from).add(to);
            indegrees[to]++;
        }

        ArrayDeque<Integer> queue = new ArrayDeque<Integer>();
        for (int i = 0; i < indegrees.length; i++) {
            if (indegrees[i] == 0) {
                queue.addLast(i);
            }
        }

        int[] par = new int[v];
        int cnt = 0;
        while (queue.size() != 0) {
            int index = queue.removeLast();

            for (Integer nextDegree : rinsetuList.get(index)) {
                int nextCnt = --indegrees[nextDegree];
                if (nextCnt == 0) {
                    queue.addLast(nextDegree);
                    par[nextDegree] = index + 1;
                }
            }
            if (cnt > v) {
                out.println("graph内に循環有");
                return;
            }
        }

        for (int i : par) {
            out.println(i);
        }

    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Keycloakでマルチプロジェクト

はじめに

複数プロジェクトでマイクロサービスを利用するために、リクエストごとにKeycloakのレルムの書き換えを行ってみたが、レルムごとにユーザー管理するのは現実的ではないことに気付き、Keycloakで行っていた認証・認可の認可の部分を切り離すことにした。

試したこと

バックエンドのマイクロサービスをSpring Bootで実装していたので、SpringのSecurity Filter Chainに、新しい認可情報を付加するフィルターを追加してみた。

プロジェクトごとに電子メールアドレスをユーザーの一意識別子としてメンバーを登録すれば、KeycloakのJWTトークンの電子メールアドレスでユーザーの名寄せができるという理屈です。

同じユーザーが複数のプロジェクトに参加するユースケースでは、プロジェクトごとに認可情報を管理したいのでKeycloakから切り離した方が自由度が高くなります。

尚、新しいフィルターの追加場所は、SessionManagementFilter.classの後が良さそうです。

ソースコード

public class CustomKeycloakFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final ProjectMemberService service;

    @Override
    public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
        logger.debug("######## CUSTOM KEYCLOAK FILTER INITIALIZED ########");
    }

    public CustomKeycloakFilter(ProjectMemberService service) {
        this.service = service;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        logger.debug("######## CUSTOM KEYCLOAK FILTER ########");

        // extract project id from the request header
        String projectId = request.getHeader("project-id");
        logger.debug("++++++++ PROJECT ID: {} ++++++++", projectId);

        // extract Kycloak authentication token
        Principal principal = request.getUserPrincipal();
        if (principal != null && principal instanceof KeycloakAuthenticationToken) {

            logger.debug("++++++++ AUTHENTICATED BY KEYCLOAK ++++++++", principal.getClass().getName());

            KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) principal;
            KeycloakSecurityContext context = (KeycloakSecurityContext)token.getAccount().getKeycloakSecurityContext();
            AccessToken accessToken = context.getToken();

            // extract email from the access token as a unique user identifier.
            String email = accessToken.getEmail();

            logger.debug("++++++++ email: {} ++++++++", email);

            if (projectId != null && email != null) {

                // retrieve project user permissions from the project database by project id and user email 
                Collection<? extends GrantedAuthority> authorities = service.getAuthz(UUID.fromString(projectId), email);

                List<String> authorityStringList = new ArrayList<>();
                authorities.forEach(o -> authorityStringList.add(o.getAuthority()));
                logger.debug("++++++++ AUTHOTITIES: {} ++++++++", authorityStringList);

                // generates a new authentication token with reloaded user permissions
                KeycloakAuthenticationToken newAuthenticationToken = new KeycloakAuthenticationToken(token.getAccount(), false, authorities);

                logger.debug("++++++++ NEW AUTHENTICATION TOKEN: {} ++++++++", newAuthenticationToken.toString());

                SecurityContext sc = SecurityContextHolder.getContext();

                // replaces authentication token with the new one
                sc.setAuthentication(newAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

まとめ

Keycloakの認証・認可の認可の部分を切り離すことにより、マルチプロジェクト(マルチテナント)に対応することができた。認可情報をプロジェクトごとに管理できるので、自由度の高いプロジェクト運用ができそうです。

参考資料

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

0から始め、Java Silver習得した話

はじめに

アンニョンハセヨ~(୨୧ᵕ̤ᴗᵕ̤) チオンです。
今日はJavaSilver取得するまでの話を皆さんと共有したいと思います。
それではスタート~~

勉強前のスペック

・未経験で2カ月前IT会社に入社し、実務経験なし。
・Javaに関してはオブジェクト指向の言語だという理解程度
・Pythonを独学で1ヶ月間勉強

勉強期間

・勉強期間:2019年3月中旬~2019年5月末(約2カ月半)
・勉強時間:平日 0.5~1時間、 土日 3~6時間
・受験日:2019年5月30日

勉強方法

・開始~1カ月目(黒本3周)

はじめはJavaの知識がなく、黒本の1章解くのも大変だったので、解説を理解することからやりました。1章から9章まで3周読みながら理解できない概念や問題はチェックして今後みれるようにまとめました。
その後、10章の模擬問題を解いてみました。当時、10章の正解率が44%で低くて少しショック。

・2カ月目(黒本2周)

Java Silver問題の傾向を理解し、11章の模擬問題を解いてみました。11章の正解率が66%
合格できそうな気分で嬉しく、間違った問題を中心に黒本を2周読みました。

・試験前の2週間(黒本1周、ネット問題)

いまだによく間違う問題や弱い概念を把握してノートに整理してメモして勉強しました。
また、試験前の1週間はネットにあるJava silver問題を解いてみたりしながら勉強しました。

Oracle Javasilver サンプル問題?
http://www.oracle.com/jp/education/certification/ocjp-silver-se8-3494542-ja.html

試験結果

正解率90%で合格しました。“(⌯¤̴̶̷̀ω¤̴̶̷́)✧

本番の問題は黒本の問題とすごく似ていて、初めてみる問題は2問程度。
黒本の復習が大事だと思いました。

感想

資格の勉強を通じてJavaの理解もできたので、良かったです。現場でJava に携わりたい。Javaで何か作りたいというモチベーションがUPしました!
何も分からなかった私も資格を取得できたので、皆さんもできると思います!応援します。

※日本語で少し不自然な表現がありましたら、すみません。日本語ももっと勉強します★

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】継承とインターフェース実装を同時に行った場合のメソッド呼び出しのエラー

Java研修中に起こったエラーについての覚え書き。

コードおよびコンパイルエラー

Sample.java
abstract class A{
    abstract void aMethod();
} 

interface B{
    void bMethod();
}

//A継承
class OnlyA extends A{
    public void aMethod(){};
}

//A継承・B実装
class AB extends A implements B{
    public void aMethod(){};

    public void bMethod(){};
}

public class Main {
    public static void main(String[] args){
        A[] a = new A[]{new OnlyA(), new AB()};

        //抽象クラスメソッド呼び出し
        a[0].aMethod();
        a[1].aMethod();

        //インターフェースメソッド呼び出し
        a[1].bMethod();
    }
}

/*
Main.java:26: error: cannot find symbol
        a[1].bMethod();
            ^
  symbol:   method bMethod()
  location: class A
*/

呼び出せませんでした。

解決法

Main.java
public class Main {
    public static void main(String[] args){
        A var1  = new AB();
        B var2  = new AB();
        AB var3 = new AB();

        var1.bMethod(); //これはダメ
        var2.bMethod(); //これはオッケー
        var3.bMethod(); //これもオッケー
    }
}

この場合、インターフェース型で宣言するかそれを実装した型で宣言しないとダメみたいですね。

インスタンスclass AB extends A implements Bのメソッドに直接アクセスしてるもんだと思ってたけどclass Aで宣言してるからまずそっちにアクセスしてるのかな?

継承だけ・実装だけの場合、親子両方定義するのでcannot find symbolが出ることはまあないんですが、このように継承と実装を同時に行うと注意しないといけないですね。
(あまりインターフェースを使ったことがないのがバレる形になった)

もっと勉強が必要と感じた次第です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AndroidStudio 他のプロジェクトのモジュール内のC++を参照しよう(Java / kotlin)

「AndroidStudio モジュール内のC++を参照する(Java / kotlin)」
https://qiita.com/sanoh/items/484e61729ab69f250fec

で作成したモジュールを他のプロジェクトから参照する手順の覚書

■Step1:プロジェクト作成

2019-05-30.png
「File」「New」「New Project」からプロジェクトを作成します。
2019-05-30 (1).png
「Native C++」を選択してから「Next」を押します。
2019-05-30 (2).png
今回のNameは「test03」で
Save locationは作業ディレクトリを指定
Languageは「Java」を指定します(Kotklinでも問題ないです)
設定が終われば「Next」で次の画面に
2019-05-30 (3).png
「Finish」でプロジェクト作成は終了です。

■Step2:他のプロジェクトのモジュールを参照

settings.gradleを編集して外部のモジュールを参照します。

settings.gradle
include ':app', ':native-module'
project(':native-module').projectDir = new File(settingsDir, '../test02/test02module')

参照したいtest02moduleの位置は、ここのプロジェクトで調整してください
ここで「Sync Now」を押せば
2019-05-30 (5).png
プロジェクトに追加されたことがわかると思います。

次にアプリケーションのbuild.gradle(Module: app)を編集します。

build.gradle
android {
  :
  :
}

dependencies {
  :
  :
    implementation project(':native-module')
}

native-moduleを追加したのでこれでアプリケーションから参照が可能になります。

■Step3:アプリケーションから参照

CmakeList.txtに登録します。

CmakeList.txt
![2019-05-30 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122121/556e419a-8a91-2280-f71a-d034063919f0.png)

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib.cpp)

include_directories(../../../../../test02/test02module/src/main/cpp)
add_library( native-module
        SHARED
        IMPORTED )
set_target_properties( native-module
        PROPERTIES IMPORTED_LOCATION
        ../../../../../../test02/test02module/src/lib/${ANDROID_ABI}/libnative-module.so)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib
        native-module
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

最後にnative-lib.cppから、モジュール内のクラスを参照します。

native-lib.cpp
#include <jni.h>
#include <string>

#include "subTest.h"

extern "C" JNIEXPORT jstring JNICALL
Java_l_toox_test03_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    subTest ss;
    ss.Hoge(32);
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Desktop : OpenCV Java Repository

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaの配列の初期化方法

いろいろな宣言&初期化方法があるので、コンパイルエラーになるものならないものを洗い出したものです。

public class A {

    public static void main(String[] args) {
        /* 一次元配列 */
        int[] ary = new int[3];
        int ary2[] = new int[3];
        int []ary3 = new int[3];

        int ary4[];
        ary4 = new int[3];

//      int ary4[];
//      ary4 = {1, 2, 3};  #=> コンパイルエラー

        int ary5[] = {1, 2, 3};
        int ary6[] = new int[] {1, 2, 3};  // 型を明示して初期化
//      int ary7[] = new int[3] {1, 2, 3};  #=> コンパイルエラー

        /* 二次元配列 */
        int[][] ary8 = new int[3][3];
        int ary9[][] = new int[3][3];
        int []ary10[] = new int[3][3];
        int[] ary11[] = new int[3][3];
        int [][]ary12 = new int[3][3];

        int ary13[][] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列を要素として持つリストのソート(Java)(Comparator)

配列を要素として持つリストのソート

以下のように、配列の最初の要素が 20,30,10 から 10,20,30 となるように配列を昇順に並べ替えてみます。

[20, 3]     [10, 2]
[30, 1] → [20, 3]
[10, 2]     [30, 1]

配列を要素として持つリストは、JavaではComparatorを用いて並べ替えることができます。(他にもラムダ式などが使えます。)

Comparator

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[0],o2[0]);
    }
};

Comparatorインターフェイスを実装したクラスを用いて、大小を比較する基準のようなものを作ることができます。これによって、配列の大小の比較を定義します。

Comparator<int[]> comparator = new Comparator<int[]>() {};の部分では、Comparatorインターフェイスを実装したクラスのインスタンスの生成とメソッドの定義を同時に行う匿名クラスを用いています。

@Overrideされているメソッドpublic int compare(int[] o1,int[] o2) {}
ではint型配列のo1,o2の大小を比較するcompareメソッドを定義しています。

return Integer.compare(o1[0],o2[0])によってint型配列o1とo2の大小は、o1[0]とo2[0]の大小で定義されました。

以上により、配列の0番目の要素の大小配列の大小の基準とするcomparatorを生成することができました。

先ほど定義したcomparatorをソートの引数に加えることにより、配列を要素とするリストをソートすることができます。

Collections.sort(list,comparator);

実行例

0番目の要素を基準

List<int[]> list = new ArrayList<int[]>();
int[] a={20,3};
int[] b={30,1};
int[] c={10,2};
list.add(a);
list.add(b);
list.add(c);

//[20,3]
//[30,1]
//[10,2]

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[0],o2[0]);
    }
};

Collections.sort(list,comparator);

for (int i=0;i<list.size();i++) {
    System.out.println(Arrays.toString(list.get(i)));
}

//[10, 2]
//[20, 3]
//[30, 1]

1番目の要素を基準

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[1],o2[1]);
    }
};

Collections.sort(list,comparator);

//[30, 1]
//[10, 2]
//[20, 3]

0番目の要素を基準、降順

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o2[0],o1[0]);
    }
};

Collections.sort(list,comparator);

//[30, 1]
//[20, 3]
//[10, 2]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

int型配列を要素として持つリストのソート(Java)(Comparator)

int型配列を要素として持つリストのソート

以下のように、配列の最初の要素が 20,30,10 から 10,20,30 となるように配列を昇順に並べ替えてみます。

[20, 3]     [10, 2]
[30, 1] → [20, 3]
[10, 2]     [30, 1]

配列を要素として持つリストは、JavaではComparatorを用いて並べ替えることができます。(他にもラムダ式などが使えます。)

Comparator

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[0], o2[0]);
    }
};

Comparatorインターフェイスを実装したクラスを用いて、大小を比較する基準のようなものを作ることができます。これによって、配列の大小の比較を定義します。

Comparator<int[]> comparator = new Comparator<int[]>() {};の部分では、Comparatorインターフェイスを実装したクラスのインスタンスの生成とメソッドの定義を同時に行う匿名クラスを用いています。

@Overrideされているメソッドpublic int compare(int[] o1,int[] o2) {}
ではint型配列のo1,o2の大小を比較するcompareメソッドを定義しています。

return Integer.compare(o1[0], o2[0])によってint型配列o1とo2の大小は、o1[0]とo2[0]の大小で定義されました。

以上により、配列の0番目の要素の大小配列の大小の基準とするcomparatorを生成することができました。

先ほど定義したcomparatorをソートの引数に加えることにより、配列を要素とするリストをソートすることができます。

Collections.sort(list, comparator);

実行例

0番目の要素を基準

List<int[]> list = new ArrayList<int[]>();
int[] a = {20, 3};
int[] b = {30, 1};
int[] c = {10, 2};
list.add(a);
list.add(b);
list.add(c);

//[20, 3]
//[30, 1]
//[10, 2]

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[0], o2[0]);
    }
};

Collections.sort(list, comparator);

for (int i=0;i<list.size();i++) {
    System.out.println(Arrays.toString(list.get(i)));
}

//[10, 2]
//[20, 3]
//[30, 1]

1番目の要素を基準

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o1[1], o2[1]);
    }
};

Collections.sort(list, comparator);

//[30, 1]
//[10, 2]
//[20, 3]

0番目の要素を基準、降順

Comparator<int[]> comparator = new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return Integer.compare(o2[0], o1[0]);
    }
};

Collections.sort(list, comparator);

//[30, 1]
//[20, 3]
//[10, 2]

AtCoderでよく出ます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カプセル化について

image.png

説明する時にいつも読むのでまとめ

カプセル化とは

クラスに変数とメソッドを凝集し、隠蔽し、インスタンス化して量産・利用できるようにしたもの

  • まとめて、隠して、たくさん作る仕組み
  • クラスとは意訳すると「種類」
  • インスタンスとは意訳すると「実体」
  • クラスで定義したものはインスタンス化することで利用できる
  • なので、クラスとインスタンスはセットで考えると良い
  • 独立性の高い部品を作る仕組み
  • オブジェクト指向三大要素の1つ
  • 種類と実体は集合論でいう集合と要素に相当する

特徴

概念的側面(現実世界)

分類ができる

  • 例えば「アメリカンショートヘア」と「日本猫」と「パグ」と「柴犬」
    • 「猫」という種類の「アメリカンショートヘア」と「日本猫」という実体
    • 「犬」という種類の「パグ」と「柴犬」という実体

技術的側面(プログラミング)

インスタンス化する時に実体に必要な情報を渡せる。インスタンス化された対象は状態を管理し続ける。インスタンス化された対象は公開する情報が制限されている

  • インスタンス化をすると、コンストラクタが実行される
  • コンストラクタが実行されると、フィールドが設定される
  • コンストラクタとは意訳すると「構築するもの」
  • フィールドとは意訳すると「属性情報」
  • 例えば「Cat」というクラスと「ねこさん」というインスタンス
    • 「Cat」クラスがインスタンス化するのに必要な情報は「名前」(だけ今回は)
    • 「Cat」がインスタンス化するとコンストラクタでインスタンスに必要な情報である「ねこさん」が設定される
    • 「ねこさん」誕生
    • 「ねこさん」であり続けるので「ねこさん」は何回でも鳴ける

プログラミング技術における「クラス」の利用

Cat.java
public class Cat {
    String name;

    Cat(String name) {
        this.name = name;
    }

    public void cry() {
        System.out.println("にゃ〜");
    }
}

プログラミング技術における「インスタンス」の利用

Main.java
public class Main {
    public static void main(String[] args) {
        Cat nekosan = new Cat("ねこさん");
        nekosan.cry();
    }
}

ポイント

  • 役割を1つにする
  • クラスは型として扱うことができる
  • 説明で使われる用語が視点や文脈や人によって違ったりする
  • 大体同じ
    • インスタンス化
    • インスタンス生成
    • 生成する
    • newする

-> new の部分がコード的には相当する

  • 大体同じ
    • 初期化する
    • コンストラクタする
    • initializeする
    • initする

->今回(Java)でいうと「Dog{」の部分。PHPとかだと「__constract」。Rubyとかだと「initialize」。Pythonとかだと「__init__」。Swiftとかだと「init」

  • 大体同じ
    • フィールド
    • メンバー変数
    • インスタンス変数

関連記事

オブジェクト指向でなぜつくるのかまとめ

書籍情報

平澤 章 (著) オブジェクト指向でなぜつくるのか 第2版
https://amzn.to/2VSrzwe

雑感

カプセル化はプログラミング技術的に説明しようとすると複数要素や視点がある
説明する言葉も多いのと、視点によって説明対象が同じでもニュアンスが違ったりするので一番大事で難しい感。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む