blog

Java開発者として、このJavaジェネリックスとコンテナの知識ポイントは、本当によく見ておく必要がある!

以下のメソッドは、一般的に2つのコンテナ間の操作に使用されます。しかし、1つのコンテナ、それ自身と独自の交差、マージ、差分、およびその他の操作を使用することもできますが、一般的には必要ありません。 以...

Oct 1, 2020 · 11 min. read
シェア

コンテナ・フレームワーク図:

Collection

Set インタフェース: Collection のサブインタフェース >> Unordered non-repeatable HashSet: Set インタフェースの実装クラス

リスト・インターフェース:Collection のサブインターフェース >> ordered repeatable

ArrayList:Lisインタフェースの実装クラスtは、効率的なクエリです LinkedList:効率的な追加と削除するListインタフェースの実装クラス Vector:スレッドセーフListインタフェースの実装クラス

Map

HashMap: Map インターフェース実装クラス

Collection< E >インターフェース共通メソッド

以下のメソッドは、一般に2つのコンテナ間の操作に使用されます。ただし、1つのコンテナを使用して、それ自身との交点、マージ、差分などを実行することも可能ですが、通常は必要ありません。注意:2つのコンテナのデータ型は同じでなければなりません。

コードクイズは以下の通りです:

import java.util.ArrayList;
import java.util.Collection;
public class TestCollection {
	
	public static void main(String[] args) {
		
		Collection<String> coll = new ArrayList<>();		
		coll.add("1");
		coll.add("2");
		coll.add("3");
		System.out.println(coll);//[1, 2, 3]
		coll.clear();
		System.out.println(coll);//[]
		
		coll.add("A");
		coll.add("B");
		coll.add("C");
		coll.add("DE");
		System.out.println(coll);//[A, B, C, DE]
		
//		coll.remove(2);//この意味は、配列の添え字2要素を削除するのではなく、整数2を削除することである
		coll.remove("DE");
		System.out.println(coll);//[A, B, C]
		
		int a = coll.size();
		System.out.println(a);//3
		
		boolean b = coll.isEmpty();
		System.out.println(b);//false
		
		boolean c = coll.contains("A");
		System.out.println(c);//true
		
		Object[] d = coll.toArray();
		System.out.println(d);//[Ljava.lang.Object;@15db9742
		
		System.out.println("=========================================");
		
		Collection<String> coll02 = new ArrayList<>();
		coll02.add("B");
		coll02.add("C");
		coll02.add("D");
		System.out.println("coll:"+coll);//coll:[A, B, C]
		System.out.println("coll02:"+coll02);//coll02:[B, C, D]
		
		boolean e = coll.containsAll(coll02);
		System.out.println(e);//false
		
		coll.retainAll(coll02);
		System.out.println(coll);//[B, C]
		
		coll.addAll(coll02);
		System.out.println(coll);//[B, C, B, C, D]
		
		coll.removeAll(coll02);
		System.out.println(coll);//[]
		
	}
	
}

List< E >インターフェース共通メソッド

コードクイズは以下の通りです:

import java.util.ArrayList;
import java.util.List;
/**
 * 	Listインターフェースのメソッドは、添え字を追加する。
 */
public class TestList {
	
	public static void main(String[] args) {
		
		List<Integer> list = new ArrayList<>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);
		System.out.println(list);//[1, 2, 3, 4, 5]
		
		list.add(1,11);
		System.out.println(list);//[1, 11, 2, 3, 4, 5]
		
//		list.remove(11);//ここでは、要素の内容としての11ではなく、演算の添え字としての11がデフォルトとなる
		
		list.remove(1);
		System.out.println(list);//[1, 2, 3, 4, 5]
		
		list.set(0,11);
		System.out.println(list);//[11, 2, 3, 4, 5]
		
		int a = list.get(0);
		System.out.println(a);//11
		
		list.add(5);
		list.add(4);
		list.add(3);
		list.add(2);
		list.add(11);
		
		int b = list.indexOf(11);
		System.out.println(b);//0
		
		int c = list.lastIndexOf(11);
		System.out.println(c);//9
		
		List<Integer> list02 = new ArrayList<>();
		list02.add(12);
		list02.add(14);
		list02.add(16);
		
		list.addAll(1,list02);
		System.out.println(list);//[11, 12, 14, 16, 2, 3, 4, 5, 5, 4, 3, 2, 11]
			
	}
	
}

CollectionインターフェイスのremoveメソッドとListインターフェイスのremoveメソッドを区別してください。

