プログラミングを始めてはや1年。
一応Androidアプリを作ったこともあって全く触れてないわけじゃないけど、オブジェクト指向ってなんやねんと思い続けている。
さすがに理解しておかないと今後つらいのでメモを作成しておく。
JavaとRubyで書きます
ここに書かれているのはプログラミング超初心者の筆者が調べてまとめたものなので、間違った表記・意味がたくさんあると思います。
間違っているところはご指摘頂けると嬉しいです。
ちょっとだけクラスについて
Mainクラスにメソッドをめっちゃいっぱい作っちゃった!! これもうわかんねえな!
class Main{
public static void main(String[] args){
hello();
sorry();
goodbye();
fine();
.
.
.
}
public static void hello(){
//処理文
}
public static void sorry(){
//処理文
}
.
.
.
}
↓
他にもクラスを作ってたくさんメソッドを書こう!
class Main{
public static void main(String[] args){
Person.hello();
}
}
class Person{
public static void hello(){
System.out.println("Hello World");
}
}
(Rubyでは)
class Person
#内容
end
すごーい!すっきりー!
オブジェクトってなに
現実世界の「モノ」を表している(ってよくいろんなとこに書いてある)
例えば、Otakuっていうオブジェクトがあるとしたら、
スペック(情報)
- 28歳
- 独身
- 彼女いない歴=年齢
- 童貞
- デブ
できること(振る舞い)
- PCを使える
- 部屋にひきこもれる
- アニメの話ができる
という感じで説明できる(偏見)
オブジェクトは別名、インスタンスという。
オブジェクト = インスタンス !
インスタンスを作るにはクラスが必要。
つまりクラスはインスタンスの設計図。(ってよくいろんなとこに書いてある)
それじゃあ otaku を定義しよう。簡単だ。
Otakuクラス(設計図)に、インスタンスの「スペック」「できること」を書けばいい。
Otakuを作ろう
class Main{
public static void main(String[] args){
Otaku otaku1 = new Otaku(); //➀ Otakuクラスのインスタンスをつくるぞ! インスタンスは変数に代入して使うよ!
//クラス型 変数名(インスタンス名) = new クラス名();
Otaku otaku2 = new Otaku();
Otaku otaku3 = new Otaku(); //➁ 同じクラス型からたくさんインスタンスを作れるよ! otakuがたくさんいるね!
//➃ インスタンス名.メソッド名() でOtakuのできることが使えるよ!
otaku1.usePC();
otaku1.specBody(); //➄specBodyメソッドで「僕はデブです!」って言いたい! インスタンスフィールドbodyの値("デブ")を使いたい!
}
}
class Otaku{
//➂ ここにはOtakuのスペック(情報)を定義するよ! 難しい言葉でインスタンスフィールドっていうらしい?けど変数宣言だ!(たぶん!)
public String age;
public String body;
//➂コンストラクタで値を代入!
Otaku(){
otaku1.age = "28歳";
otaku1.body = "デブ";
}
//➃ ここからOtakuのできること(振る舞い)をメソッドで表現するよ! インスタンスメソッドとも言うよ!
public void usePC(){
System.out.println("僕はパソコンの大先生なんだぞ!");
}
public void specBody(){
System.out.println("僕は" * this.body + "です!"); //➄ MainクラスでspecBodyメソッドが呼ばれた時に、thisをインスタンス名に置き換えるよ! これで「僕はデブです!」って言えるね!
}
}
(Rubyでのインスタンスメソッドの使い方)
class Otaku
def usePC #インスタンスメソッドの定義
puts "僕はパソコンの大先生なんだぞ!"
end
end
otaku = Otaku.new #インスタンス生成
otaku.usePC
publicとかstaticとか
public ・・・ クラス外からでも呼び出せる
static ・・・ インスタンスを作っていなくても呼び出せる
コンストラクタについてちょっと詳しく
コンストラクタとは、newを使ってインスタンス生成をした後に自動で呼び出される特別なメソッドのこと。
Rubyでの「initializeメソッド」と同義
インスタンスフィールドの値を設定するときにコンストラクタを使うのと使わないのじゃ、結構コードが変わってくるよ!
ちゃんと覚えよう!
コンストラクタなしver
class Main{
public static void main(String[] args){
Otaku otaku1 = new Otaku(); //➀ Otakuクラスのインスタンスをつくるぞ! インスタンスは変数に代入して使うよ!
//クラス型 変数名(インスタンス名) = new クラス名();
Otaku otaku2 = new Otaku();
Otaku otaku3 = new Otaku(); //➁ 同じクラス型からたくさんインスタンスを作れるよ! otakuがたくさんいるね!
otaku1.age = "28歳"; //➂各インスタンスにOtakuの細かい情報を入れていくよ! これじゃダメ人間だね!
otaku1.body = "デブ";
otaku1.usePC(); //➃ インスタンス名.メソッド名() でOtakuのできることが使えるよ!
otaku1.specBody(); //➄specBodyメソッドで「僕はデブです!」って言いたい! インスタンスフィールドbodyの値("デブ")を使いたい!
}
}
このコードの
otaku1.age = "28歳";
otaku1.body = "デブ";
のところで値を設定してるよ。
これだとインスタンスフィールドが増えてきたら大変だー! たくさんあってわかんないよー!
コンストラクタありver
class Main{
public static void main(String[] args){
Otaku otaku1 = new Otaku(); //➀ Otakuクラスのインスタンスをつくるぞ! インスタンスは変数に代入して使うよ!
//クラス型 変数名(インスタンス名) = new クラス名();
Otaku otaku2 = new Otaku();
Otaku otaku3 = new Otaku(); //➁ 同じクラス型からたくさんインスタンスを作れるよ! otakuがたくさんいるね!
//ないぞ!
otaku1.usePC(); //➃ インスタンス名.メソッド名() でOtakuのできることが使えるよ!
otaku1.specBody(); //➄specBodyメソッドで「僕はデブです!」って言いたい! インスタンスフィールドbodyの値("デブ")を使いたい!
}
}
class Otaku{
//➂ ここにはOtakuのスペック(情報)を定義するよ! 難しい言葉でインスタンスフィールドっていうらしい?けど変数宣言だ!(たぶん!)
public String age;
public String body;
//ここでコンストラクタを使うよ! new Otaku(); が呼ばれたときに必ず使われるメソッドだ!
Otaku(){
otaku1.age = "28歳"; //➂各インスタンスにOtakuの細かい情報を入れていくよ! これじゃダメ人間だね!
otaku1.body = "デブ";
}
//➃ ここからOtakuのできること(振る舞い)をメソッドで表現するよ! インスタンスメソッドとも言うよ!
public void usePC(){
System.out.println("僕はパソコンの大先生なんだぞ!");
}
public void specBody(){
System.out.println("僕は" * this.body + "です!"); //➄ MainクラスでspecBodyメソッドが呼ばれた時に、thisをインスタンス名に置き換えるよ! これで「僕はデブです!」って言えるね!
}
}
コンストラクタを書くときのルール!
- コンストラクタ名はクラス名と同じにする
- 返り値を書いてはいけない(voidもいらない)
また、インスタンス生成のときに引数で値を設定してコンストラクタに渡すこともできるよ!
Otaku otaku = new Otaku("デブ");
class Otaku{
public String body;
Otaku(String body){ //"デブ"が入る
this.body = body; //otaku.body = "デブ"; と同じ!
}
}
Rubyだとこうなる
class Otaku
def initialize(name) //インスタンス生成時に行いたい処理
@name = name #インスタンス変数(インスタンスの持つ情報(データ))
end
def info
puts "私は#{@name}です" #クラス内でのみインスタンス変数は利用可能
end
end
otaku = Otaku.new("デブ")
otaku.info
クラスフィールドとかクラスメソッドについて
そろそろ頭が追いついてないとこ。
クラスにも情報が持てるってことかな?
クラスにもメソッドが持てる。そもそも
public static void main(String[] args){
}
これもクラスメソッドだよね。
class Otaku{
static int count = 0; //クラス変数(全てのインスタンスで使える変数)
//インスタンスフィールド
public String age;
public String body;
//コンストラクタ
Otaku(){
Otaku.count++; //クラスフィールドにアクセス
}
}
Rubyでのクラスメソッドの書き方
class Otaku
@@count = 0 #クラス変数の定義
def initialize(name)
@name = name
@@count += 1
end
def Otaku.data #クラスメソッドの定義 self.クラスメソッドとしても可
puts "nameです"
end
end
Otaku.data #クラスメソッドの呼び出し
# 出力結果 nameです
カプセル化って...?
いやーきついっす
簡単に言うと、作った機能の内の安全な部分を公開して、使ってほしくない部分を制限(カプセル化)すること。
フィールドとメソッドへのアクセスを制限することでできる。
ワイ「クラス作ったやで!見てこれ!すごいじゃろ!他のクラスでも使ったええで!」
「public」をつける!
class Main(){
public static void main(String[] args){
Otaku otaku = new Otaku("wai"); //インスタンス生成
System.out.println(otaku.name); //publicに公開してるから使えるで!
}
}
class Otaku{
//インスタンスフィールド
public String name; //クラスの外部からアクセスできるように「public」をつける!
//コンストラクタ
Otaku(String name){
this.name = name;
}
}
ワイ「クラス作ったやで!見てこれ!でも他のクラスで使ったらバグ起こしそうだから使わせられんわ...」
「private」をつける!
class Main(){
public static void main(String[] args){
Otaku otaku = new Otaku(28); //インスタンス生成
System.out.println(otaku.age); //エラー!!! 使えません!
}
class Otaku{
//インスタンスフィールド
private int age; //外部からアクセスできないようにするために「private」をつける!
//コンストラクタ
Otaku(int age){
this.age = age; //同じクラス内なら使えるよ!
}
}
Rubyのメソッドは何も指定しない限りはpublicメソッドとなる。
privateの後に書いたメソッドはprivateメソッドとなり、クラス内でしか呼び出せなくなる
しかーし、
インスタンスフィールドをprivateにしても安全に値を頂きたいお客様のために、フィールドの返り値のみをご利用できる「ゲッター」というメソッドをご提供!
class Main{
public static void main(String[] args){
Otaku otaku = new Otaku("~","~","~");
System.out.println(otaku.getName());
}
}
class Otaku{
//インスタンスフィールド
~
private String name; //ここは「private」だけど、、、
~
//インスタンスメソッド
public String getName(){ //ここが「public」なので、クラス外からアクセス可能
return this.name; //フィールドの値を返す
}
}
Rubyでもインスタンス変数の値はクラス内でしか取得できないので、ゲッターを使ってクラス外から取得できる
class Otaku
attr_reader:name #ゲッター定義
def initialize(name)
@name = name
end
end
otaku = Otaku.new("ブス")
puts otaku.name
attr_readerでは↓と同義のことを行ってゲッターを定義している
def name
@name #戻り値(returnは省略)
end
反対に、外部からフィールドの値を変更するメソッド「セッター」もあります
class Main{
public static void main(String[] args){
Otaku otaku = new Otaku("~","~","~");
otaku.setName("washi"); //setNameメソッドに引数セット
System.out.println(otaku.getName());
//出力結果: washi
}
}
class Otaku{
~
private String name;
~
public void setName(String name){
this.name = name; //フィールドに値をセット
}
}
Rubyでのセッター定義
class Otaku
attr_writer:name #セッターの定義
def initialize(name)
@name = name
end
end
otaku = Otaku.new("ブス")
otaku.name = "かわいい" #セッターの呼び出し
puts otaku.name #出力結果 かわいい
attr_writerでは↓と同義のことを行ってセッターを定義している
def name=(value)
@name = value
end
Rubyでゲッターとセッターを同時に定義する時に「attr_accessor」を用いると両方を一度に定義できる
基本的には、
- フィールドはprivate
- メソッドはpublic
にすることで、変数はprivateに守られ、かつ、メソッドは他のクラスでもpublicに使えるので便利。
継承!?
なんかかっこいい。
同じような内容のコードってまとめたくなるよね。それはクラスの内容でも同じこと。
あるクラスの内容を別のクラスが「引き継ぐ」ことを継承っていう。
先輩「俺の特技は汎用性ヤバイぜ!超使える!」 (継承される特技(クラス):スーパークラス)
class Super{
public void setName(String name){
System.out.println(name);
}
}
後輩「先輩!それ使わせて!」 (継承してできる特技(クラス):サブクラス)
class Sub extends Super{ //Superクラスのインスタンスメソッドを継承している
}
class Main{
public static void main(String[] args){
Sub sub = new Sub();
sub.setName("ハイパーキネティックポジションリバーサー!!!"); //スーパークラスのインスタンスメソッドを呼び出す
}
}
Rubyではこうなる
class Super
def initialize(name)
@name = name
end
def info
puts @name
end
end
class Sub < Super
end
sub = Sub.new("ハイパーキネティックポジションリバーサー!!!") #newをすると親クラスのinitializeメソッドが実行される
sub.info #親クラスから継承しているのでinfoメソッドが使える
スーパークラスから継承したメソッドと同名のメソッドをサブクラスに定義すると、スーパークラスの内容を上書きすることができる。
これを「オーバーライド」という。
また、「private」がそのクラス内からのみアクセス可能だったのに対して、「protected」はそのクラス内とサブクラスからのみアクセス可能になる。
気づいたこと・注意点
- メソッドはクラスの中に定義する
- thisはクラス内のメソッドやインスタンスを指すときに使用する
- 変数の定義に値を代入しなかった場合、String型には「null」、int型には「0」、double型には「0.0」、boolean型には「false」が入る
- サブクラスのインスタンスはスーパークラスのメソッドも呼べるが、その逆はできない。
- クラス名のネタををオタクにしたのは完全に深夜テンションのせいです。
- ハイパーキネティックポジションリバーサーはLoLっていうゲームからとってきただけなので特に意味は無いです()