Chapter 07

データ型

KeitoYuasa
KeitoYuasa
2023.02.12に更新

データ型とは

  • データ型:データの種類の事
  • javaのデータ型は、基本データ型と参照型がある。
データ型 種類
基本データ型(プリミティブ型) byte, short, int, long, float, double, char, boolean型の8種類ある。
参照型(非プリミティブ型) クラス(Stringも含む), 配列, インターフェースなどを基本データが以外のすべての型。
データ型 それぞれの違い
基本データ型(プリミティブ型) メモリ上の値を直接参照する。
参照型(非プリミティブ型) メモリ上の値を格納するメモリのアドレス(領域)を参照する。
※つまり、値を直接参照するか、値を格納する領域を参照するかの違い。

基本データ型(プリミティブ型)

文字型

  • 1文字を表現できる。シングルクォーテーションで囲む必要がある。(囲まない場合はコンパイルエラー)
  • また、複数の文字を扱った場合もコンパイルエラー
文字型 説明
char 1文字。シングルクォーテーションで囲む。
エラーの例 エラーの理由
char var = 'aa'; char型は1文字しか扱えないため
char var = "a"; char型をダブルクォーテーションで囲んでいるため

整数型

  • 4つの整数型がある
  • それぞれは、扱うことができる数値の範囲の違い(ほとんどintでいい)
  • 扱える範囲を超えたものを代入するとエラーになる(エラーの例:byte = 1000;)
整数型 数値の範囲の違い
byte だいたい-100〜100
short だいたい-3万〜-3万
int だいたい-20億〜20億
long 京の桁以上(-も含む)

※longのみ数字の末尾にL、またはlをつける必要がある。
longの符号がない場合は、デフォルトでint型と認識される。
そのため、int型で扱える範囲外の数値を変数に代入している場合はコンパイルエラーになることに注意。

Training.java
class Training {
    public static void main(String[] args){
        byte var = 100;
        short var2 = 30000;
        int var3 = 2000000000;
        long var4 = 123456789000L;

        System.out.println(var);
        System.out.println(var2);
        System.out.println(var3);
        System.out.println(var4);
    }
}

//出力結果:
//100
//30000
//2000000000
//123456789000

小数型

  • 2つの整数型がある。
  • それぞれ、扱える小数点以下の桁数に違いがある(ほとんどdoubleでいい)
  • 扱える範囲を超えたものを代入するとエラーになる
整数型 小数点以下の桁数の違い
float 7桁(有効桁数)。32bit
double floatより多い16桁。64bit

※floatのみ小数の末尾にF、またはfをつける必要がある。
floatの符号がない場合は、デフォルトでdouble型と認識される。
そのため、小数は64bitと認識された後、データサイズに小さいfloat型の32bitに代入する場合はコンパイルエラーになる。

Training.java
class Training {
    public static void main(String[] args){
        float var = 1.23456789F;
        double var2 = 1.23456789;

        System.out.println(var);
        System.out.println(var2);
    }
}

//出力結果:
//1.2345679 ←切り捨てられている
//1.23456789

ブーリアン型

  • true, falseを扱うデータ型
Trining
class Training {
    public static void main(String[] args){
        boolean var = 10 > 1;

        System.out.println(var);
    }
}

//出力結果:
//true
Trining
class Training {
    public static void main(String[] args){
        boolean var = 10 < 1;

        System.out.println(var);
    }
}

//出力結果:
//false

参照型(非プリミティブ型)

参照型は、空の場合はエラーではなくnullを返す。

文字列型

String(= java.lang.String)

※意外と特殊な頻繁に使用するデータ型

  • 文字列を扱うためのクラスの一種
  • 文字列型が参照型として扱われる理由は、文字のかたまり(複数のデータを要素として)を1つの変数で複数参照できるため。クラス、配列なども同じ理由。
  • 基本は、1変数に1データしか参照できない。1変数、1データしか管理できないのは両データ型同じことだが、複数のデータを参照できるかの違い。
