2017-04-13 第2回目 Java言語の基礎2
本日のテーマ
Java言語の基礎2
コメント
Javaのコメントは3種類の書き方ができます.
- 一行コメント
//
以降改行までがコメントとして扱われます.
- 通常コメント
/*
と*/
で囲まれた部分がコメントとして扱われます.- C言語と同じスタイルです.
- Javadoc コメント
/**
と*/
で囲まれた部分がコメントとして扱われます.- 通常コメントと同じような書き方ですが,このコメントがかける場所は次の3つに限られています.
- クラス宣言の前,
- メソッド宣言の前.
- フィールド宣言の前.フィールド宣言とは,クラス宣言の内側,かつ,メソッド宣言の外側で定義された変数を指します.
javadoc
コマンドにより,ソースファイルからドキュメントを生成できますが,その時にドキュメントに掲載する文章をこのコメントで記します.- この授業では扱いません.
クラス定義の基本形
まずは,以下のクラスファイルの基本形を覚えておきましょう.
GivenClassName
は与えられたクラス名に置き換えてください.
run
メソッド内に指定されたプログラムを書いてください.
main
メソッドは返り値の型の前にpublic static
というキーワードがついていますが,これらのキーワードは今のところは main
のみにつけるものと思ってください.
public class GivenClassName{
void run(){
// ここに課題内容のプログラムを書く.
}
public static void main(String[] args){
GivenClassName application = new GivenClassName();
application.run();
}
}
ここで注目してもらいたいのは,6行目,GivenClassName application = new GivenClassName();
と,
7行目のapplication.run();
です.
6行目のnew GivenClassName()
でGivenClassName
という型の実体を作成し,
GivenClassName
型の変数application
に代入しています.
そして,7行目のapplication.run()
は,変数application
に対して,
run
メソッドを呼び出しています.
C言語とは異なり,Java言語では,メソッドはどこかの型の実体に必ず所属しています. そのため,メソッドを呼び出すときは,どの実体に対して呼び出すのかを明示しなくてはいけません.
new演算子
先ほど,new
で実体を作成したと言いました.
次のプログラムは今まで書いてきたプログラムの例です.
Integer value1 = 3;
Integer value2 = 5;
Integer result = value1 + value2;
System.out.println(result);
実は,このプログラムは,様々なものが省略されています.省略せずに書くと,次のようなプログラムになります.
Integer value1 = new Integer(3);
Integer value2 = new Integer(5);
Integer result = new Integer(value1 + value2);
System.out.println(result);
このように,実は,実体を作成して変数に代入しています. Java言語では,ほぼ全てこのように実体を作成しなければ変数に代入できないことを覚えておいてください.
変数
宣言場所
変数は宣言する場所によって2種類の呼び方があり,特徴も少し異なります.
一つは,メソッド内で宣言する変数,ローカル変数(local variable),
もう一つは,メソッドの外で宣言する変数,フィールド(field)です.
メソッドもフィールドもどちらも,クラス宣言の直下になければいけません(クラス宣言の括弧({ }
)のすぐ内側).
- フィールド(field)
- 初期値は
null
(何も参照していないことを表す予約語). 変数名.フィールド名
でアクセスできる.- 有効範囲は,そのフィールドが宣言されているクラスの実体が有効な範囲.
- クラスの実体の有効範囲と同じ.
- クラスの実体の有効範囲は,そのクラスがフィールド,ローカル変数のどちらで宣言されたかによって異なる.
- 初期値は
- ローカル変数(local variable)
- 初期化されなければコンパイルエラーとなる.
- 有効な時間は,そのメソッド内のスコープ内のみ.
- その変数が宣言された箇所以降かつ,宣言された場所の一番内側の括弧内(
{ }
)のみ.
- その変数が宣言された箇所以降かつ,宣言された場所の一番内側の括弧内(
プログラムを書くとき,変数の有効範囲はできるだけ狭く,というのが定石です. そのため,基本的には,ローカル変数を使い,ローカル変数で対応できない場合に,フィールドを利用しましょう.
実体
実体を確認するために,次のプログラムを考えてみましょう.
Date
は日付を表す型です.new Date()
,
もしくは,new Date(Integer year, Integer month, Integer day, Inetger hour, Integer minute)
という命令で実体を作成します.ただし,年月日,時間を指定する場合,年は1900年からの経過年数,
月は0から始まる(0が1月を表す)点に注意してください.
古い時代のもので,互換性のために残されているもので,変な仕様ではありますが,これで確認してみましょう.
また,コンパイル時に「非推奨のAPIを使用または...」という注意が出ますが,無視してください. これはコンパイルエラーではなく,注意(Warning)ですので,コンパイルはできています. お勧めできない古い時代のライブラリを使っている時に出ます.基本的には使わない方が良いのですが, 今回は説明のために用います.
なお,Date
型を利用するときは,import java.util.Date
が
クラス宣言の前に必要になります.import
文が必要な理由は,
FAQ import文とは何かを参照してください.
実際に,入力して,どのような実行結果になるかを考えてから,動かしてみましょう. そして,予想との違いを考えてください.
import java.util.Date;
public class DateExample{
void run(){
// year は 1900年からの経過年数.
// month は 0 から始まる.
Date date1 = new Date(115, 8, 29, 9, 0);
Date date2 = date1;
System.out.printf("date1: %s%n", date1);
System.out.printf("date2: %s%n", date2);
// Year を +1 している.
date1.setYear(date1.getYear() + 1);
System.out.printf("date1: %s%n", date1);
System.out.printf("date2: %s%n", date2);
}
public static void main(String[] args){
DateExample example = new DateExample();
example.run();
}
}
Javaの変数はほぼ全てがポインタとなっています.
ポインタとは,メモリ領域の特定の場所を指し示すだけの変数です.
上のプログラムの date2 = date1
という命令が実行されると,date2
にdate1
の参照先が代入されたことを表します.
その結果,date1
と date2
は同じ参照先の実体を指し示すようになり,
一方を変更すると(date1.setYear(...);
),
もう一方も変更されることになります.
下の図をクリックすると図が更新されます.何度かクリックして見て動作を確認しましょう.
基礎プログラミング演習で学習したものとは変数の扱いが異なる場合がありますので,注意してください. Java言語では,全ての変数は,メモリ上のどこかにある実体を参照しているものと思ってください.
参照の一致性
先のプログラムの run
メソッドに次のコードを追加して,実行結果を確認してみましょう.
void run(){
Date date1 = new Date(115, 8, 29, 9, 0);
Date date2 = date1;
date1.setYear(date1.getYear() + 1);
// 以下のプログラムを追加する.
Date date3 = new Date(116, 8, 29, 9, 0);
System.out.println(date1 == date2);
System.out.println(date1 == date3);
System.out.println(date2 == date3);
}
各変数が指し示す Date
型変数の値は全て,2016-09-29 9:00
になっているはずですが,
なぜ true
とfalse
という違いが現れるのでしょうか.
実は,==
は参照先が同じであるかを判定する演算子であり,値が一致するか否かは判定されません.
以下の画像をクリックし,動作を確認してみましょう.
値の一致性
では,2つの変数の値が一致するかどうかを判定するにはどうすれば良いのでしょうか.
それには,Objects
型のequals
メソッドを利用します.
先ほどと同じく,run
メソッドに次の処理を追加し,実行結果を確認しましょう.
import java.util.Date;
import java.util.Objects;
public class DateExample{
void run(){
// ...
// 次の処理を追加する.
System.out.println(Objects.equals(date1, date2));
System.out.println(Objects.equals(date1, date3));
System.out.println(Objects.equals(date2, date3));
}
// ...
}
このようにすることで,値の一致性を確認できます. Javaで比較する時は,参照の一致か,値の一致か,どちらを判定したいのかを区別して比較しましょう.
なお,Objects
型を利用するときは,クラス宣言の前に import
文が必要です.
import java.util.Objects
と書いてください.
配列
宣言方法
Java言語にもC言語と同じように,配列が存在します. ただし,宣言の方法はC言語とは異なります.
// C言語は以下のように,変数名に配列を表す記号をつけていた.
int array[];
// Java言語では,型名の方に配列を表す記号をつける.
// Integerの配列型である array を宣言する,と考えてください.
Integer[] array;
配列の長さ
Java言語で配列の長さを取得するには,配列型の変数に .length
をつけることで取得できます.
Integer[] array = // ... ;
System.out.println(array.length); // => arrayの長さが出力される.
配列の各要素
配列の各要素にアクセスするには,C言語と同じく,array[0]
のように書きます.
この array[0]
の 0 をインデックスと呼びます.
配列の要素は,0から始まり,配列の長さ - 1
のインデックスまでが配列の有効な範囲です.
配列の範囲外の要素にアクセスしようとすると,ArrayIndexOutOfBoundsException
というエラーが発生します.
配列の例
では,次のように,String
型の配列であるarray
の各要素から図のように文字列が参照されている例を考えましょう.
この時,以下の処理を行うと,どのような結果になるか考えましょう.
System.out.println(array.length);
System.out.println(array[1]);
System.out.println(array[5]);
System.out.println(array[6]);
Moodle上の小テストを受験してください.
配列の作成方法
この授業では扱いません.基本的に自分で配列を作成することはなく,
すでにあるものを利用するのみとします.
配列が必要な場合は,4回目で扱う List
を利用するようにしましょう.
コマンドライン引数
今まで,main
メソッドの引数に String
型の配列がついていました.
この変数を使うと,コマンドライン引数で受け取った値をプログラムから利用できます.
次のプログラムで,コマンドライン引数で与えられた値を全て出力してみましょう.
public class ArgsPrinter{
void run(String[] args){
for(Integer i = 0; i < args.length; i++){
System.out.printf("%d: %s%n", i, args[i]);
}
}
public static void main(String[] args){
ArgsPrinter printer = new ArgsPrinter();
printer.run(args);
}
}
入力できれば,上記のプログラムを実行して実行結果を確認してください. 実行する時,コマンドライン引数をいくつか与えてみてください.
$ java ArgsPrinter
$ java ArgsPrinter abc def ghi
$ java ArgsPrinter abcdefg
$ java ArgsPrinter 0 1 2 3 4 5 6 7 8 9
このように,run
メソッドが引数を受け取るようにすることもできます.
必要に応じてコマンドライン引数を run
メソッドでアクセスできるようにしましょう.
練習問題
1. HelloWorld 改
コマンドライン引数で与えられた人に,挨拶しましょう.
もし,誰も指定されない場合は,"Hello, World"
と出力してください.
クラス名は,HelloWorld2
とし,クラス定義の基本形に従ってプログラムを書いてください.
コマンドライン引数も参考になるでしょう.
出力例
$ java HelloWorld2 Tamada
Hello, Tamada
$ java HelloWorld2 Sagisaka
Hello, Sagisaka
$ java HelloWorld2
Hello, World
2. HelloWorld 改2
コマンドライン引数で与えられた人に,挨拶しましょう.
基本的には,HelloWorld 改と同じですが,もし,
"World"
が指定されたら,"Hi, World"
と気さくに挨拶してください.
クラス名は,HelloWorld3
とし,クラス定義の基本形に従ってプログラムを書いてください.
コマンドライン引数も参考になるでしょう.
出力例
$ java HelloWorld3 Sagisaka
Hello, Sagisaka
$ java HelloWorld3 Tamada
Hello, Tamada
$ java HelloWorld3 World
Hi, World
$ java HelloWorld3
Hello, World
3. 階乗
コマンドライン引数であたえられた数値の階乗を計算するプログラムを作成してください. $n$の階乗は,$n! = n \times (n - 1) \times (n - 2) … 2 \times 1$ で求められます.
public class Factorial{
void run(String[] args){
Integer number = new Integer(args[0]);
Integer factorial;
// number の階乗を計算する.
System.out.printf("%d! = %d%n", number, factorial);
}
// mainメソッドは省略
}
String
型からInteger
型への変換
なお,String
型の変数からInteger
型に変換するには,以下のように行います.
Factorial
の3行目で同じことを行っています.
// Integer max = "15"; // コンパイルエラー."15"という文字列はそのまま Integer 型に代入できない.
String numberString = "15";
Integer max = new Integer(numberString); // => max には 15 という数値が代入される.
出力例
$ java Factorial 3
3! = 6
$ java Factorial 4
4! = 24
$ java Factorial 5
5! = 120
4. FizzBuzz
FizzBuzz は1から特定の値までの数値を順に出力します.
ただし,3の倍数の時は,数値の代わりに Fizz
という文字列を,
5の倍数の時は,数値の代わりに Buzz
という文字列を,
3と5の公倍数の時は,数値の代わりに FizzBuzz
という文字列を出力します.
クラス名は,FizzBuzz
としてください.
コマンドラインから受け取った値まで,上記のルールに従って値を出力してみましょう. もし,コマンドラインで値が指定されなかったときは,15が指定されたものとして処理を進めてください.
出力例
$ java FizzBuzz 3
1
2
Fizz
$ java FizzBuzz
1
2
Fizz
4
Buzz
... 途中省略
13
14
FizzBuzz
5. Fibonacci数列
Fibonacci数列とは,次の漸化式で表される数列です.
このFibonacci数列を初項からコマンドライン引数で指定された項まで出力してみましょう.
コマンドライン引数が指定されなかった場合は,20項目(20項も出力結果に含む)までを出力するようにしてください.
クラス名は,Fibonacci
とします.
\[
F_i = \begin{cases}
1 & i=1\\
1 & i=2\\
F_{i-2}+F_{i-1} & i\geq 3
\end{cases}
\]
出力例
$ java Fibonacci 3
1 1 2
$ java Fibonacci 8
1 1 2 3 5 8 13 21
$ java Fibonacci 15
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610
$ java Fibonacci
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
まとめ
- Java言語の基礎2
- コメント
- 1行コメント,通常コメント,Javadocコメントの3種類が存在する.
- クラス定義の基本形
- 変数
- フィールドとローカル変数がある
- Javaの変数はポインタである
- 参照の一致性
- 指し示している先が一致するかを判定するには
==
.
- 指し示している先が一致するかを判定するには
- 値の一致性
- 変数が表す値が一致するかを判定するには
Objects.equals(val1, val2)
. Objects
を利用するにはimport
文が必要.
- 変数が表す値が一致するかを判定するには
- 配列
- 配列の宣言方法
Integer[] array
のように型名に[]
を付ける.
- 配列の長さ
array.length
のように配列変数に.length
を付ける.
- 配列の各要素へのアクセス方法
array[0]
のように配列変数に[0]
を付ける.- ここの
0
を配列のインデックスと呼ぶ. - 配列の有効範囲は
0
から配列の長さ - 1
まで. - 配列の有効範囲を超えてアクセスしようとすると,
ArrayIndexOutOfBoundsException
というエラーが発生する.
- 配列の宣言方法
- コマンドライン引数
main
メソッドの引数であるString
型の配列はコマンドラインで指定された値が格納される.
- コメント
- その他