import java.util.ArrayList;
import java.util.List;
/**
 * 	CollectionインターフェイスのremoveメソッドとListインターフェイスのremoveメソッドを区別する
 * 	
 */
public class TestRemove {
	
	public static void main(String[] args) {
		
		List<String> list01 = new ArrayList<>();
		list01.add("1");
		list01.add("2");
		list01.add("3");
		list01.add("4");
		list01.add("5");
		System.out.println(list01);//[1, 2, 3, 4, 5]
		
		//removeメソッドの親インターフェースCollection
		list01.remove("1");
		System.out.println(list01);//[2, 3, 4, 5]
		
		//Listインターフェース removeメソッド
		list01.remove(1);
		System.out.println(list01);//[2, 4, 5]
		
		System.out.println("=========================================");
		
		List<Integer> list02 = new ArrayList<>();
		list02.add(1);
		list02.add(2);
		list02.add(3);
		list02.add(4);
		list02.add(5);
		list02.add(11);
		
		list02.remove(1);
		System.out.println(list02);//[1, 3, 4, 5, 11]
		
		/**
		 * java.lang.IndexOutOfBoundsException: Index: 11, Size: 5
		 */
		list02.remove(11);//int型ではデフォルトで添え字インデックスを参照するため、これは以下のような表が範囲外の例外を報告する。
		
	}
	
}

練習1:ArrayListの手書きシミュレーションで配列を作成し、関数に要素を追加します:

/**
 * 	手書きのArrayListでコンテナを作成し、要素を追加する関数
 * 	ジェネリックを追加する
 */
public class WriteArrayList<E> {
	
	private Object[] array;
	private int size;//配列の添え字
	private static final int DEFAULT = 10;
	
	public WriteArrayList() {
		array = new Object[DEFAULT];
	}
	
	public WriteArrayList(int index) {
		array = new Object[index];
	}
	
	public void add(E data) {
		array[size++] = data;
	}
	
	@Override
	public String toString() {
		// [a,b,c]フォーマット出力
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(int i=0; i<size; i++) {
			sb.append(array[i]+",");
		}
		sb.setCharAt(sb.length()-1,']');//最終出力のカンマ「,」を「,」に置き換える。]'記号、コード中の一重引用符を二重引用符に変更することはできない
		return sb.toString();
	}
	
	public static void main(String[] args) {
		WriteArrayList<Integer> wal = new WriteArrayList<>();
		wal.add(11);
		wal.add(12);
		wal.add(13);
		System.out.println(wal);
	}
	
}

演習2:演習1に配列展開を追加

/**
 * 	配列の拡張を増やす
 */
public class WriteArrayList<E> {
	
	private static Object[] array;
	private int size;//配列の添え字
	private static final int DEFAULT = 10;
	
	public WriteArrayList() {
		array = new Object[DEFAULT];
	}
	
	public WriteArrayList(int index) {
		array = new Object[index];
	}
	
	public void add(E data) {
		//いつ拡張するか?
		if(size==array.length) {
			//どのように拡張するのか?
			Object[] newArray = new Object[array.length+(array.length>>1)];//アナロジー10+10/2,ここでは、プラス記号'+'よりも優先順位が高い。>>'
			System.arraycopy(array, 0, newArray, 0, array.length);
			array = newArray;
		}
		array[size++] = data;
	}
	
	@Override
	public String toString() {
		// [a,b,c]フォーマット出力
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(int i=0; i<size; i++) {
			sb.append(array[i]+",");
		}
		sb.setCharAt(sb.length()-1,']');//最終出力のカンマ「,」を「,」に置き換える。]'記号、コード中の一重引用符を二重引用符に変更することはできない
		return sb.toString();
	}
	
	public static void main(String[] args) {
		WriteArrayList<Integer> wal = new WriteArrayList<>();
		for(int i=0; i<40; i++) {
			wal.add(i);
		}
		System.out.println(wal);
	}
	
}

演習3:演習2にset()メソッドとget()メソッドを追加し、配列の境界検出を追加します。

/**
 * 	setメソッドを追加する
 * 	配列の境界チェックを追加する
 */
public class WriteArrayList<E> {
	
	private static Object[] array;
	private int size;//配列の添え字
	private static final int DEFAULT = 10;
	
	public WriteArrayList() {
		array = new Object[DEFAULT];
	}
	
	public WriteArrayList(int index) {
		//判定を追加する
		if(index<0) {
			throw new RuntimeException("コンテナの容量を負にすることはできない: "+index);
		} else if(index==0) {
			array = new Object[DEFAULT];
		} else {
			array = new Object[index];
		}
	}
	