No. 注意点
1 Stringのsは、必ず大文字にすること。
2 1つ以上の文字を表現できる。ダブルクォーテーションで囲む必要がある。(囲まない場合はコンパイルエラー)
3 String型の文字列は、それ自身を書き換えることができない。(初期化されたString型の変数に、異なる文字列を再代入すると、新たな文字列とそのメモリ領域が生成され、変数の参照先がそれに切り替わるため。)
String型のメソッド 説明
charAt(1) 引数と一致するインデックスの文字を返す。arg:int, return:char
equals("abc") 引数の文字列と同じかを比較、真偽値を返す。**文字列の比較を行う時に用いる。**arg:String, return:boolean
intern() 同じ領域の文字列を返す。return:String
indexOf('a') 引数の文字が最初に出現するインデックスを返す。arg:char, return:int
length() 文字の数を返す。return:int
replace('a', 'z') 第一引数の文字を第二引数の文字で置き換えた文字列を返す。arg1:char, arg2:char, return:String
substring(1) 引数で指定したインデックスから最後までの文字列を返す。arg:int, return:String

※配列のサイズを取得する際は、配列.lengthになることに注意。(()が不要な点)

Training.java
class Training {
    public static void main(String[] args){
        char var = 'a';
        String var2 = "Hello World";

        System.out.println(var);
        System.out.println(var2);
    }
}
//出力結果:
//a
//Hello World

以下では、コンパイルエラーの具体例を紹介。
原因は、String型をシングルクォーテーションで文字を囲んでいるため。

Training.java
class Training {
    public static void main(String[] args){
        String var = 'Hello World';

        System.out.println(var); //コンパイルエラー
    }
}

以下では、Stringメソッドの挙動を紹介。

Training.java
class Training {
    public static void main(String[] args){
        String s = "abcdef";

        System.out.println(s.charAt(1));
        System.out.println(s.equals("abcde"));
        System.out.println(s.intern());
        System.out.println(s.indexOf('c'));
        System.out.println(s.length());
        System.out.println(s.replace('a', 'z'));
        System.out.println(s.substring(4));
    }
}
//出力結果:
//b
//false
//abcdef
//2
//6
//zbcdef
//ef

StringBuilder

  • 文字列を扱うためのクラスの一種
  • 特有のメソッドを用いることで、変数に格納した文字列を直接書き換えることができるクラス。(つまり、新たな領域に文字列を生成するのではなく、既存の文字列を直接更新することができる。)
StringBuilder型のメソッド(文字列を直接操作するもの) 説明
append("zzz") 引数に指定した文字列を末尾に追加する。arg:String, return:String
insert(2, "zzz") 第一引数に指定したインデックス番目に、第二引数の文字列を追加する。文字列数を超えた数を指定した場合、それまでを空白文字で埋めて文字列を追加する。arg1:int, arg2:String, return:String
delete(0, 5) 第一引数から第二引数の一つ前のインデックスまでの文字列を削除する。arg1:int, arg2:int, return:String
replace(0, 5, "zzz") 第一引数から第二引数の一つ前のインデックスまでの文字列を第三引数の文字列で置き換える。arg1:int, arg2:int, arg3:String, return:String
substring(1) 引数で指定したインデックスから最後までの文字列を返す。arg:int, return:String

以下では、StringBuilder型のメソッドを使用している。
String型と違って、文字列自体が書き換わっていることがわかる。

Training.java
class Training {
    public static void main(String[] args){
        StringBuilder sb = new StringBuilder("abcdef");

        System.out.println(sb.append("zzz"));
        System.out.println(sb.insert(2, "zzz"));
        System.out.println(sb.delete(0, 5));
        System.out.println(sb.replace(0, 5, "zzz"));
        System.out.println(sb.substring(4));
        System.out.println(sb.length());
    }
}
//出力結果:
//abcdefzzz
//abzzzcdefzzz
//cdefzzz
//zzzzz
//z
//5

データ型の比較

  • 要点
    • 基本データ型:値が等しければtrue
    • 参照型:値を格納するメモリ領域(アドレス)が等しければtrue

基本データ型

基本データ型の比較は、直接値が等しいかを見る。
データ型が異なる場合でも値が同じであればtrue。

Training.java
class Training {
    public static void main(String[] args){
        int a = 10; int b = 1_0; long c = 10L;
        byte d = 10; char e = 'a';
        float f = 10.0f; double g = 10.0;
        boolean h = true;

        System.out.println(a == b);
        System.out.println(a == c);
        System.out.println(a == d);
        System.out.println('a' == e);
        System.out.println(f == g);
        System.out.println('a' == e);
        System.out.println(true == h);
    }
}
//出力結果:
//全てtrueを返す

