Javaのプリミティブ型と参照型、値渡しと参照渡しなど

なんでプリミティブ型と参照型にデータ型が分かれているかずっと疑問だったけど、講師の方の説明を聞いて納得。

プリミティブ型と参照型

Javaのデータ型は、大きく分けて2種類に分けられるようです。

プリミティブ型

データ型 消費メモリ
double型 64bit
float型 32bit
long型 64bit
int型 32bit
short型 16bit
byte型 8bit
char型 16bit
boolean型 1bit

参照型

データ型 消費メモリ
String型 不明
配列型 不明
クラス型 不明
ラッパークラス型 不明

ラッパークラス型も参照型らしいです。

「ラッパークラス」とは、プリミティブ型をクラスの中に梱包したもので、参照型である。

Javaのプリミティブ型と参照型について

プリミティブ型 ラッパークラス
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Char
boolean Boolean

 

データ生成時の状態

なぜ、参照型が変数とは別の異なる場所にもメモリを消費して保存されるのかというと、プリミティブ型のように事前に消費メモリが決まっていないことが原因のようです。 

f:id:ts0818:20170629200534p:plain

プリミティブ型は1個所、参照型は変数とは別に実体の保存場所としてメモリを消費するため異なる2個所の領域(ここでいうと、『1033番』と『1054番~1058番』の2個所)が使用されるようです。

f:id:ts0818:20170629202632p:plain

 そして、参照型の変数(『1033番』)には、実体の先頭のアドレス(ここでは『1054番』)が格納されるようです。

参照型は、プリミティブ型のようにあらかじめ消費メモリが分かっていないため、最初に作られる変数に直接、値を入れようがないため、アドレスを格納するという、このような二段構えになっているようです。

値渡し

public class PassValue {
  static int global_num = 10;
  public static void main(String[] args) {
    int num = 10;
    method(num);
    System.out.println(num);
    method(global_num);
    System.out.println(global_num);
  }
  
  public static void method(int n) {
    n++;
    System.out.println(n);
  }
}

結果は、

11
10
11
10    

となります。値渡しは、値のコピーが渡されるため、methodで処理されても、元の変数には変化なしです。

参照渡し

配列aと配列bで参照渡しについて見てみると、

public class Main() {
  public static void main(String[] args) {
    int[] a = {10, 20, 30, 40, 50};
    int[] b;
    b = a;
    b[0] = 100;
    System.out.println(a[0]);
  }
}

b = aによって、aに格納されている配列aの実体の先頭アドレス(『1054番』)が渡されるので、配列bも同じ配列aを参照することになるようです。

f:id:ts0818:20170629210212p:plain

値渡しと参照渡しは混乱することこの上ないですね。

 

今日の課題は、最大値と最小値を配列の中から見つけるというもの。

package arrays;

public class MaxMinTest {

	public static void main(String[] args) {
		// 変数定義
		int[] numbers = { 17, 68, 14, 55, 70, 12, 21, 63, 88, 50 };
		int max; // 最大値
		int min; // 最大値
		// メソッドにnumbersを渡して呼び出し結果をmaxに代入
		max = maxNumber(numbers);
		min = minNumber(numbers);
		System.out.println("配列中の最大値:" + max + "   配列中の最小値:" + min);
	}

	/**
	 * 配列から最大値の要素を返す
	 * @param int[] ary
	 * @return int ary[ary.length -1]
	 */
	static int maxNumber(int[] ary) {
		arraySort(ary);
		return ary[ary.length -1];
	}

	/**
	 * 配列から最小値の要素を返す
	 * @param int[] ary
	 * @return int ary[0]
	 */
	static int minNumber(int[] ary) {
		arraySort(ary);
		return ary[0];
	}

	/**
	 * 配列をソートする(昇順)
	 * param int[] ary
	 * return int[] ary
	 */
	static int[] arraySort(int[] ary) {
		// 退避用の変数
    int key = 0;
    // 配列を昇順に並び替え
		for(int i = 0; i < ary.length; i++) {
		  for(int j = ary.length -1; j > i; j--) {
		  	if(ary[j] < ary[j-1]) {
		  		key = ary[j-1];
		  		ary[j-1] = ary[j];
		  		ary[j] = key;
		  	}
		  }
		}

		return ary;
	}

}

package arrays;

public class MaxMinTest2 {

	public static void main(String[] args) {
		// 変数定義
		int[] numbers = { 17, 68, 14, 55, 70, 12, 21, 63, 88, 50 };
		int max; // 最大値
		int min; // 最大値
		// メソッドにnumbersを渡して呼び出し結果をmaxに代入
		max = maxNumber(numbers);
		min = minNumber(numbers);
		System.out.println("配列中の最大値:" + max + "   配列中の最小値:" + min);
	}

	/**
	 * 配列から最大値の要素を返す
	 * @param int[] ary
	 * @return int result[0]
	 */
	static int maxNumber(int[] ary) {
		int[] result = arraySort(ary);
		return result[0];
	}

	/**
	 * 配列から最小値の要素を返す
	 * @param int[] ary
	 * @return int result[1]
	 */
	static int minNumber(int[] ary) {
		int[] result = arraySort(ary);
		return result[1];
	}

	/**
	 * 配列をソートする(昇順)
	 * param int[] ary
	 * return int[] ary
	 */
	static int[] arraySort(int[] ary) {
		// 基準となる変数を決める
    int min = ary[0];
    int max = ary[0];
    // 結果(maxとmin)格納用の配列
    int[] result = new int[2]; // 0: max, 1: min
    // 配列から、最大値と最小値を探す
    for(int i = 0; i < ary.length; i++) {
    	// 最大値の検索
	    if(max < ary[i]) {
	    	max = ary[i];
	    }
      // 最小値の検索
	    if(min > ary[i]) {
	    	min = ary[i];
	    }
	  }
    // 最大値と最小値を格納
    result[0] = max;
    result[1] = min;

		return result;
	}

}

明日、講師の方がまた目からウロコな解法を披露してくれることでしょう。ということで今回はこのへんで。

 

2017年7月3日 追記

講師の先生の解法。さすが、整ってます。

package ex5;

public class MaxMinTest2 {

	public static void main(String[] args) {
		// 変数定義
		int[] numbers = { 17, 68, 14, 55, 70, 12, 21, 63, 88, 50 };
		int max; // 最大値
		int min; // 最大値
		// メソッドにnumbersを渡して呼び出し結果をmaxに代入
		max = maxNumber(numbers);
		min = minNumber(numbers);
		System.out.println("配列中の最大値:" + max + "   配列中の最小値:" + min);
	}
	
	static int maxNumber(int[] ary) {
		int max = ary[0]; // 仮の最大値
		// 最大値検索
		for (int i = 0; i < ary.length; i++) {
			if (ary[i] > max) { max = ary[i]; 	}
		}
		return max;
	}
	
	static int minNumber(int[] ary) {
		int min = ary[0]; // 仮の最小値
		// 最大値検索
		for (int i = 0; i < ary.length; i++) {
			if (ary[i] < min) { min = ary[i]; }
		}
		return min;
	}

}