配列からオブジェクト指向までまとめる。
復習用にどうぞ
(タイトルのクリリンと特に関連性はないです)
--以下の簡単な文法は割愛--
if構文
if-else if-else構文
swith文
while文
do-while文
for文
配列
配列の各要素には同一種のデータしか格納できない。(intならintのみ、Stringのみ等)
添え字(index)は0から数える。(要素0番目~)
配列作成手順
String型配列を作ってみる。
//String型配列変数dragonBallを定義
String[] dragonBall;
//String型要素7つ作成し、代入し配列dragonBallの完成
dragonBall = new String[7];
//1行で作成することも可能
String[] dragonBall = new String[7];
配列の要素数を知りたい
lengthを使う。
System.out.println(dragonBall.length);
とすれば、7と出力される。
配列に要素を代入したい
配列dragonBallの2つ目(要素1番目)に二星球(アルシンチュウ)を代入する場合
dragonBall[1] = "二星球";
配列の要素は自動で初期化される
配列に何も代入していない要素を出力したらどうなるか。
String[] dragonBall = new String[7];
System.out.println(dragonBall[0]);
↑nullが出力されエラーは起こらない。
配列もintやString同様に自動で初期化される。
・int,double型 ⇒ 0
・boolean型 ⇒ false
・String型 ⇒ null
配列の作成と初期化を同時に行う
次の2パターンの記述方法がある。
①int[] score1 = new int[]{20,30,40,50};
⇒ 要素4つの配列が作成される
②int[] score2 = {20,30};
⇒ 要素2つの配列が作成される
for文と配列
配列の添え字に変数を用いることができる。
public class Main {
public static void main(String[] args){
int[] score = {10,20,30};
for(int i =0 ; score.length ; i++){ //4行目
System.out.println(score[i]);
}
}
}
変数iは、0,1,2と変化していく。これを配列を回すという。
4行目に「length」を用いることで、初期値を変更されても要素数は変わらないので
コードの修正が不要というメリットがある。
拡張for文
単純に配列型を全て回したいときは拡張for文が便利。
for(型 変数名 : 配列){}
int[] score = {10,20,30};
for(int value : score){
System.out.println(value);
}
動きは1週目の value には10が入り、2週目の value には20が入る・・・。
要素の数だけ回転してくれる。
参照
次のコードを見てほしい。
出力したbには何が入っているか。
int a = 1;
int b = a;
a = 2;
System.out.println(b);
bには1が入る。
a=1のときに代入したから、その後aに何が代入されてもbには関係がない。
しかし、配列だと変わる。
int[] a = {1};
int[] b = a;
a[0] = 2;
System.out.println(b[0]);
bには2が入る。
配列aには直接値が入っているわけではない。
値がある場所を知っているだけである。これを参照という。
int[] b = a;
では場所を共有している状態。
場所を住所に例えると、
Aさんは101号室にバナナを置く。
B=Aで、AさんはBに部屋番号を教える。
Aさんがリンゴを追加する。
Bさんが101号室に行くとバナナとリンゴがある。
二次元配列
二次元配列の例
int[][] scores = new int[2][3];
2つの箱があって、それぞれ3つの箱が入っている状態。
[0] ⇒ [0][1][2]
[1] ⇒ [0][1][2]
計6つの箱が用意される。
public class Main {
public static void main(String[] args){
int[][] scores = {{10,20,30}, {40,50,60}};
System.out.println(scores[1][1]);
System.out.println(scores.length);
System.out.println(scores[0].length);
}
}
}
50
2
3
メソッド
メソッドの作成をメソッドの定義という。
使用することをメソッドを呼び出すという。
メソッド名の後ろの「{}」の部分をメソッドブロックという。
メソッド名();
で呼び出せる。
public static void main(String[] args){
methodA();
}
public static void methodA(){
System.out.println("メソッドAを呼んだ");
}
引数
メソッドに値を渡すことができ、その値を引数という。
さらに細かく言うと、渡す値を実引数、受け取る値を仮引数という。
引数を渡す側 メソッド名(値);
引数を受け取る側 ~ メソッド名(引数の型 引数を代入する変数){}
public static void main(String[] args){
methodA("クリリン");
}
public static void methodA(String name){
//変数nameに引数クリリンが入ってくる。
System.out.println(name + "さんです。");
}
引数を複数渡す
例:
引数を渡す側 メソッド名("クリリン",20);
引数を受け取る側 ~ メソッド名(String name, int age){}
ローカル変数
ローカル変数の独立性
メソッド内で宣言された変数をローカル変数という。
ローカル変数はその変数が属するメソッド内だけで有効。(有効範囲をスコープという)
別メソッドで宣言された同名のローカル変数とは別物となる。
戻り値
値を返すことを値を戻すという。
戻されるデータ(値)のことを戻り値という。
return文⇒return 戻り値;
で値を戻せる。
public static 戻り値の型 メソッド名(型 変数){
return 戻り値;
}
戻す値がないときは「戻り値の型」の部分を
何も返さないという意味の「void」にする。
public static void main(String[] args){
int a = 10;
int b = 20;
int total = tasu(a, b); //戻り値が返ってくるのでtotalへ代入
System.out.println("合計は" + total + "です。");
}
//足し算を行うメソッド
public static int tasu(int x, int y){
return x+y;
}
return文はメソッドの終了も行う為、return文以降にコードを書いてもエラーになる。
オーバーロード
同名メソッドを定義することをオーバーロードという。
同じメソッド名でも仮引数の型や引数の数が違えば定義しても問題ない。
メソッドを呼ぶときに自動で判断してくれる。
public static int add(String x, int y){
return x+y;
}
public static int add(int x, int y){
return x+y;
}
public static int add(int x, int y,int z){
return x+y+z;
}
add("クリリン", 20)
と呼べば、きちんと一番上のメソッドが呼ばれる。
参照渡し
これまでのサンプルコードで値そのものを渡すことを値渡しという。
配列を渡すことを参照渡しという。
public class Main {
public static void main(String[] args) {
int[] array = {1,2,3};
//配列を渡す(参照渡し)。
printArray(array);
}
public static void printArray(int[] array){
for(int element : array){
System.out.println(element);
}
}
}
public class Main {
public static void main(String[] args) throws Exception {
int[] array = {1,2,3};
intArray(array);
for(int i : array){
System.out.println(i);
}
}
public static void intArray(int[] array){
for(int i = 0; i < array.length; i++){
array[i]++;
}
}
}
実行結果は2,3,4となる。
戻り値で返してるわけでもないのに配列arrayの値に変化があるのは
配列型が参照型だから。
クラスとパッケージ
クラスを利用することで1つのプログラムを複数に分ける、つまり部品化し、
開発を分担できる。
クラスが増えてきたらパッケージを用いてさらに部品化できる。
・クラス名は一文字目は大文字でなければいけない。
・パッケージ名の一文字目は基本小文字。
・パッケージは独立しているので、パッケージ毎に同じクラス名を作成することも可能。
・パッケージ名にドット「.」を含めることが多い。
・自身以外のパッケージを使うとき、所属パッケージを添える必要がある。
例:
movieパッケージのとあるクラスで
計算(calc.app)パッケージの計算処理(CalcLogic)クラスのtasuメソッドを使いたい。
int total = calc.app.CalcLogic.tasu(a,b);
パッケージ名を先頭につけたこのようなクラスを
完全限定クラス(full qualified class name)
略してFQCNという。
パッケージのメリット
- パッケージ毎に別で開発すれば、クラス名が他人と被っても名前の衝突が起きない。
- パッケージ名はドメインを逆にしたものを推奨。(foo.exsample.com ⇒ com.exsample.foo)
ドメインは世界中の誰とも被ることがない。
※名前の衝突:名前が被ってエラーになること。
インポート文
import文:FQCNの記述を省略できる。
import パッケージ名.クラス名;
※import文はソースの先頭に記述。ただし、パッケージよりは後。
以下のように記述量が減る。
int total = calc.app.CalcLogic.tasu(a,b);
⇒ int total = CalcLogic.tasu(a,b);
インポートしたいクラスが大量にあると大変。
全てのクラスをインポートしたいときはアスタリスクを使う。
計算(calc.app)パッケージなら
import calc.app*;
API
APIとは便利な公式のようなもの。
java.util.Arrays.sort()で自動並び替えを使う為にjava.util.*
をインポートする。
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
int[] heights = {20,35,10};
java.util.Arrays.sort(heights);
for(int h : heights){
System.out.println(h);
}
}
}
実行結果は10,20,35となる。
API | 意味 |
---|---|
java.lang | 必須のクラス群 |
java.util | 便利なクラス群 |
java.math | 数学系のクラス群 |
java.net | ネット通信系のクラス群 |
java.io | ファイル読み書き,データ処理クラス群 |
java.langは自動的にインポートされる。 | |
様々なAPIの詳細は「Java APIリファレンス」と検索すれば見れる。 |
オブジェクト指向 ~インスタンスとクラス~
オブジェクトの作成方法
①クラスの定義
②インスタンス化
③インスタンス(オブジェクト)の完成
オブジェクトの仕組みをガンプラで例えると・・・
①ガンプラの基本となる型を作れば
②それを利用し様々なガンプラを生成し
③できあがる
元となる基本を作れば簡単に大量生産できるメリットがある。
プログラムに必要なものをRPGで例えると・・・
・mainメソッド(神様クラス、最初に動く)
・その他のメソッド(登場人物クラス)
クラスの説明
public class Gokuu{
String name;
int hp;
void attack(){・・・}
void jump(){・・・}
}
変数を宣言することを属性の定義という。
定義された変数をフィールドという。
メソッドの宣言は操作の定義という。
フィールド宣言の頭に「final」を付けると値の変更不可になる。
「final」が付くと定数フィールドという。定数フィールドはわかりやすく大文字推奨。
final String NAME;
final int HP;
this
public class Gokuu{
String name;
int hp;
void attack(){
this.name = "悟空";
}
}
「this.name = "悟空";」と「name = "悟空";」は同じ動作だが、
ローカル変数や仮引数にも「name」が使われていれば予想外の動作が起こる可能性があり、
防ぐ為にthisで自身のフィールドだと現している。
以下は極端な例だが
「this」があるおかげで仮引数とフィールドの見分けがつきやすい。
public class Main {
public static void main(String[] args) {
//インスタンスの生成(後で説明)
Monster m = new Monster();
//引数「魔人ブウ」を渡す
m.attack("魔人ブウ")
}
}
public class Monster{
String name;
public void attack(String name){
//仮引数をフィールドに代入
this.name = name;
System.out.println(this.name + "を攻撃!")
}
}
クラス図
クラス⇒属性⇒操作 この3つでまとめた図をクラス図という。
フィールドとメソッドをまとめてメンバという。
クラス定義で可能になること
1.そのクラスに基づいてインスタンスを生成できる。
2.そのクラスから生まれたインスタンス を入れる変数の型が利用できる。
インスタンスの生成方法
クラス名 変数名 = new クラス名();
とあるクラスで悟空クラスのattackメソッドを利用したいとき
インスタンスを生成することで利用できる。
「new」インスタンスの生成を行う。
new Gokuu();
で悟空クラスのインスタンスを作成。
変数名は「gokuu1」とする。
悟空クラスのインスタンスなので型は「Gokuu」
よって、Gokuu gokuu1 = new Gokuu();
となる。
さらに悟空クラスのattackメソッドも使いたいので
gokuu1.attack();
となる。
また悟空クラスのHPフィールドを取得したいなら
gokuu1.hp;
と書けば良い。
生成は二行に分けても良い
Gokuu gokuu1; //クラス型はフィールドに用いることも可能。
gokuu1 = new Gokuu();
ここで「this」の説明時に用いたコードをもう一度見ると理解できる。
public class Main {
public static void main(String[] args) {
//インスタンスの生成
Monster m = new Monster();
//引数「魔人ブウ」を渡す
m.attack("魔人ブウ")
}
}
public class Monster{
String name;
public void attack(String name){
//仮引数をフィールドに代入
this.name = name;
System.out.println(this.name + "を攻撃!")
}
}
インスタンスの独立性
次のコードで出力される値はいくつか。
Gokuu g1 = new Gokuu();
g1.hp = 100;
Gokuu g2;
g2 = g1;
g2.hp = 200;
System.out.println(g1.hp);
実行結果は200。
g1とg2は同じ「new Gokuu();」を参照している。(配列のときと同じ。)
なのでg2で値を変更すればg1の値も変わる。
しかしインスタンスの独立性と言って、g2が自身で「new Gokuu();」すると、
参照はされない。
悟空1号と同じHPのコピーも作れるし、HPの違う悟空2号を作ることも可能ということ。
クラス型をメソッド引数や戻り値に用いる
とりあえずカリン様に回復を求める孫悟空。
public class Main {
public static void main(String[] args) {
Gokuu g1 = new Gokuu();
g1.hp = 100;
Karinsama k1 = new Karinsama();
k1.heal(g1); //悟空を渡して回復させる。
}
}
public class Karinsama {
public void heal(Gokuu g){
g.hp += 100;
System.out.println("カリン様に仙豆でHP100回復してもらった。")
}
}
コンストラクタ
newで生み出されたばかりのインスタンスのフィールドには、まだ何も入っていない。
しかし、厳密には初期値が設定されている。
フィールドの初期値
型 | 値 |
---|---|
int,short,long等 | 0 |
char | ¥u000 |
boolean | false |
配列 | null |
String,クラス | null |
newされた直後に自動的に実行されるメソッドをコンストラクタという。
これまではインスタンス後に悟空のHPを決めていたが、
基本的100で良いなら、悟空クラスで先に100を代入しておく。
public class Gokuu{
int hp;
public Gokuu(){
this.hp = 100;
}
}
コンストラクタになれる条件は2つ。
①メソッド名がクラスと同じ。
②メソッドに戻り値が宣言されていない(voidも✖)
名前などインスタンス毎に変えたいフィールドは引数にすれば良い。
public class SuperSaiyaJin {
int hp;
String name;
public SuperSaiyaJin(String name){
this.hp = 100;
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
SuperSaiyaJin gokuu = new SuperSaiyaJin ("悟空");
SuperSaiyaJin beji-ta = new SuperSaiyaJin ("ベジータ");
}
}
実はJavaはインスタンス化時、必ず1つはコンストラクタを定義しなければならない。
しかし、1つも定義されていなければコンストラクタが自動で生成される為、
今までは気にせずインスタンス化が可能だった。
コンストラクタのオーバーロード
コンストラクタも引数で判別して処理してくれる。
public class SuperSaiyaJin {
//引数なければこれが動く
public SuperSaiyaJin(){
}
//引数あればこれが動く
public SuperSaiyaJin(String name){
}
}
同一クラスのコンストラクタの利用
this();
で自身のコンストラクタを呼べる。
public class SuperSaiyaJin {
int hp;
String name;
public SuperSaiyaJin(){
this("悟空");
}
public SuperSaiyaJin(String name){
this.hp = 100;
this.name = name;
}
}
この状態だと引数無しで SuperSaiyaJin()を呼んだ場合でも、
this("悟空");
があるのでhpは100に設定されている。
静的メンバ
静的フィールド
インスタンスの独立性により、new毎に個々のフィールドを持っている。(自身でnewすれば参照(共有)されない)
ただしstaticを使うと全インスタンスで共有される。
インスタンスは別々で生成しても一部のフィールドを共有したいときに便利。
staticの付いたフィールドを静的フィールドという。
静的フィールドはインスタンス化しなくても使える。
この特徴からクラス変数ともいう。
使い方:クラス名.静的フィールド名;
※もちろん静的フィールドと言うこともあり、メソッド内の変数(ローカル変数)にstaticは付けられない。
静的メソッド
static付きのメソッドを静的メソッドという。クラスメソッドともいう。
静的フィールドと合わせて静的メンバと呼ばれる。
静的メソッドは静的フィールドと同じく以下3つの能力がある。
- ①メソッドがクラスに属する(共有される)ので、
クラス名.メソッド名();
で呼べる。 - ②
インスタンス変数名.メソッド名();
で呼べる。 - ③インスタンスを作らずとも呼べる。
※③にあるように、最初に呼ばれるmainメソッドはインスタンス化できないので常に「static」が必要となる。
public class Item {
public static void main(String[] args) {
static int money;
static void setRandomMoney(){
Item.money = (int)(Math.random()*1000);
}
}
}
public class Main {
public static void main(String[] args) {
//staticなのでnew不要
Item.setRandomMoney();
System.out.println(Item.money); //※1
Item i = new Item();
System.out.println(i.money); //※2
}
}
「Math.random()」は0.0~1.0未満の乱数を発生させる(double型)
※1と※2は今までなら別々の数字が出るが、今回の変数moneyは静的
つまり共有さているので同じ値が出力される。
静的メソッドの制約
静的メソッド内で「static」がないフィールドやメソッドは呼べない。
staticが付いたメソッドはインスタンス化せずに呼べるが、
ブロック内にstatic無しで宣言されていたフィールドがあればエラーとなる。
staticの付いていないフィールドはインスタンス化しないと呼べないからである。
静的メソッドで扱うフィールドは静的フィールドでなければならない。
続きはこちら⇒後編