ねっとぱんだ-プログラミング勉強ブログ-

Webデザイン、プログラミングの勉強ブログ。

【java】コレクション(ArrayList)とPECS(Put/Get原則)

コレクションと配列の違い

参考
https://www.javadrive.jp/start/arraylist/
https://docs.oracle.com/javase/jp/8/docs/api/java/util/ArrayList.html
http://java.it-manual.com/advanced/arraylist.html
配列との違い
http://qiita.com/NoriakiOshita/items/49294a0a8b13ef86c94e
  • java.utilクラス内で定義。
  • リストのオプションの操作をすべて実装し、nullを含むすべての要素を許容。
  • 大きさが決まっていない配列。
  • 宣言時に10個の要素が格納できるサイズだが、自動で拡張される。

オブジェクト作成時の記述

//まずクラスをインポートする必要がある。
import java.util.ArrayList;

//以前のバージョン
ArrayList List = new ArrayList();

//J2SE5.0以降 genericsとともに記述
ArrayList <型> 変数 = new ArrayList<型>();

//例
ArrayList <Integer> List = new ArrayList<Integer>();
J2SE 5.0
Sun Microsystems社によって2004年にリリースされたJava開発プラットフォーム
http://www.weblio.jp/content/J2SE5.0

値の追加

下記でリストに追加できる。

配列.add(値);
配列.add(new 型(値));

import java.util.ArrayList;

public class Practice {

	public static void main(String arg[]){
		
		ArrayList<String> List = new ArrayList<String>();

		List.add("a");
		List.add("b");
		List.add("c");
        //上記は下記と同じ
		List.add(new String("d"));
        
		for(String value : List){
			System.out.println(value);
		}
	}
	
}

プリミティブ型は使えないのでラッパークラスを使用する。

ArrayList<Integer> List = new ArrayList<Integer>();
		
List.add(10);
List.add(20);
List.add(30);
get()
インデックスを指定して値を取り出せる。
Integer num = List.get(0);
System.out.println(num);
size()
格納している要素数の確認
System.out.println(List.size());
set()
要素の置き換え
//0番のインデックスの値を40に変えている。
List.set(0,40);
indexOf()
配列の先頭から要素を検索してインデックス番号を返す。
lastIndexOf()
配列の先頭から要素を検索してインデックス番号を返す。
List.add(10);
List.add(20);
List.add(30);
List.add(20);
		
int first = List.indexOf(20);
int second = List.lastIndexOf(20);
		
System.out.println(first + "番目の" + List.get(first));
System.out.println(second + "番目の" + List.get(second));

/*
出力結果
1番目の20
3番目の20
*/
remove()
指定したインデックスの要素の排除。
List.remove(3);

PECS(Put/Get原則)

参考
https://www.xmisao.com/2014/02/12/java-pecs-producer-extends-consumer-super.html
PECS
プロデューサー(producer)-extends, コンシューマー(consumer)-superを表す。
  • メソッドが値を取得するコレクション(Producer)は型にextendsをつける
  • メソッドで値を設定するコレクション(Consumer)は型にsuperをつける

らしいです。

つまり

  • あるメソッドが値を取得してProducerという配列に入れるとき、どういう型の変数内に格納するか、
  • あるメソッドが値Consumerという配列に別のところから取り出した値を入れるには、どういう型の変数に格納してから入れるか、

ということに関して、推奨されている形がPECSということ。だと考えました。

Iterable
java.lang
インターフェース。実装するとfor-eachループの対象にできる。
<T> = イテレーターから返される要素の方。
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Iterable.html
Collection
コレクション階層のルート・インタフェース
順序付けられているコレクションとそうでないコレクションがある
最大限の普遍性が求められる場面でコレクションを渡したり、そのコレクションを操作するために使用

Collection,Iterable,Iteretorについては後日

Stackのクラス

Stack.java

package jp.suzuki.practice.model;
import java.util.ArrayList;

public class Stack<T>{
	
	private ArrayList<T> Stack = new ArrayList<T>();
	
	//ArrayListを取得するメソッド
	public ArrayList<T> getStack(){
		return this.Stack;
	}
	
	//ArrayListに値を追加するメソッド
    
	
	//push(配列の最後に要素を追加)
	public void push(T elm){
		Stack.add(elm);
	}
	
