クラス
- Javaアプリケーションの基本
- クラスを組みあわせアプリを構成
修飾子
- クラスやメンバーの性質を決めるキーワード
- クラス修飾子
- public:全クラスからアクセス可能
- final:継承を許可しない
- abstract:抽象クラス
- strictfp:浮動小数点を環境依存しない方法で演算
public
-
アクセス修飾子:現在のクラスが全てのクラスからアクセスできる
- 指定ない場合、同じパッケージからのアクセスのみ(パッケージプライベート)
strictfp
- strictfp演算子を付与した配下の浮動小数点数は常にIEEE754規格で処理
- 環境によらず同じ結果が得られる!
- cf:浮動小数点そのものの誤差をなくしたい場合、BigDecimalクラス
クラスの構成
- クラス
- Staticメンバー
- クラスフィールド
- static初期化ブロック
- クラスメソッド
- インスタンスメンバー
- フィールド
- 初期化ブロック
- コンストラクター
- メソッド
- Staticメンバー
フィールド
- メンバー変数:クラスの管理すべき情報
- 変数の命名規則
-
.
でアクセス
Person.java
//String型のname, int型のageフィールド定義
public class Person {
public String name;
public int age;
}
Main.java
public class Main {
public String firstName;
public String lastName;
public static void main(String[] args) {
//new演算子でインスタンス化
var p1 = new Person();
p1.name = "山田太郎";
p1.age = 30;
var p2 = new Person();
p2.name = "鈴木一郎";
p2.age = 25;
System.out.printf("%s(%d歳)\n", p1.name, p1.age); //山田太郎(30歳)
System.out.printf("%s(%d歳)\n", p2.name, p2.age); //鈴木一郎(25歳)
}
}
フィールドの修飾子
- 一般的にpriveteを使ってアクセスを限定
- クラス利用時にデータの持ち方を意識せずに済む
- public:全クラスからアクセス可
- protected:現クラスと派生クラス、同じパッケージのみアクセス可
- private:現クラスからのみアクセス可、デフォルト値
- static:クラスフィールドを宣言
- final:再代入禁止
- transient:シリアライズ対象除外
- volatile:値のキャッシュ抑制
フィールド規定値
- フィールドのデータ型による規定値を持つ
- 規定値をそのまま使う場合は初期化しなくてもいいが可読性に欠ける
- cf: メソッド宣言の変数(ローカル変数)は規定値なし
- boolean:false
- byte, short, int, long:0
- float, double:0.0
- char:\u0000
- 参照型:null
メソッド
- クラスの動作、処理、振る舞いを表す
- クラスのデータ値(フィールド)を操作
- mainメソッド:アプリのエントリポイント、起動時に自動実行
- 他一般的なメソッドは
.
演算子で他のメソッドから呼び出して実行
Person.java
//showメソッド定義
public class Person {
public String name;
public int age;
public String show() {
return String.format("%s(%d歳)です。", this.name, this.age);
//return String.format("%s(%d歳)です。", name, age);
}
}
MethodBasic.java
//p.showでshowメソッドにアクセス
public class MethodBasic {
public static void main(String[] args) {
var p = new Person();
p.name = "山田太郎";
p.age = 30;
System.out.println(p.show());
}
}
メソッド引数
- 実引数:呼び出し元から渡される
-
仮引数:受け取り側変数
- メソッド内からのみアクセス可能(ローカル変数)
//実引数
getBmi(60,1.7)
//仮引数
public double GetBmi {double weight, double height){
return weight / (height * height )
}
- 引数が多い場合、関連引数をクラスにまとめる
- 引数の順
- 重要なものから
- 順序に一貫性
- 関連引数は近接
メソッドの戻り値
- returnで処理結果を戻す
- return以降の命令は実行されない
- 戻り値がない場合は省略可能、メソッド定義の型にviodを指定
- voidメソッドでも
return ;
で明示的に処理を呼び出し元に返すことが可能
Person.java
public class Person {
public String name;
public int age;
public void show() {
System.out.printf("%s(%d歳)です。\n", this.name, this.age);
}
}
MethodVoid.java
public class MethodVoid {
public static void main(String[] args) {
var p = new Person();
p.name = "山田太郎";
p.age = 30;
p.show();
}
}
メソッドの修飾子
- 修飾子でクラス利用時にデータの持ち方を意識せずに済む
- public:全クラスからアクセス可
- protected:現クラスと派生クラス、同じパッケージのみアクセス可
- private:現クラスからのみアクセス可、デフォルト値
- static:クラスメソッドを宣言
- abstract:抽象メソッドを宣言
- final:オーバーライド禁止
- synchronized:1スレッドからのみアクセス可能
- strictfp:浮動小数点を環境依存しないように計算
-
native:Java以外の言語で記述されたメソッド(C/C++)
public final native void notify();
- オーバーヘッド存在、Java単独よりソースの管理が煩雑、などデメリットも
this
- 現在のオブジェクトを指す
- メソッド配下で暗黙的に利用できる変数
- 現在のオブジェクトに属するname/ageフィールドを参照
System.out.printf("%s(%d歳)です。\n", this.name, this.age);
- メソッドの参照
this.myMethod(…)
- thisを書くべきかどうか
- フィールドの場合同名のローカル変数と被った時に区別するためにthisを使う
- 一々ローカル変数があるかで判断しなくて済むよう全フィールドにはthisを付けるのがいいと思われる
- メソッドは現在のオブジェクトに属することを明記したい時thisを使う
メソッドのオーバーロード
- オーバーロード:名前は同じで引数の型/並びのみ異なるメソッドを複数定義すること
- 戻り値の型/引数の名前が異なる場合は不可
- 基本的に同じクラスに同名のフィールドが存在してはいけない
- しかしメソッドは**シグニチャ(名前、引数の型、並び)**で識別されるので、以下が異なる場合のみ許容される
- 引数の個数
- 引数のデータ型
- シグニチャ
-
int indexOf( String str, int index )
のシグニチャは indexOf( String , int )
-
- オーバーロード
public static int abs( int a )
public static float abs( float a )
- 片方のオーバーロードで引数の規定値のみ準備して大元のオーバーロードを呼び出す場合に使う
- 注意:引数の個数が同じで型のみ異なるオーバーロードは良くない
- オーバーロードは実行時ではなくコンパイル時に選択される
- 以下コード実行時にはforループの型である
CharSequence
のpublic void show(CharSequence cs) {
のみ実行される
- 以下コード実行時にはforループの型である
- オーバーロードは実行時ではなくコンパイル時に選択される
//型に応じて最適なオーバーロードを期待
//しかし結果は
//CharSequence:春はあけぼの
//CharSequence:夏は夜
//CharSequence:秋は夕暮れ
public class OverloadAnti {
public void show(String value) {
System.out.println("String: " + value);
}
public void show(StringBuilder builder) {
System.out.println("StringBuilder:" + builder);
}
public void show (StringBuffer buf) {
System.out.println("StringBuffer:" + buf);
}
public void show(CharSequence cs) {
System.out.println("CharSequence:" + cs);
}
}
public class OverloadAntiClient {
public static void main(String[] args) {
var c = new OverloadAnti();
var list = new CharSequence[] {
"春はあけぼの",
new StringBuilder("夏は夜"),
new StringBuffer("秋は夕暮れ"),
};
for (var cs : list) {
c.show(cs);
}
}
}
スコープ
- コードの中で変数の有効範囲
- 変数がどこから参照できるか決める
- 変数の宣言場所によって異なる
-
フィールドのスコープ
- class{…}直下で宣言
- クラス全体でアクセス可能
-
ローカル変数のスコープ
- メソッド定義ブロックで宣言
- メソッド内のみアクセス可能
-
ブロックスコープ
- ローカル変数の一種
- メソッド配下で宣言(if/while/forなど制御ブロック)
- ブロック内のみアクセス可能
-
フィールドのスコープ
フィールドとローカル変数の衝突
- メソッド内外で同名の変数を宣言した場合
- スコープの異なる変数(フィールド変数、ローカル変数)は名前が同じでも異なる!!
- 隠蔽されたフィールド変数にアクセスしたい場合thisを使う
Scop.java
//dataが被ってる
public class Scope {
//フィールド変数としてのdata
public String data = "フィールド";
public String show() {
//ローカル変数としてのdata
//これが宣言されたことでクラス全体で有効なはずのフィールド変数が一時的に隠蔽される
var data = "ローカル";
return data;
//隠蔽されたフィールド変数にアクセスしたい場合
// return this.data;
}
}
ScopeBasic.java
public class ScopeBasic {
public static void main(String[] args) {
var s = new Scope();
//showメソッドのローカル変数
System.out.println(s.show()); //ローカル
//ローカル変数はフィールド変数に影響しない
System.out.println(s.data); //フィールド
}
}
-
注:変数の有効範囲は宣言された位置からブロックの終端まで
- 変数は宣言された位置から有効
//NG例:str1は宣言された位置から有効
public class ScopeStrict {
String str2 = str1; //str1よりstr2を先に宣言できない
String str1 = “neko desu“;
}
-
メソッド/コンストラクターからの参照は例外
- 宣言位置に依らずクラス全体から参照できる
- メソッド/コンストラクタ以外(初期化ブロックなど)から参照は不可
public class ScopeStrict {
public void show() {
System.out.println(str); //neko desu
}
String str = “neko desu”;
}
StrictClient.java
public class StrictClient {
public static void main(String[] args) {
var s = new ScopeStrict();
s.show();
}
}
ブロックスコープ
- 制御構文(if/while/for/try など)で宣言された変数
- ローカル変数の一種なので、上位のローカル変数と同名のブロックスコープ変数は宣言不可
- ブロック変数の破棄後に同名ローカル変数を宣言することは可能
- 並列のブロックでブロックスコープ変数宣言も可能
public class ScopeBlock {
public static void main(String[] args) {
/*
// ローカル変数と同名のブロックスコープ変数を宣言
var data = "ローカルスコープ";
{
var data = "ブロックスコープ"; //エラー
}
*/
{
var data = "ブロックスコープ";
}
//この時点でブロックスコープ変数は破棄されている
var data = "ローカルスコープ"; //OK
System.out.println(data);
}
}
//並列のブロックスコープ
public class ScopeBlock {
public static void main(String[] args) {
{
var data = "ブロックスコープ";
System.out.println(data);
}
{
var data = "ブロックスコープ2";
System.out.println(data);
}
}
}