参照型

参照型の比較は、メモリ領域(アドレス)が等しいかを見る。
値が同じであっても参照先が異なればfalse。

参照型 違い
配列 毎回、値が同じでも別の領域に新たに配列を生成する。そのため、同じ値でもfalseになる場合がほとんど。
String newを使ってStringを生成するか、newを使わずStringを生成するかの2パターンで比較結果が異なる。
String生成方法 比較の違い
newを使う 配列と同じで、毎回、値が同じでも別の領域に新たに配列を生成する。
newなし(一般的) メモリ領域上に同じ文字列が存在していればその領域を参照する。そのため、値が同じであれば領域も同じになるため基本true。

※newを使ってString型を定義する方法は、2度デマなので一般的に使用しない。
(コンパイルが""で囲った値はString型を認識するため、new String(文字列型);となって2度デマになる。)

配列の比較

配列は、値が同じでも毎回異なる領域に配列を生成する。
そのため、変数a, bの配列は参照先が異なるためfalse。
また、変数dは変数c自体を代入しているので、配列の値もその領域も同じになるためtrue。

Training.java
class Training {
    public static void main(String[] args){
        int[] a = {10}; int[] b = {10};
        int[] c = {10}; int[] d = c;

        System.out.println(a == b);
        System.out.println(c == d);
    }
}
//出力結果:
//false
//true

String型の比較

一般的な、newを使わないString型の比較は、メモリ領域上に同じ値が存在していればその領域を参照する。
そのため、変数a, b, cは同じ領域を参照していることになるためtrue。

newを使ったString型の比較は、配列と同じなので値が同じでも毎回異なる新しい領域に文字列を生成する。
そのため、変数c, dは異なる領域を参照している。

Training.java
class Training {
    public static void main(String[] args){
        String a = "aaa";
        String b = "aaa";
        String e = a.intern();  //String.intern():同じ領域の文字列を返す
        String c = new String("aaa");
        String d = new String("aaa");


        System.out.println(a == b);
        System.out.println(a == e);
        System.out.println(b == e);
        System.out.println(a == c);
        System.out.println(c == d);
    }
}
//出力結果:
//true
//true
//true
//false
//false

※String型を用いて比較を行う際、領域を比較するより値を比較することのほうが多い。
領域ではなく、値を直接比較するには、String.equals()メソッドを用いる。

String型とStringBuilder型の比較

StringBuilder型は、String型と違って、値を上書きすることができる。
以下で、値を上書きするメソッドの1つであるStringBuilder.append()を変数eに使っている。
そのため、変数eが持つ値を上書きするので、領域は変わらない。trueが返る。

Training.java
class Training {
    public static void main(String[] args){
        String a = "aaa";
        String b = a + "A";

        String c = "aaa";
        String d = c.concat("A");

        StringBuilder e = new StringBuilder("aaa");
        StringBuilder f = e.append("A");

        System.out.println(a == b);
        System.out.println(c == d);
        System.out.println(e == f);
	System.out.println(e);
	System.out.println(f);
        // System.out.println(a == e); コンパイルエラー(異なる参照型の比較)
    }
}
//出力結果:
//false
//false
//true
//aaaA
//aaaA

基本データ型の型変換

基本データ型の型変換は、主に小数から整数に変換したい時に用いられる。(キャスト)

変換方法

数値同士の演算や代入を行う際、またはメソッドの引数、戻り値でデータ型の変換が
①自動で行われる場合(暗黙型変換)。
②手動で行う必要があるの場合(キャストによる型変換)。の2パターンの変換方法がある。

変換ルール

各、基本データ型のデータのサイズと表現できる値。つまり、表現できる値の幅が重要になってくる。
表では、下に行くにつれて、表現できる値の幅が大きくなる。

  • 自動変換(暗黙型変換):表の上から下に型変換する場合
  • 手動変換(キャストによる型変換):表の下から上に型変換する場合
基本データ型 サイズ 表現できる値
byte 8bit だいたい-100〜100
short 16bit だいたい-3万〜-3万
int 32bit だいたい-20億〜20億
long 64bit 京の桁以上(-も含む)
float 32bit 7桁(有効桁数)。
double 64bit floatより多い16桁。