	public void add(E data) {
		//いつ拡張するか?
		if(size==array.length) {
			//どのように拡張するのか?
			Object[] newArray = new Object[array.length+(array.length>>1)];//アナロジー10+10/2,ここでは、プラス記号'+'よりも優先順位が高い。>>'
			System.arraycopy(array, 0, newArray, 0, array.length);
			array = newArray;
		}
		array[size++] = data;
	}
	
	@Override
	public String toString() {
		// [a,b,c]フォーマット出力
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(int i=0; i<size; i++) {
			sb.append(array[i]+",");
		}
		sb.setCharAt(sb.length()-1,']');//最終出力のカンマ「,」を「,」に置き換える。]'記号、コード中の一重引用符を二重引用符に変更することはできない
		return sb.toString();
	}
	
	public E get(int index) {
		checkIndex(index);
		return (E)array[index];
	}
	
	public void set(int index, E data) {
		checkIndex(index);
//		//インデックスの法的判断、インデックス間隔は[0,size)
//		if(index<0||index>size-1) {
//			//不正、手動で例外をスローする
//			throw new RuntimeException("インデックスは合法ではない:"+index);
//		}
		array[index] = data;
	}
	/**
	 * 	多くの場所で、インデックスindexが合法かどうかを判断する必要があるため,
	 * 	というわけで、ここに独立したメソッドを書いて、必要なときに直接呼び出そう。
	 */
	public void checkIndex(int index) {
		//インデックスの法的判断、インデックス間隔は[0,size)
		if(index<0||index>size-1) {
			//不正、手動で例外をスローする
			throw new RuntimeException("インデックスは合法ではない:"+index);
		}
	}
	public static void main(String[] args) {
		WriteArrayList<Integer> wal = new WriteArrayList<>();
		for(int i=0; i<40; i++) {
			wal.add(i);
		}
		System.out.println(wal.get(10));
		
		wal.set(1,100);
		System.out.println(wal);
		
	}
	
}

練習問題 4: 練習問題 3 に remove()、size()、isEmpty() メソッドの実装を追加します。

/**
 * 	種類のremove()実装メソッドを追加する
 * 	sizeメソッドを追加する
 */
public class WriteArrayList<E> {
	
	private static Object[] array;
	private int size;//配列の添え字
	private static final int DEFAULT = 10;
	
	public WriteArrayList() {
		array = new Object[DEFAULT];
	}
	
	public WriteArrayList(int index) {
		//判定を追加する
		if(index<0) {
			throw new RuntimeException("コンテナの容量を負にすることはできない: "+index);
		} else if(index==0) {
			array = new Object[DEFAULT];
		} else {
			array = new Object[index];
		}
	}
	
	public void add(E data) {
		//いつ拡張するか?
		if(size==array.length) {
			//どのように拡張するのか?
			Object[] newArray = new Object[array.length+(array.length>>1)];//アナロジー10+10/2,ここでは、プラス記号'+'よりも優先順位が高い。>>'
			System.arraycopy(array, 0, newArray, 0, array.length);
			array = newArray;
		}
		array[size++] = data;
	}
	
	@Override
	public String toString() {
		// [a,b,c]フォーマット出力
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(int i=0; i<size; i++) {
			sb.append(array[i]+",");
		}
		sb.setCharAt(sb.length()-1,']');//最終出力のカンマ「,」を「,」に置き換える。]'記号、コード中の一重引用符を二重引用符に変更することはできない
		return sb.toString();
	}
	
	public E get(int index) {
		checkIndex(index);
		return (E)array[index];
	}
	
	public void set(int index, E data) {
		checkIndex(index);
//		//インデックスの法的判断、インデックス間隔は[0,size)
//		if(index<0||index>size-1) {
//			//不正、手動で例外をスローする
//			throw new RuntimeException("インデックスは合法ではない:"+index);
//		}
		array[index] = data;
	}
	/**
	 * 	多くの場所で、インデックスindexが合法かどうかを判断する必要があるため,
	 * 	というわけで、ここに独立したメソッドを書いて、必要なときに直接呼び出そう。
	 */
	public void checkIndex(int index) {
		//インデックスの法的判断、インデックス間隔は[0,size)
		if(index<0||index>size-1) {
			//不正、手動で例外をスローする
			throw new RuntimeException("インデックスは合法ではない:"+index);
		}
	}
	public void remove(int index) {
		//移動が必要な配列の要素数
		int numMoved = array.length - index - 1;
		if(numMoved>0) {
			//根本原理:配列のコピー
			System.arraycopy(array, index+1, array, index, numMoved);
		}
		array[--size] = null;
	}
	
