データ型
データの種類の事を指す。
変数宣言の時に入れ物の形を指定する為に使う。
▶︎ データ型の種類
|--①基本データ型
| |--整数
| |--小数
| |--文字
| |--真偽値
|
|--②参照型
|--文字列
|--配列
|--etc
1,基本データ型
データ型の種類は3000種類以上あると言われているがその中で基本的な整数や少数、文字、真偽値をまとめたものを基本データ型(プリミティブ型)と呼ぶ。
基本データ型は全部で8種類でそれ以外は参照型になる。
それぞれデータ型のサイズによって細かく分類され、箱の大きさの桁数が増えると表現できる値の幅も広げることが出来る。
メモリに直接書き込まれる具体的なデータ値(数値や文字)を代入することが出来る。
種類 | データ型 | データの幅(箱の大きさ) | データの表現範囲 |
---|---|---|---|
整数 | byte | 8ビット | -128 ~ 127 |
- | short | 16ビット | − 2の15乗~2の15乗 − 1 (-32,768 ~ 32,767) |
- | int | 32ビット | − 2の31乗~2の31乗 − 1 (-2,147,483,648 ~ 2,147,483,647) |
- | long | 64ビット | − 2の63乗~2の63乗 − 1 (-9,223,372,036,854,775,808L ~ 9,223,372,036,854,775,807L) |
小数 | float | 32ビット | IEEE 754 規格の単精度浮動小数点数 |
- | double | 64ビット | IEEE 754 規格の単精度浮動小数点数 |
文字 | char | 16ビット | Unicode規格の1文字(\u0000~\uFFFF) |
真偽値 | boolean | 1ビット | true(真)またはfalse(偽) |
・数値はデフォルトで整数はint型に、小数はdoubleとして扱われる。
なのでfloot型の小数にはf(F)を、long型の整数にはl(L)を付ける必要がある。付けないとコンパイルエラーになる。
float weight = 64.5f
・文字列(char)のデータは''シングルクォーテーションで囲む。
2,参照型
参照型とは配列やクラスのようにnew演算子を用いてオブジェクトを生成してから使用するデータ型のこと。
値(データ)はメモリ上で管理されており、データ自体はメモリ上の別の領域に置かれてそのアドレスの値(参照値)が入る
基本データ型はメモリ上に直接、値が格納されるが参照型はアドレスの値(参照値)を格納する。
文字列や配列は作らないと何文字になるか、メモリがどのくらい必要になるのかがわからない。
そのためその時々に合わせて必要なメモリを確保して、確保した場所のアドレスを変数に入れる。
このようにしてメモリを出来るだけ有効に使う仕組みになっている。
char[] array = {'A', 'B', 'C'};
① {'A', 'B', 'C'}という配列をメモリ上の別の領域に保存する。
②{'A', 'B', 'C'}という配列を保存したメモリ上の領域ないのアドレスの値(住所のようなイメージ)が変数arrayの中にアドレスの値が入る。
(仮に{'A', 'B', 'C'}という配列をメモリ上の住所の「A001番地」に保存したとしたら変数arrayには「A001番地」という住所(値)が入る)
で囲む。
参照型のデータの持ち方と流れ
class Main {
public static void main(String args[]) {
char[] arrayA = {'A'};
char[] arrayB = arrayA;
char[] arrayC = arrayA;
arrayC[0] = 'C';
System.out.println(arrayA[0]);
System.out.println(arrayB[0]);
System.out.println(arrayC[0]);
}
}
①char[] arrayA = {'A'};で以下の図になる
②char[] arrayB = arrayA;と char[] arrayC = arrayA;で以下の図になり、出力結果も全てAになる。
A
A
A
③ここでarrayC[0] = 'C';にすると以下の図になる。
arrayC[0]の参照値はarrayA、Bと同じなのでarrayAとarrayBも値が「'C'」に上書きされてしまい、出力結果も全てCになる。
C
C
C
3,参照型(イミュータブル)(Stringとラッパークラス)
文字列を代入できるString型とラッパークラス(基本データ型の値を持つことができ、色々なメソッドが用意されたクラスの事)は他の参照型とは扱いが違う。
String型とラッパークラスは**イミュータブル(不変)**と呼ばれる変数で一度定義したオブジェクトを変更する事が出来ない。
その為String型とラッパークラスの値を変更すると新たな領域が確保されその領域を参照する。
class Main {
public static void main(String args[]) {
String stringA = "あいうえお";
String stringB = stringA;
stringB = "かきくけこ";
System.out.println(stringA);
System.out.println(stringB);
}
}
あいうえお
かきくけこ
出力結果は基本データ型と変わらないような結果になるが実際にはメモリ上では別領域に参照を作っている。
*String型は文字列を代入しているが、Stringオブジェクト内部で文字列をchar配列として扱っている。
基本データ型の型変換、キャスト
基本データ型の変数を作ったり、変数同士で演算をさせたりする時にデータ型の変換が行われる時がある。
データ型の変換が行われる時は自動で行われる時とキャストを使って明示する2パターンに分かれる。
キャストとは、Javaなどのプログラミング言語において、従来のデータ型を別のデータ型に変換することを指す。
・自動で行われる場合
表現できる値の幅が小さいデータから大きいデータにいく時
・キャストを使って明示する場合
表現できる値の幅が大きいデータから小さいデータにいく時
(✳︎真偽値であるboolean型は型変換できない)
キャストの書き方
データ型 変数 = (変更後の型)変数;
// 例1(long型の変数をint型に変換)
long l = 50;
int i = (int)l;
// 例2(int型の変数をshort型に変換)
int amount;
amount = (short)2;
比較的多いのが小数の計算結果を整数に変えたい時にキャストを行う場合が多い。
例文
class Cast{
public static void main(String[] args){
int price = 1980;
double rate = 0.08; // 消費税率:8%
int amount;
amount = (int)(price * (1 + rate));
System.out.println("税込金額:" + amount + "円");
}
}
税込金額:2138円
1980円の消費税を確かめるとしてint型の変数priceに代入している。
4行目でdouble型の変数rateを0.08に初期化。
5行目の変数amountは後で税込金額を計算して格納するための変数。
7行目で (price * (1 + rate)の計算結果の値をint型にキャストして変数amountに代入している。
1980×1.08=2138.4となるがint型に変換することで小数点部分は切り捨てられる。よって"税込金額:2138円"と出力される。
double型は64ビットでint型は32ビット。もしキャストを行わなかった場合、データ型が小さい方に代入しようとしているので下記のエラー分が出力される。
エラー: 不適合な型: 精度が失われる可能性があるdoubleからintへの変換
amount = (price * (1 + rate));
エラー1個
参照型の型変換
参照型の型変換ができる時は型変換する前のクラスと型変換後のクラスの間で継承関係にある時。
参照型の型変換が行われる時は継承関係にあるクラス同士でオブジェクトの型変換が自動で行われる時とキャストを使って明示する2パターンに分かれる
・自動で行われる場合
サブクラスのオブジェクトをスーパークラスのオブジェクトとして扱う時。(スーパークラス = サブクラスの関係の時)
・キャストを使って明示する場合
スーパークラスのオブジェクトをサブクラスのオブジェクトとして扱う時。(サブクラス = スーパークラスの関係の時)
上の写真はフィールドname、コンストラクタPerson、displayメソッドを持ったスーパークラスのPersonクラスとフィールドstuNo、コンスタントStudent、displayメソッド、 chgStuNoメソッドを持ったサブクラスのStudentクラス。
// 例1(自動で型変換)
Student stu1 = new Student(・・・);
Person psn = stu1;
// スーパークラス名 変数名 = 変数名;
// スーパークラス = サブクラスなので自動で代入される
// 例2(キャストで明示して型変換)
Student stu2 = (Student)psn;
// サブクラス名 変数名 = (サブクラス名)変数名;
// サブクラス = スーパークラスなのでキャストで明示して型変換する必要がある
psn.display(); →オーバーライド有効
psn chgStuNo(・・・); →コンパイルエラー
stu2.chgStuNo(・・・); →呼び出される
例1ではStudentクラスからオブジェクトstu1を生成している。二行目でオブジェクトstu1をPersonクラスのオブジェクトpsnに代入している。この時に参照型の型変換が行われている。(StudentクラスからオブジェクトからPersonクラスのオブジェクトに代入されている)。
スーパークラス = サブクラスの関係になっているので自動で代入される。
例2ではスーパークラスの変数psnをサブクラスの変数stu2に型変換している。
スーパクラスの情報をサブクラスの変数に代入する時はメモリ上にサブクラスの情報が必ず存在するのをコンパイラに知らせる為にキャストをする必要がある。
psn.display();ではサブクラス側(オーバーライドされた)displayメソッドが呼出される。
psn chgStuNo(・・・);はスーパークラスが持っていないメソッドなのでコンパイルエラーになる。
stu2.chgStuNo(・・・);はサブクラスが持っているメソッドなので呼出される。
上の写真はそれぞれのオブジェクトが持つフィールドやメソッドのイメージ。
例文
public class StuSample5{
public static void main(String[] args){
Student5 stu1 = new Student5("菅原",1);
Person5 psn = stu1;
psn.display();
/* 補足:instaceofキーワード
オブジェクト(インスタンス)のクラスを特定する事が出来る
対象オブジェクト instaceof クラス名*/
if(psn instanceof Student5){
Student5 stu2 = (Student5)psn;
stu2.chgStuNo(1001);
stu2.display();
}
}
}
public class Person5{
private String name;
public Person5(String name){
this.name = name;
}
public void display(){
System.out.println("名前" + name);
}
}
public class Student5 extends Person5{
private int stuNo;
public Student5(String name, int stuNo){
super(name);
this.stuNo = stuNo;
}
public void display(){
super.display();
System.out.println("学籍番号" + stuNo);
}
public void chgStuNo(int stuNo){
this.stuNo = stuNo;
}
}
名前:菅原
学籍番号:1
名前:菅原
学籍番号:1001
実行用クラスの3行目でStudent5のコンストラクタを呼び出してオグジェクトstu1に代入している。
4行目でスーパークラスのオブジェクトpsnにオグジェクトstu1に代入する。psn.display();でスーパークラスのdisplayメソッドを呼び出しているがサブクラスでオーバーライドされているので出力結果は"名前:菅原","学籍番号:1"となる。
10行目でinstaceofキーワードを使うことでStudent5クラスのインスタンスか?を確認している(instaceofキーワードの結果はtrueかfalseで返ってくる)
11行目ではスーパークラスのオブジェクトpsnをサブクラスのオブジェクトstu2にキャストしている。
stu2.display();でサブクラスのdisplayメソッドを呼び出しているが直前のstu2.chgStuNo(1001);でchgStuNoメソッドに1001という値を渡しているので出力結果は"名前:菅原","学籍番号:1001"となる。
参考記事
https://www.youtube.com/watch?v=KDmJDC7U59c
https://www.youtube.com/watch?v=yyPdrxOQWbs&list=PLru8-xuz0YvwUh0FofxilaQ7Tmu_lWyTo&index=6