※floatは、longに比べてサイズが小さいが、小数は整数も表現できるので表現できる値の幅が大きい。
※charは、16bitなのでshrotと同じだが、基本、数値での型変換になる。
※booleanは、型変換できない。

変換の具体例

①int→doubleに変換したい場合
intは、32bitのメモリ領域で値を表現する(つまり、0, 1が32個ある箱でintを表現する)。
doubleは、64bitなのでintの2倍のメモリ領域で値を表現する。
そのため、32bitで表現できる値は64bitでも表現できる。つまり、64bitという大きい箱に32bitが収まるので、エラーなく自動で型変換ができる。

②doubl→intに変換したい場合
大きいメモリ領域を小さいメモリ領域に入れる際、コンパイルエラーになる。
そのため、キャストを用いて、型を変換することを手動でコンパイラに知らせる必要がある。
(キャストをしないと、コンパイラが自分よりサイズの小さい箱に値を入れて、大丈夫か?データが溢れないか?といった心配をするため)

以下では、代入、メソッドの引数を用いて自動型変換、キャストの例を示している。

Training.java
class Training {
    public static void main(String[] args){
        int i = 10;
        double d = 20.0;

        d = i; //int→double
        i = (int)d; //double→int

        System.out.println(d);
        System.out.println(i);
        foo((short) i); //int→short
    }

    static void foo(short s){
        System.out.println(s);
    }
}
//出力結果:
//10.0
//10
//10

演算を行う際の型変換は注意

演算を行う場合の型変換は、計算するデータ型によって、計算前に自動的にデータ型が変換されてしまうので、その際はキャストしなければいけないという注意点がある。

No. 注意点
1 一方がdouble型の場合、演算の前に他方もdouble型に変換される。
2 一方がfloat型の場合で他方がdouble型ではない場合、演算の前に他方もfloat型に変換される。
3 一方がlong型の場合で他方がfloat, double型ではない場合、演算の前に他方もlong型に変換される。
4 一方、他方どちらともlong, float, double型でない場合、両者ともint型に変換される。

以下では、演算を行う場合の型の変換を示す。
変数s1では、short型 + 1を行なっている。そのため、双方はint型に自動で変換される。int型に変換された値をshort型の領域を持った変数s1に代入しているのでコンパイルエラーが起こる。
このエラーは、キャストによって解決できる。

※インクリメント・デクリメントを行う際は、自動で型変換されない

Training.java
class Training {
    public static void main(String[] args){
        short s1 = 10;
        short s2 = 20;

        //s1 = s1 + 1; コンパイルエラー
        s1 = (short)(s1 + 1); //int→short
        s2 = ++s2;
        
        System.out.println(s1);
        System.out.println(s2);
    }
}
//出力結果:
//11
//21

ラッパークラス

javaでは、基本データ型の値を参照型として扱うためのクラスがビルトインで用意されている。これをラッパークラスと呼ぶ。

基本データ型 対応するラッパークラス
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
  • 基本データ型からそれに対応したラッパークラス間の変換は自動で行われる。
    • Boxing:基本データ型→ラッパークラスへの自動変換のこと
    • Unboxing:ラッパークラス→基本データ型への自動変換のこと

Boxing・Unboxingと注意点

※基本データ型同士の場合、ルールに従った自動変換ができる
Boxingにおいては型の自動変換ができない。コンパイルエラーになる。

以下では、

  • ①基本データ型とそれに対応するラッパークラスの比較
  • ②Boxing, Unboxing、またはメソッドの引数でのBoxing
  • ③Boxingにおいて、自動型変換ができない例(コンパイルエラー)
  • ④ラッパークラスと基本データ型の計算
Training.java
class Training {
    public static void main(String[] args){
        int i = 10;
        Integer i_class = 10;
    
        System.out.println(i == i_class); //値自体の比較

        i_class = i; //Boxing
        int i2 = i_class; //Unboxing
        add(i2); // メソッドの引数で自動変換

        double d = 1; //基本データ型同士の自動型変換
        //Double d_class = 1; Boxingにおいては、自動型変換できない(コンパイルエラー)
        System.out.println(d);
    }

    static void add(Integer i_class){
        int i = i_class + 10; //Integerとintの計算
        System.out.println(i);
    }
}
//出力結果:
//true
//20
//1.0