間違ってたら指摘してくださいm(_ _)m
Sun Microsystems(現Oracle)が開発した言語です。
VM(仮想マシン)上で動かすことで、様々なプラットフォームで同じコードが動くことを目的としています。
しかし、PC向け、モバイル向け等のSDKが出ているのですべてのプラットフォームで同じコードが動くかというと、動かないのが現実です。
また、VMの違いによって、動作が異なる場合があります。
ちなみに、JavaScriptという言語もあるが、「Java」とついてはいるが、全くの別物です。
余談ですが、稀に書店などでJavaとJavaScriptの専門書が一緒におかれている場合があります。
種類 | 概要 |
J2SE | 一般的なSDKになります。Windows等でJavaアプリを開発する際に利用されます。 |
J2ME | モバイル向けのSDKです。フューチャーフォン向けとして日本では使われます。 |
J2EE | J2SEに電商取引などのサーバー処理を行う為の機能を追加したものです。 |
最低でもJDKとコンソール、あとテキストエディタがあれば開発可能です。
定番はEclipse。
なので、Eclipseを使うことを前提に話を進めます。
クラスというのは、機能(メソッド)や情報(変数)を詰め込んだ塊です。
たとえば、車にはハンドルやアクセルといった「機能するもの」があり、速度やガソリンの量といった「情報」があります。
メソッドは、ハンドルやアクセルといった「機能するもの」のようなものです。
変数は速度やガソリンの量といった「情報」のようなものです。^
パッケージはクラスをまとめる名前のようなものです。
パッケージは階層化され管理します。
一番簡単なプログラムは「Hello World!」を表示するプログラムです。
この言葉、プログラムを勉強するときにかなりの確率で遭遇する言葉です。
まぁ、それはいいとして、さっそくコードを書いてみましょう。
#codeprettify{{ package jaghama.sample01_1; class HelloWorld{
public static void main(String[] args){ System.out.println("Hello World!"); }
} }}
まず、main()メソッドですが、これはJavaのプログラムが動いたときに必ず呼び出されます。
ただし、Web系やAndroidではmain()メソッドはありません。
System.out.println("Hello World!");
これは、文字を出力する処理になります。
実行するとコンソールに"Hello World!"が出力されます。
変数を使ってみます。
#codeprettify{{ package jaghama.sample01_2; class HelloWorld{
public static void main(String[] args){ String helloWorld = "Hello World!"; System.out.println(helloWorld); }
}
}}
実行してみると、同じようにコンソールに"Hello World!"が出力されます。
Stringとはクラスで、文字列を扱うクラスです。
Stringクラスは文字列を扱うための機能を持っています。
その機能に関してはこのあと扱っていきます。
数字の計算を行うのも簡単にできます。
#codeprettify{{ package jaghama.sample02_1; class Calculation{
public static void main(String[] args){ int a = 1; int b = 2; int sum = a + b; System.out.println(a + "+" + b + "=" + sum); }
}
}}
intは整数を扱う型です。
変数aと変数bを足して、変数sumにその結果を格納しています。
あとは、Hello World!の時のようにSystem.out.println()メソッドでコンソールに結果を出力しています。
Javaにかかわらず、プログラムでは計算に+,-,*,/を使います。
これらを演算子といいます。
演算子 | 意味 |
+ | 足し算 |
- | 引き算 |
* | 掛け算 |
/ | 割り算 |
% | 余り |
また、int型以外にも数値を扱う型が有ります。
型 | 意味 |
boolean | 真偽値を扱う型。true,falseを値として格納 |
byte | 8ビット符号付き整数。扱える数は-2^7(-128)~2^7-1(127) |
char | 16Bit Unicodeキャラクターデータ |
short | 16ビット符号付き整数。扱える数は-2^15(-32768)~2^15-1(32767) |
int | 32ビット符号付き整数。扱える数は-2^31(-2147483648)~2^31-1(2147483647) |
long | 64ビット符号付き整数。扱える数は-2^63(-9223372036854775808)~2^63-1(9223372036854775807) |
float | 32ビット符号付き浮動小数点数 |
double | 64ビット符号付き浮動小数点数 |
文字列を結合する場合、以下のように記述できます。
#codeprettify{{ package jaghama.sample03_01; public class StringFunc {
public static void main(String[] args) { String a = "A"; String b = "B"; String ab = a + b; System.out.println(ab); }
} }}
変数aと変数bに格納された文字を変数abに結合して格納します。
実行すると、コンソールには"ab"と表示されます。
ただし、この書き方は実はJavaでは推奨されません。
文字列を結合する場合、StringBufferクラスやStringBuilderクラスを使うことが推奨されています。
StringBufferクラスとStringBuilderクラスは提供される機能は同じですが、同期化が保障されるかされないかの違いがあります。
同期化はスレッドなどで並列で非同期に処理を行う場合に意識する必要があります。
今回は、StringBufferクラスを使ってみます。
#codeprettify{{ package jaghama.sample03_02; public class StringFunc {
public static void main(String[] args) { String a = "A"; String b = "B"; StringBuffer sb = new StringBuffer(); sb.append(a); sb.append(b); System.out.println(sb.toString()); }
} }}
行数が増えてしまいましたが、実行すると、StringBufferクラスを使っていない場合と同じ結果がコンソールに出力されます。
本などを読むとオブジェクトやインスタンスという言葉を見かけると思います。
意味合い的には
というようになります。
第3章でStringBufferクラスの変数を宣言したときに、newという命令が使われました。
newとは、新しいインスタンスを作りますという宣言です。
変数を使う場合、クラスから変数を宣言する場合にはnewでインスタンスを作る必要があります。
Stringクラスの場合、代入することでインスタンスが自動的に生成されるので、newは必要ありません。
プログラムで変数を扱う場合、変数を格納する領域をメモリ上に確保する必要があります。
newはその領域を確保する意味を持ちます。
わかりやすく言うと、newしていない状態は、倉庫の建築予定地、newした場合は倉庫が建築された状態になります。
予定地に物を入れることができなければ、電話もないので連絡することもできません。
既に倉庫ができていれば、ものを入れられますし、電話があれば電話を掛けることもできます。
その為、newせずにメソッドにアクセスすると、エラーになります。
(その前にビルドエラーになると思いますが・・・)
試に以下のソースを入力して、ビルドしてみてください。
エラーになります。
#codeprettify{{ package jaghama.sample04_01; public class NewClass {
public static void main(String[] args) { Object obj1 = new Object(); Object obj2; //↓これはエラーにならない obj1.toString(); //↓これはエラーになる obj2.toString(); }
} }}
JavaではC/C++のようにnewしたものを解放しなくてもガベージコレクション(以下GC)というものがメモリ解放を行ってくれます。
ただし、何らかのインスタンスで保持し続けたりすると、GCがメモリ解放できず、メモリを占有し続けることがあります。
Javaはメモリ管理を行わなくてもよいといわれることがありますが、そんなことはないので気を付ける必要があります。
GCはVMが自動的に行う為、メモリの解放タイミングを自分で制御できません。
ただし、利用した変数にnullを設定することで、GCの対象となります。
強制的にGCを呼び出すこともできますが、推奨されませんのでここでは触れません。
Fileクラスはパスやファイルの権限等を扱うクラスです。
ファイルの情報を参照してみましょう。
#codeprettify{{ package jaghama.sample05_01; import java.io.File; public class FileRef {
public static void main(String[] args) { File f = new File("test.txt"); System.out.println("Name : " + f.getName()); System.out.println("Length : " + f.length()); System.out.println("isDirectory : " + f.isDirectory()); System.out.println("isFile : " + f.isFile()); }
} }}
実行すると、ファイルの名前、サイズ、ディレクトリかどうか、ファイルかどうかが表示されます。
このほかにも、ファイルを削除したり、ディレクトリを指定している場合は、ファイルの一覧を取得すること等もできます。
importというキーワードがソース上に出てきましたが、これは「"java.io.File"をこのソースで利用します」という宣言になります。
利用したいクラス(java.langパッケージのクラスを除く)をimportを使って宣言して利用するのがJavaの書き方になります。
import java.io.*;とすると、java.ioパッケージのすべてのクラスを参照可能にすることを表します。
ただし、こうすると、ビルドが遅くなることがあります。
その為、importに書く場合は、必ずフルパッケージ名(パッケージ+クラス名)にするようにしてください。
ファイルを読み込む場合は、Readerクラス、InputStreamクラスを実装したクラスを利用します。
個人的にInputStreamクラスが好きなので、InputStreamクラスを使った例を挙げます。
#codeprettify{{ package jaghama.sample05_02;
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException;
public class FileRead {
public static void main(String[] args) { File f = new File("test.txt"); // ファイルを読み込むストリーム FileInputStream fis = null; // byte配列を書き込むストリーム ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 読み込んだ内容を保持する配列 byte[] buff = new byte[1024]; long len = 0; try { // FileInputStreamクラスのインスタンスを生成 fis = new FileInputStream(f); do{ // ファイルから読み込む len = fis.read(buff); // ByteArrayOutputStreamに書き込む baos.write(buff, 0, (int)len); //読み込んだ長さが1024なら継続する }while(len == 1024); // byte配列から文字列を生成する String str = new String(baos.toByteArray()); System.out.println(str); } catch (FileNotFoundException e) { // ファイルがない場合に発生するFileNotFoundExceptionをキャッチする e.printStackTrace(); } catch (IOException e) { // そのほかのI/O系の例外をキャッチする e.printStackTrace(); } finally { // 例外が発生してもしなくても必ず最後に行う処理 if(fis != null){ try { // ストリームを閉じる fis.close(); } catch (IOException e) { e.printStackTrace(); } fis = null; } } }
} }}
基本的な流れはFile()インスタンスを作って、作ったインスタンスをもとにInputStreamのインスタンスを作るという流れです。
で、ファイルを読み込むわけですが、ファイルを一定サイズで読み込んで、ByteArrayOutputStreamのインスタンスに書き込んでいます。
これは、byte配列をストリームに書き込んでおいて、後でbyte配列を取得するために行っています。
ファイルサイズが小さいものはこんなことしなくてもいいんですけどね。
これらの処理を囲うようにtry~catch~finallyがありますが、これは例外を処理するためのものです。
try~catch~finallyについては後程説明します。
Javaに限らず、C++やC#なんかでも問題があったりすると、例外というものが発生します。
問題が発生した場合に対処する必要があり、その対処を行う為にtry~catchを使います。
tryの{}の中が例外が発生する箇所、catch{}の中が例外を処理するところになります。
finallyは例外が発生してもしなくても行いたい処理を記述するところです。
この例の場合、例外が発生してもしなくてもBufferedInputStreamで開いたストリームを閉じるように処理しています。
catchの()の中には、キャッチしたい例外のクラスを記述します。
発生する例外ごとにcatchは記述することが大切です。
catch(Exception e)と書けますが、この場合、すべての例外をキャッチしてしまいます。
便利ですが、どの例外に対して対処したいのかが不透明になりますし、本来呼び出し元より上に通知すべき例外が通知できなくなることがあります。
その為、catchは発生しうる例外ごとに記述するほうが望ましいです。