Java入門
目次
- はじめに
- 動作環境
- 対象者
- Javaとは?
- 環境構築
- 最終目的
- コーディング規約
- ハローワールド
- データ形式
- 文字列
- 演算子
- 配列
- I/O
- 制御構造
- クラス
- パッケージ
- アクセス制御
- ポリモーフィズム
- オーバーロード
- オーバーライド
- インタフェース
- 抽象クラス
- 継承
- インラインメソッド
- 例外
- スレッド
- デバック
- 最後に
- 参考資料
はじめに
既に何かの言語を習得された方のためのJava入門です。 入門書にある例えなどはありません。 自分の習得した言語と機能を比較することで理解してください。 言語習得に必要な部分しか書きません コマンドラインで実行しながら学習してください。
動作環境
LinuxやCygwin, MacOSXなど
対象者
Javaのソースコードをとりあえず見てみたい方。
Javaとは?
1995年にJava言語として公開されました。
1998年12月にJ2SE1.2が公開され、この時に大幅な修正がありJava2と呼ばれるようになりました。
2002年2月にJ2SE1.4が公開されました。この時にも大幅な変更がありました。政治的理由などがありJava4などとはなっていません。
2004年9月にJ2SE1.5(= J2SE 5.0)が公開されました。今回はJava3とも呼べるぐらい大幅な変更がありました。今までの変更はライブラリの増加や小さな言語仕様の変化であったためさほど技術者に影響がなかったのですが、今回は大幅に言語仕様が変更されました。
J2SE Code Names(英語)
J2SE 5.0 Name and Version Change(英語)
最近、SunMicrosystems社はMicrosoft社と同様にJava言語に寿命をつけました。(Java[tm] Tecnology EOL Policy英語)。ビジネスとともに成長する言語は、政治経済のシステムから逃れることができないためこのような戦略を企業として打ち出すのですが、Java言語が拡張され成長し、今後衰退することを決定する事項となることが予想できます。当然、数年後に次世代の言語を公開する事も予想されます。
2005年7月、今年のJavaのカンファレンス(JavaOne 2005)でJ2SEやJ2EEの名称を変更しました。Java Platform Standard Edition 6の場合はJava SE 6というようになります。
環境構築
Java(ジャバ)入門・記事一覧を参考に環境構築してください。
最終目的
今回の目標は、復習です。
コーディング規約
ハローワールド
[s-okita@localhost java]$ cat HelloWorld.java
public class HelloWorld {
public static void main(String [] args) {
System.out.println("hello world");
}
}
[s-okita@localhost java]$ javac HelloWorld.java
[s-okita@localhost java]$ java HelloWorld
hello world
データ形式
Javaのプリミティブデータ型での特徴は、boolean型があることです。C++ではboolがありました。また、1byte(8bit)を表記するためにbyte型が存在します。
[s-okita@localhost java]$ cat DataType.java
public class DataType {
public static void main(String [] args) {
boolean boolValue = false;
byte byteValue = 0x00;
char charValue = 'a';
short shortValue = 128;
int intValue = 1000;
long longValue = 1000L;
float floatValue = 0.0f;
double trouble = 0.0D;
}
}
[s-okita@localhost java]$ javac DataType.java
^[[s-okita@localhost java]$ java DataType
文字列
java.lang.Stringクラスで文字列を表現する。C言語みたいに面倒な事をしなくてもよい。また文字を結合する場合は、StringBufferクラスを使うとパフォーマンスがよくなる。
[s-okita@localhost java]$ cat Strings.java
public class Strings {
public static void main(String [] args) {
String tmp = "hello";
System.out.println(tmp);
tmp = tmp + " world";
System.out.println(tmp);
StringBuffer sb = new StringBuffer(tmp);
sb.append(" hogehoge");
sb.append(" fugafuga");
System.out.println(sb.toString());
}
}
[s-okita@localhost java]$ javac Strings.java
[s-okita@localhost java]$ java Strings
hello
hello world
hello world hogehoge fugafuga
演算子
剰余を求めることができます。
[s-okita@localhost java]$ cat Operation.java
public class Operation {
public static void main(String [] args) {
int result = 0;
result = result + 1;
result = result * 2;
result = result - 1;
result = result / 1;
System.out.println(result%2);
}
}
[s-okita@localhost java]$ javac Operation.java
[s-okita@localhost java]$ java Operation
1
配列
[s-okita@localhost java]$ cat Array.java
public class Array {
public static void main(String [] args) {
/* int型の配列 */
int intArray [] = { 1,2,3,4,5 };
for ( int i = 0; i < intArray.length; i++ ) {
System.out.print(intArray[i]);
System.out.print(" ");
}
/* float型の配列 */
float floatArray [] = new float[5];
floatArray[0] = 0.1f;
floatArray[1] = 1.1f;
floatArray[2] = 2.1f;
floatArray[3] = 3.1f;
floatArray[4] = 4.1f;
for ( int i = 0; i < floatArray.length; i++ ) {
System.out.print(floatArray[i]);
System.out.print(" ");
}
/* java.lang.String型の配列 */
String stringArray [] = new String[5];
stringArray[0] = "H";
stringArray[1] = "E";
stringArray[2] = "L";
stringArray[3] = "L";
stringArray[4] = "O";
for ( int i = 0; i < stringArray.length; i++ ) {
System.out.print(stringArray[i]);
System.out.print(" ");
}
}
}
[s-okita@localhost java]$ javac Array.java
[s-okita@localhost java]$ java Array
1 2 3 4 5 0.1 1.1 2.1 3.1 4.1 H E L L O [s-okita@localhost java]$
I/O
キャラクタストリーム
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class AsciiIO {
public static void main(String [] args) {
AsciiIO aio = new AsciiIO();
try {
aio.exec();
} catch (IOException e) {
}
}
private void exec() throws IOException {
File f = new File("ascii_test.txt");
if ( !f.exists() ) {
f.createNewFile();
}
/* write to character stream */
FileWriter fw = new FileWriter(f);
System.out.println(fw.getEncoding());
fw.write("hello", 0, "hello".length());
fw.flush();
fw.close();
/* read character stream */
FileReader fr = new FileReader(f);
int buf;
while ( (buf = fr.read()) != -1 ) {
System.out.println((char)buf);
}
fr.close();
}
}
バイナリストリーム
[s-okita@localhost s-okita]$ cat BinaryIO.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BinaryIO {
public static void main(String [] args) {
BinaryIO bio = new BinaryIO();
try {
bio.exec();
} catch (IOException e) {
e.printStackTrace();
}
}
private void exec() throws IOException {
File f= new File("binary_test.txt");
if ( !f.exists() ) {
f.createNewFile();
}
/* write to binary stream */
FileOutputStream fos = new FileOutputStream(f);
byte [] b = new byte [] { 0x48, 'e','l','l','o' };
fos.write(b, 0, b.length);
fos.flush();
fos.close();
/* read from binary stream */
FileInputStream fis = new FileInputStream(f);
byte buf;
while ( (buf = (byte) fis.read()) != -1 ) {
System.out.println((char) buf);
}
fis.close();
}
}
[s-okita@localhost s-okita]$ javac BinaryIO.java
[s-okita@localhost s-okita]$ java BinaryIO
H
e
l
l
o
制御構造
分岐・反復
[s-okita@localhost java]$ cat Condition.java
public class Condition {
public static void main(String [] args) {
int i = 100;
/* C/C++言語とは、異なりboolean型で条件を判断します */
if ( true ) {
System.out.println(true);
} else if ( i == 100 ) {
System.out.println(i);
} else {
System.out.println("hoge");
}
int count = 0;
/* C/C++言語とは、異なりboolean型で条件を判断します */
while ( true ) {
count++;
if ( count == 100) break;
}
int msg = 5;
switch ( msg ) {
case 1:
System.out.println(1);
break;
case 2:
System.out.println(2);
break;
default:
System.out.println("default");
}
}
}
[s-okita@localhost java]$ javac Condition.java
[s-okita@localhost java]$ java Condition
true
default
クラス
インスタンス変数・インスタンスメソッド
インスタンスとは、メモリを確保した(malloc)データです。[s-okita@localhost java]$ cat Pearent.java
public class Pearent {
/* インスタンス変数 */
String name;
int age;
/* コンストラクタは初期化のために使います */
public Pearent() {
name = "satoshi";
age = 26;
}
/*aインスタンスメソッドはnewをしてから呼べるものです */
void printValues() {
System.out.println(name + age);
}
public static void main(String [] args) {
Pearent p = new Pearent();
System.out.println(p.name);
System.out.println(p.age);
p.printValues();
}
}
[s-okita@localhost java]$ javac Pearent.java
[s-okita@localhost java]$ java Pearent
satoshi
26
satoshi26
この状態では、外部からインスタンス変数にアクセスできてしまいます。そのためアクセス制御を行わなければなりません。(以降で説明)
クラス変数・クラスメソッド
クラス全体で使うものをstaticキーワードをつけてクラス変数やクラスメソッドにします。
[s-okita@localhost java]$ cat Constant.java
public class Constant {
static double tax = 0.05f;
static double getTax() {
return tax;
}
public static void main(String [] args) {
System.out.println(Constant.tax);
System.out.println(Constant.getTax());
}
}
[s-okita@localhost java]$ javac Constant.java
[s-okita@localhost java]$ java Constant
0.05000000074505806
0.05000000074505806
パッケージ
外部からアクセスさせないようにするためと、ソースコードを管理しやすいようにパッケージという機能があります。オブジェクト指向のカプセル化を実現する機能です。
[s-okita@localhost java]$ cat src/user/User.java
/* packageキーワードで自分のパッケージを作ります */
package user;
/* importキーワードで別のパッケージを取り込みます */
import util.MoneyUtility;
public class User {
public static void main(String [] args) {
double tax = MoneyUtility.getTax();
System.out.println(tax);
}
}
[s-okita@localhost java]$ cat src/util/MoneyUtility.java
package util;
public class MoneyUtility {
static double tax = 0.05f;
public static double getTax() {
return tax;
}
}
[s-okita@localhost java]$ javac src/util/MoneyUtility.java src/user/User.java
[s-okita@localhost java]$ ls src/util/
MoneyUtility.class MoneyUtility.java
[s-okita@localhost java]$ ls src/user/
User.class User.java
[s-okita@localhost java]$ java -cp src user.User
0.05000000074505806
アクセス制御
[s-okita@localhost java]$ cat AccessPrivilege.java
public class AccessPrivilege {
private String mySecret = "I am Japanese";
public String talkMySecret() {
return mySecret;
}
public static void main(String [] args) {
AccessPrivilege ap = new AccessPrivilege();
System.out.println(ap.talkMySecret());
}
}
[s-okita@localhost java]$ javac AccessPrivilege.java
[s-okita@localhost java]$ java AccessPrivilege
I am Japanese
なぜ、パッケージやアクセス修飾子が必要なのでしょうか?
構造化言語のように直接変数にアクセスしたほうがソースコードが読みやすいです。その答えは、OPC(OpenClosed Principale)という概念がオブジェクト指向には存在するからです。これは、追加には開いていて変更には閉じているという概念です。
たとえばバグがあったとしたら、修正ではなく、ソースコードを追加することで解決しようという思考があるのです。OPCについては、日本語の文献がほとんどないので、Java技術者でも理解している人は少ないですが、オブジェクト指向言語が良いとされているのは根底にこの概念があるからです。
構造化言語に対して、なぜクラスなどの複雑な概念が必要なのかはすべてOCPを目指しているからです。しかし、現在のオブジェクト指向言語ではその目標が達成されていないのも事実です。
ポリモーフィズム
多様性を実現するための機能。オーバーロードやオーバーライドがある。
オーバーロード
[s-okita@localhost java]$ cat Overload.java
public class Overload {
public static void main(String [] args) {
Overload ol = new Overload();
System.out.println(ol.getValue());
System.out.println(ol.getValue("HELLO"));
System.out.println(ol.getValue(1));
}
/* メソッド名はどうようだがシグネチャが異なる */
public String getValue() {
return "hello";
}
/* メソッド名はどうようだがシグネチャが異なる */
public String getValue(String src) {
return src;
}
/* メソッド名はどうようだがシグネチャが異なる */
public String getValue(int i) {
return Integer.toString(i);
}
}
[s-okita@localhost java]$ javac Overload.java
[s-okita@localhost java]$ java Overload
hello
HELLO
1
オーバーライド
[s-okita@localhost develop]$ cat Pearent.java Child.java
public class Pearent {
private String param1;
protected String param2;
public String param3;
public Pearent() {
System.out.println("Pearent Instanciate");
param1 = "param1Value";
param2 = "param2Value";
param3 = "param3Value";
}
public String getParam1() {
return param1;
}
public String getParam2() {
return param2;
}
public String getParam3() {
return param3;
}
}
public class Child extends Pearent {
public Child() {
super();
}
public String getParam3() {
System.out.println("in Child");
return param3;
}
/*
* launcher
*/
public static void main(String [] args) {
/* Pearentクラス型の変数pを宣言。まだデータはない。*/
Pearent p = null;
/* 変数pにChildクラスのインスタンスを生成
* (メモリの確保)
*/
p = new Child();
/*
* getParam3メソッドはオーバーライドされているので、
* 変数pの型ではなく、インスタンス(メモリ)によって
* メソッドがきまる
*/
System.out.println(p.getParam3());
}
}
[s-okita@localhost develop]$ javac Pearent.java Child.java
[s-okita@localhost develop]$ java Child
Pearent Instanciate
in Child
param3Value
インタフェース
[s-okita@localhost develop]$ cat Storage.java
public interface Storage {
public abstract void read(String key);
public abstract void write(String data);
}
[s-okita@localhost develop]$ javac Storage.java
[s-okita@localhost develop]$ java Storage
Exception in thread "main" java.lang.NoSuchMethodError: main
抽象クラス
[s-okita@localhost develop]$ cat DBStorage.java
public abstract class DBStorage implements Storage {
public void read(String key) {
}
public void write(String data) {
}
public abstract Object select(String key);
public abstract boolean insert(String data);
public abstract boolean update(String data);
public abstract boolean delete(String data);
}
[s-okita@localhost develop]$ javac DBStorage.java
[s-okita@localhost develop]$ java DBStorage
Exception in thread "main" java.lang.NoSuchMethodError: main
継承
[s-okita@localhost develop]$ cat CustomDBStorage.java
public class CustomDBStorage extends DBStorage {
public void read(String key) {
}
public void write(String data) {
}
public Object select(String key) {
return null;
}
public boolean insert(String data) {
return true;
}
public boolean update(String data) {
return true;
}
public boolean delete(String data) {
return true;
}
public static void main(String [] args) {
System.out.println("hoge");
}
}
[s-okita@localhost develop]$ javac Storage.java DBStorage.java CustomDBStorage.java
[s-okita@localhost develop]$ java CustomDBStorage
hoge
インラインメソッド
s-okita@localhost develop]$ cat InlineTest.java
public class InlineTest {
final void print() {
System.out.println("hoge");
}
public static void main(String [] args) {
InlineTest it = new InlineTest();
it.print();
}
}
[s-okita@localhost develop]$ javac InlineTest.java
[s-okita@localhost develop]$ java InlineTest
hoge
例外
[s-okita@localhost java]$ cat MyException.java
public class MyException {
public static void main(String [] args) {
MyException myExcept = new MyException();
try {
myExcept.exeException();
} catch (HogeException e) {
if ( e instanceof HogeException ) {
System.out.println("catch hoge Exception!!!");
} else {
System.out.println("catch other Exception!!!");
}
}
}
public void exeException() throws HogeException {
try {
System.out.println("throw HogeException");
throw new HogeException();
} catch (HogeException e) {
System.out.println("catch exception class.");
throw e;
} finally {
System.out.println("execute finally statement.");
}
}
}
class HogeException extends Throwable {
}
[s-okita@localhost java]$ javac MyException.java
[s-okita@localhost java]$ java MyException
throw HogeException
catch exception class.
execute finally statement.
catch hoge Exception!!!
スレッド
スレッドの簡単なサンプル。Javaでは標準ライブラリにスレッド用クラスjava.lang.Threadがあるのでそれを利用する。以下のサンプルはmainメソッドを実行することで、TestThreadスレッドを呼び出す。これにより同時に2つの処理が可能になる。スレッドを増やせばその分処理を同時に実行できる。
$ cat TestThread.java
public class TestThread extends java.lang.Thread {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public void run() {
System.out.println("thread runing!!");
this.setUsername("satoshi");
}
}
stoc@stoc-61vmpwgpbm ~
$ javac TestThread.java
stoc@stoc-61vmpwgpbm ~
$ cat RunThread.java
public class RunThread {
public static void main(String [] args) throws Exception {
TestThread tt = new TestThread();
tt.start();
tt.join();
System.out.println(tt.getUsername());
}
}
stoc@stoc-61vmpwgpbm ~
$ javac RunThread.java
stoc@stoc-61vmpwgpbm ~
$ java RunThread
thread runing!!
satoshi
デバック
SDKには、jdbというJava debuggerが付属しているが、あまり利用する人はいないようです。EclipseやJUnitでのテストとデバックを行っている技術者が多いようです。
最後に
今回、Java言語の復習もかねて、Java入門を記述してみました。Java言語のみを触れていると意識しないことだが、Java言語は標準ライブラリをどれだけ知っているかでコーディングに差が出るような気がしました。C言語などは、関数がなければ作るという発想の言語体系なのに対し、Java言語は、できているものをどこから探すか(javadoc ,websearch)という言語なのかと改めて感じました。
今日のIT技術の進化速度を考えると、非常に効率の良い開発ができる言語であるが、技術者がこの盲点に気づかないのであれば、コンピュータの詳細を理解、実装できるプログラマと、要件をJava言語に置き換えるだけのプログラマ(軽視:トランスレータ、デジタル土方)の二極化が今後進む事が予想される。
