はじめに
前回に「webプログラミングに興味あるので勉強します」という記事を書きましたが、今回はなんとJavaです
大学の授業でJavaを2年以上も学んでいましたが、実は全然理解できてなかったので必要なところだけをノート代わりとしてまとめました。
今回の記事にオブジェクト指向についても書いていますが、これはPHPやJavaScriptのオブジェクト指向の理解にも繋がるので重要だと思っています。
では、宜しく御願い致します
クラスの宣言
クラスとは、プログラムの実行に必要な処理をまとめたものです。単語の先頭と区切り文字を大文字で名詞で記載します。
実行処理の部分にはそのクラスの状態と振る舞いを定義します。
書き方は以下の通りですね。
class クラス名 {
実行処理...
}
Javaでは1ファイル1クラスが原則となっています。以下で、1つのファイルに複数classがあるような書き方をしていますが、実際にコードを書く場合には分けてください。(Why only 1 public class in Java file)
メンバ変数(フィールド)について
メンバ変数とはクラスの状態を定義したもので、基本型、クラス型、配列型の変数が宣言できます。
メンバ変数の宣言順序は、修飾子 型 変数名
です。
基本型 : int id;
クラス型 : Test a = new Test;
配列型 : int a[];
or int[] a;
メンバ変数には、クラス変数とインスタンス変数があります。クラス変数は型の前にstatic
をつけたもの。インスタンス変数はstatic
がついていない変数です。
public class Test{
int id = 1; //メンバ変数(インスタンス変数)
static int value = 200; //メンバ変数(クラス変数)
void student(){ //これはメソッド
System.out.println(id);
System.out.println(value);
}
}
また、メンバ変数は、そのクラスの状態を参照しようとするどのメソッド、コンストラクタからでも参照可能です。
しかし、各メソッド、コンストラクタの状態を定義する変数であるローカル変数では、それぞれのメソッド、コンストラクタ内からしか参照できません。
public class Student{
int grade = 1; // メンバ変数
void student1(){
int id_1 = 7; // ローカル変数
System.out.println(grade); // メンバ変数なので参照可能
System.out.println(id_1); // student1内に宣言したローカル変数なので参照可能
System.out.println(id_2); // student2内に宣言したローカル変数なので参照不可×
}
void student2(){
int id_2 = 1000;
System.out.println(grade); // メンバ変数なので参照可能
System.out.println(id_1); // student1内に宣言したローカル変数なので参照不可×
}
}
メソッド
メソッドとは、クラス内の振る舞いを定義したものです。以下のフォーマットで構成されています。
修飾子 戻り値のデータ型 メソッド名 (引数型 引数名....){
メソッド本体
}
①戻り値のデータ型
戻り値とは、メソッドの呼び出し元に返す値のことで、何の値も返さない(戻り値がない)場合はvoid型で記載します。以下に例を書きます。
public class Return {
public static void print() { // void型なので戻り値を返さない
System.out.println("It all returns to nothing");
}
public static int add(int x) {
int result = x + 1999;
return result; // return文でresultの値を返す。
}
public static void main(String[] args) {
int result = add(1); // 分かりやすくするためにreturnによって戻される値と同じ型で変数を指定
print(); // 「It all returns to nothing」と出力
System.out.println(result); // 「2000」と出力
}
}
②引数
メソッド内に値を引き継ぐ必要がある場合に引数を記載します。書き方は(引数型 仮引数名....)
引数型は引き継ぐ値の型、仮引数名はメソッドの中でのみ参照できる変数名を表します。引き継ぐ値がない場合は()のみです。
引数を持つメソッドの読み出し方は、メソッド名(値1,値2,...);
であり、読み出されると仮引数から実引数という名前に変わります。
public class Argument {
public static void main(String[] args){
rabbithouse("香風 智乃"); // ←実引数
rabbithouse("保登 心愛");
rabbithouse("天々座 理世");
amausaan("宇治松 千夜");
fleur_du_lapin("桐間 紗路");
}
public static void rabbithouse(String name){ // ←仮引数
System.out.println("ラビットハウス:"+ name);
}
public static void amausaan(String name){
System.out.println("甘兎庵:" + name);
}
public static void fleur_du_lapin(String name){
System.out.println("フルール・ド・ラパン:" + name);
}
}
実行結果はこのようになります。
ラビットハウス:香風 智乃
ラビットハウス:保登 心愛
ラビットハウス:天々座 理世
甘兎庵:宇治松 千夜
フルール・ド・ラパン:桐間 紗路
修飾子
Javaの修飾子には以下のような種類があります。(かなり割愛してます)
①アクセス修飾子
public
: 制限はなく、どこからでも参照可能
protected
: 同一クラス、同一パッケージ内、またはそのサブクラスからのみアクセス可能
private
: 同一クラスからのみ参照することが可能。カプセル化に習うため、メンバ変数は"private"になることが多い。
なし
: パッケージプライベートと言う。アクセス修飾子を省略した状態で、パッケージ内部からのみ自由にアクセスできる。
②static
クラス変数であることを表します。クラスをインスタンス化しなくてもアクセスできるようなるので、クラス名.メンバー名
でアクセスが可能です。
③final
クラスに付けて宣言を行うと、クラスを継承することができなくなります。
またメソッドに付けると、サブクラスでメソッドをオーバーライドできなくなります。
インスタンスとオブジェクトについて
ここから、オブジェクト指向について触れていきます。
イメージとしてクラスは設計図、オブジェクトは物体(人間とか車など)、インスタンスは設計図を基に作られた実体だと思っていてください。。。
インスタンスは以下のフォーマットで生成されます。
クラス名 変数名 = new クラス名(引数);
インスタンスの参照方法は以下の2つです。
変数名.メンバ変数名;
変数名.メソッド名;
6月8日更新
Javaでは全てのメンバ変数(フィールド)、メソッド名はすべて小文字、複合文字の場合は区切りを大文字する命名規則があるそうです。キャメルケースと言うそうですが、これが一般的な記述法だとコメント頂きました。。!
以下では変数名を「A」などと置いてますが、一般的ではないので補完して頂くと幸いです、、、
以下に例を書きます。
class Instance {
String name = "白露型駆逐艦『夕立』"; //メンバ変数
void shipType(){ //メソッド
System.out.println("駆逐艦");
}
}
class MainClass{
public static void main(String[] args) {
Instance A = new Instance();
System.out.println(A.name); // ここで「白露型駆逐艦『夕立』」と出力
A.shipType(); // ここで「駆逐艦」と出力
}
}
staticと非static
上のメンバ変数(フィールド)や修飾子の所でも少し触れましたが、ここではより詳しく説明していきます。
staticのついたメソッドや変数の事を、staticメソッド
・静的メソッド
・クラスメソッド
・クラス変数
など参考書やネットでは多様な言い方をします。
ごちゃごちゃにならないように
逆に、staticのつかないメソッドや変数のことを、インスタンスメソッド
・非staticメソッド
・インスタンス変数
と言います。
staticメソッド
staticメソッドはクラスが持つメソッドであるため、newを使ってインスタンスを生成しなくても他のstaticメソッドやインスタンスメソッド、別クラスでも呼び出すことが可能です。
しかし、自クラス内での呼び出す際はメソッド名();
で良いですが、別クラスで呼び出す際にはクラス名.メソッド名();
でないといけません。
また、staticメソッドはそのクラスで共有して使われることになります。よってどこで呼び出しても変わらない処理となるため、設計上で共通の処理やデータがある場合にはstaticメソッドが良いです。
インスタンスメソッド
new演算子を使ってインスタンス化されたオブジェクトごとに識別されるメソッドです。よって、必ずインスタンスを生成して呼び出す必要があります。
まとめ
class Method1 {
// staticメソッド・静的メソッド・クラスメソッド
static void staticMethod1() {
// instanceMethod(); これはダメ! staticメソッドから、(同一クラス内の)インスタンスメソッドへの(直接の)アクセスはできない。
Method1 a = new Method1(); // クラスのインスタンスを生成
a.instanceMethod(); // インスタンスを介した間接的なアクセスでインスタンスメソッドにアクセスできる。
}
// staticメソッド・静的メソッド
static void staticMethod1_1() {
staticMethod1(); // 自クラス内からの呼び出しなのでクラス名はいらない。
Method1.staticMethod1(); // これでも呼び出せる。
}
// インスタンスメソッド・非staticメソッド
void instanceMethod() {
staticMethod1(); // インスタンスメソッドからstaticメソッドの呼び出し(アクセス)もクラス名なしでok
Method1.staticMethod1(); // これでも呼び出せる。
}
}
// 別クラス
class Method2 {
static void staticMethod2() {
// staticMethod1(); これはだめ!
Method1.staticMethod1(); // 別クラスから呼び出すときは、クラス名.staticメソッド名
// instanceMethod(); これはダメ!
Method1 b = new Method1(); // 別クラスのインスタンスメソッドにアクセスする時も、インスタンスを介してインスタンスメソッドにアクセス
b.instanceMethod();
Method2 c = new Method2(); // 自クラス内のインスタンスメソッドへのアクセスも同じ。
c.instanceMethod2();
}
void instanceMethod2() {
Method1.staticMethod1_1(); // インスタンスメソッドから別のクラスのstaticメソッドの呼び出しの際は、クラス名が必要!
staticMethod2();
Method3.staticMethod3();
}
}
class Method3 extends Method1{
static void staticMethod3() {
staticMethod1(); // 継承するとクラス名不要で呼び出せる
//instanceMethod(); 継承でもこれはダメ。必ずクラスのインスタンスを生成し、それを介してアクセス
Method1 d = new Method1();
d.instanceMethod();
}
void instanceMethod3() {
staticMethod1();
}
}
コンストラクタ
コンストラクタとは、クラスのインスタンスを作成するときに実行されるもので、メンバ変数の値を自分で決めて初期化できる処理です。
コンストラクタの呼び出しは、クラス名 変数名 = new クラス名(引数);
でインスタンスを生成したときと同名のクラス名を持つメソッドがコンストラクタです。
つまり、クラス名 変数名 = new コンストラクタ名(引数)
とも表せます。
引数なしのコンストラクタ(デフォルトコンストラクタ)の例
public class Constructor1{
String name = "青山 ブルーマウンテン";
public Constructor1(){
System.out.println(name);
}
}
class Main{
public static void main(String[] args) {
Constructor1 cs = new Constructor1();
}
}
実行結果は以下のようになります。
青山 ブルーマウンテン
引数ありのコンストラクタの例
public class Constructor2{
public Constructor2(String str){
System.out.println(str);
}
}
class Main{
public static void main(String[] args){
Constructor2 A = new Constructor2("Hello");
}
}
実行結果は以下のようになります。
Hello
thisについて
①自分自身のインスタンス変数、インスタンスメソッドを指すthis
メンバ変数(フィールド)とローカル変数の変数名が同じである時にthis
を使います。
これを付けないと、メソッド内で定義したローカル変数の方が優先されてしまうので、メンバ変数(フィールド)を参照されなくなります。
class ThisClass{
private int number;
public void setNumber(int number){ //ローカル変数(引数)numberの値をメンバ変数(フォールド)のnumberに代入している
this.number = number + 100;
}
public int getNumber(){
return this.number;
}
}
class Main{
public static void main(String[] args) {
ThisClass A = new ThisClass();
A.setNumber(1);
System.out.println(A.getNumber()); // 101と出力される。
}
}
上の見出し「メンバ変数(フィールド)について」で書かれたStudentクラスと比較した時、メンバ変数(フィールド)とローカル変数の変数名が同じであるか否かで、this
を付けるか付けないかを判断してください。
②コンストラクタから、別のコンストラクタを呼び出すthis()
共通の処理を一方のコンストラクタのみに記載し、別のコンストラクタからはその処理を呼び出したい時にthis()
を使います。①で書いたものとはまた別物です。
class ThisConstructor {
private String ShopName;
private String CharacterName;
public ThisConstructor(String shopName , String CharacterName){
this.ShopName = shopName;
this.CharacterName = CharacterName;
}
// デフォルト値の設定
public ThisConstructor(){
this("ラビットハウス" , "香風 智乃");
}
// フィールドの初期化
public void print(){
System.out.println(ShopName+" : "+CharacterName);
}
}
class Main{
public static void main(String[] args) {
ThisConstructor tc1 = new ThisConstructor();
tc1.print();
ThisConstructor tc2 = new ThisConstructor("ラビットハウス" , "天々座 理世");
tc2.print();
}
}