	public void remove(E data) {
		for(int i=0; i<size; i++) {
			if(array[i].equals(data)) {
				remove(i);
			}
		}
	}
	
	public int size() {
		return size;
	}
	
	public boolean isEmpty() {
		return size==0?true:false;
	}
	
	public static void main(String[] args) {
		WriteArrayList<Integer> wal = new WriteArrayList<>();
		for(int i=0; i<40; i++) {
			wal.add(i);
		}
		System.out.println(wal.get(10));
		
		wal.set(1,100);
		System.out.println(wal);
		
		wal.remove(2);
		System.out.println(wal);
		
		WriteArrayList<String> s = new WriteArrayList<String>();
		s.add("A");
		s.add("B");
		s.add("C");
		s.add("D");
		System.out.println(s);
		s.remove(1);
		System.out.println(s);
		s.remove("D");
		System.out.println(s);
		
		System.out.println(s.size());
		System.out.println(s.isEmpty());
	}
	
}

StringBuilderクラスを学習し、それはappend()、setCharAt()メソッドマスターarraycopy()メソッドを提供しています:System.arraycopy(コピーする配列、コピーする最初の要素から、どの配列にコピーするには、どの位置に貼り付け、コピーする要素の数の合計);独自のArrayList実装クラスのスタンドアロン書き換え

演習1~4 テークアウェイ

以下のコードは私が独自に完成させたもので、練習問題4のコードとの本質的な違いは、sizeとarray.length固有の代表的な意味です。以下の私のコードは、sizeはコンテナ内の要素数を表し、array.lengthはコンテナのサイズを表します。配列の拡張により、コンテナのサイズは一般的に要素数よりも大きくなります。とequalsの違いに注意してください。

public class WriteArrayList02<E> {
	private Object[] array;
	private int size;
	private static final int DEFAULT = 10;
	
	public WriteArrayList02() {
		array = new Object[DEFAULT];
	}
	
	public WriteArrayList02(int index) {
		if(index == 0) {
			array = new Object[DEFAULT];
		}else if(index<0) {
			throw new RuntimeException("インデックスを負にすることはできない: "+index);
		}else {
			array = new Object[index];
		}
	}
	
	public void add(E element) {
		if(size==array.length) {
			Object[] newArray = new Object[array.length+(array.length>>1)];
			System.arraycopy(array, 0, newArray, 0, array.length);
			array = newArray;
		}
		array[size++] = element;
	}
	
	public void set(int index, E element) {
		checkIndex(index);
		array[index] = element;
	}
	
	public E get(int index) {
		checkIndex(index);
		return (E)array[index];
	}
	
	public void checkIndex(int index) {
		if(index<0||index>=size) {
			throw new RuntimeException("インデックスの例外:"+index);
		}
	}
	
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(int i=0; i<size; i++) {
			sb.append(array[i]+",");
		}
		sb.setCharAt(sb.length()-1,']');
		return sb.toString();
	}
	
	public void remove(E element) {
		for(int i=0; i<size; i++) {
			if(array[i].equals(element)) {
				remove(i);
			}
		}
	}
	
	public void remove(int index) {
		System.out.println(array.length);
		//1,2,3,4,5,6,7
		int numCopy = size - index - 1;
		if(numCopy<0) {
			throw new RuntimeException("インデックスの例外:"+index);
		}else if(numCopy==0) {
			array[size] = null;
		}else {
			System.arraycopy(array, index+1, array, index, numCopy);
		}	
		//array[size-1] = null;
		size--;
		System.out.println(array.length);
	}
	
	public int size() {
		return size;
	}
	
	public boolean isEmpty() {
		return size==0?true:false;
	}
	
	public static void main(String[] args) {
		WriteArrayList02<String> wal = new WriteArrayList02<>();
		for(int i=0; i<40; i++) {
			wal.add(i+"");
		}
		System.out.println(wal);
		
		wal.set(1,"11");
		System.out.println(wal);
		
		System.out.println(wal.get(39));
		
		wal.set(39,"12");
		System.out.println(wal);
		
		wal.remove(0);
		System.out.println(wal);
//		wal.remove(38);
//		System.out.println(wal);
		wal.remove("12");
		System.out.println(wal);
		System.out.println(wal.size());
		System.out.println(wal.isEmpty());
	}
	
}

LinkedList連鎖リスト格納構造

Read next

Vue -Routerの概要

Vue-Routerのコアを簡単に分析 公式サイト Vue-plugin機構はroutesmap{path:rule}hash-change$router mixinsを解決します。

Oct 1, 2020 · 5 min read