	//pop(配列の末尾から要素を取り除く)
	public T pop(){
		//配列の長さを取得、1を引いて末尾のインデックスを取得
		return Stack.remove(Stack.size() - 1);
	}
	
	//コレクションが空かどうかを真偽値で返す
	public boolean isEmpty(){
		//コレクションのサイズが0以上ならfalse
		//0以下ならtrueを返す
		return Stack.size() > 0 ? false : true;
	}
	
}
Stackクラスを拡張したクラス

Stack2.java

package jp.suzuki.practice.model;
import jp.suzuki.practice.model.Stack;
import java.util.Collection;

public class Stack2<T> extends Stack<T> {
	
	//イテラブルオブジェクトをナンバー以下の階層の型も含めて読み込む(?)
	public void pushAll(Iterable<? extends T> src){
		//srcから取得した値(elm)を順に取り出すループ
		for(T elm : src){
			//Stackの末尾に追加(add)していく(Stackクラスのメソッド)
			push(elm);
		}
	}
	//コレクションオブジェクトをナンバー以上の階層の型も含めて読み込む(?)
	public void popAll(Collection<? super T> dst){
		//isEmptyの返り値がfalseの間(空にならない間)のループ
		while(!isEmpty()){
			//末尾の値を取得して新しいコレクションに追加してく
			dst.add(pop());
		}
	}
	
}
popAllメソッドの実行

newStackオブジェクトの値をnewCollectionオブジェクトにpopしていく。
この際newStackの型はIntegerでnewCollectionはNumberだが、
popメソッドでは引数の型を
「Collection<? super T>」
と指定している為、newCollectionオブジェクトに入る値は<? super Number>となりNumberより上の階層の型なら全て入るようになる。

package jp.suzuki.practice;
import jp.suzuki.practice.model.Stack2;
import java.util.ArrayList;
import jp.suzuki.practice.model.Collection;

public class Practice {

	public static void main(String arg[]){
		
	//値を保持するコレクションを準備
		Stack2<Integer> Stack = new Stack2<Integer>();
		//Stackの取得
		ArrayList<Integer> newStack = Stack.getStack();
		
		//newStackに値を格納
		for(int i = 1; i <= 4;i++){
			newStack.add(i);
		}
		
		//newStackの値を書き出し
		System.out.println("newStackの値");
		for(Number num : newStack){
			System.out.println(num);
		}
		
	//値を入れていくコレクションを準備
		Collection<Number> Collection = new Collection<Number>();
		//Collectionの取得
		ArrayList<Number> newCollection = Collection.getCollection();
		
		//newStackの値を後ろから取り出し
		//newCollectionの後ろに挿入していく
		Stack.popAll(newCollection);
		
		//newCollectionの値を書き出し
		System.out.println("newCollectionの値");
		for(Number num : newCollection){
			System.out.println(num);
		}
		
		System.out.println(
			"newStackは空かどうか" + Stack.isEmpty()
		);
			
	}
	
}

pushメソッドの実行

newCollectionオブジェクトの値をnewStackオブジェクトにpushしていく。
newCollectionの型はIntegerでnewStackの方はNumberだが、
pushメソッドの引数で
「Iterable<? extends T> src」
となっているのでpushされたときnewStackにはNumberから下の階層の型が全て入る。

package jp.suzuki.practice;
import jp.suzuki.practice.model.Stack2;
import java.util.ArrayList;
import jp.suzuki.practice.model.Collection;

public class Practice {

	public static void main(String arg[]){
		
	//値を入れていくコレクションを準備
		Stack2<Number> Stack = new Stack2<Number>();
		//Stackの取得
		ArrayList<Number> newStack = Stack.getStack();
		
	//値を渡すコレクションを準備
		Collection<Integer> Collection = new Collection<Integer>();
		//Collectionの取得
		ArrayList<Integer> newCollection = Collection.getCollection();
		
		//newCollectionに値を格納
		for(int i = 1; i <= 4;i++){
			newCollection.add(i);
		}
		
		//newCollectionの値を上から順に
		//newStackの後ろに挿入していく
		Stack.pushAll(newCollection);
		
		//newStackの値を書き出し
		System.out.println("newStackの値");
		for(Number num : newStack){
			System.out.println(num);
		}
		
	}
	
}