本日は「JavaとRubyの違い」について書いていきます。
メジャー言語の代表であるJavaもRubyと同じくオブジェクト指向言語ですが、大きく違うところが何点かあります。
今回は個人的に大きな違いだと思った4点を比較しながら書いていきます。
1.コンパイラ言語かインタプリタ言語の違い
・コンパイラ言語
全てのコードを機械語に翻訳してから実行する言語。
Javaはこちらに分類されます。
コンパイルという機械語への翻訳作業が必要。
実行速度が速い。
・インタプリタ言語
コードを実行する際に機械語に翻訳していく言語。
Rubyはこちらに分類されます。
実行速度が遅い。
記述が短い。
2.静的型付け言語か動的型付け言語の違い
・静的型付け言語
変数などのデータ型の宣言が必要。
Javaはこちらに分類。
・動的型付け言語
変数などのデータ型の宣言が不要。
Rubyはこちらに分類。
さらにRubyでは他言語にあるプリミティブ型がなく、全てがオブジェクト型である為、「Rubyは全てがオブジェクト」と言われる一因になっているようです。
これは型がないわけではなく、オブジェクト型の中でデータ型の分類をしているということです。
代表例として文字列型について取り上げると
Ruby→オブジェクト型のStringクラス
となっており
str = “文字列”
str = String.new(“文字列”)
上記のようにRubyの文字列は自動的にStringクラスのインスタンスを作成していることになります。
つまり、「全てがオブジェクト」とは「全てクラスで定義されている」とも言えます。
同じ動的型付け言語の中でも、PHPやJSにはプリミティブ型がある為、Rubyは動的言語の中でも特殊だと思います。
訂正:Javaの文字列型はプリミティブ型ではないです。
3.メソッドの引数について
・Javaは「.メソッド()」の「()」は省略不可
「メソッド呼び出し」か「変数へのアクセス」かを区別。
・Rubyは「.メソッド()」の「()」は省略可
「.」に続く呼び出しは「メソッドの呼び出し」。
他言語にあるような組み込み関数がなく、全てがメソッド。
→Rubyは全て「オブジェクト.メソッド(引数)」という形でオブジェクトにメソッドでアクセスしています。
「いや、putsみたいに組み込み関数のように使えているのもありますよね???」
と私も最初に思いました。しかし厳密にはputsも組み込み関数ではなくメソッドです。これについてはかなり長くなるので後々書きたいと思います。
4.privateについて
・Javaの「private」はクラス内部からのみアクセスが可能で、他のクラスからはアクセス不可
・Rubyの「private」は継承関係にある他のクラスからのアクセスや再定義が可能
Rubyのprivateは特殊です。
以下が例です。
class Parent
def public_method
puts "This is a public method in Parent"
end
def call_private_method
private_method #=>self.private_methodでも同じ
end
private
def private_method
puts "This is a private method in Parent"
end
end
class Child < Parent
def call_private_method_2
private_method #=>self.private_methodでも同じ
end
end
class Grandchild < Child
def call_private_method_3
private_method #=>self.private_methodでも同じ
end
def private_method
puts "Rubyのprivateメソッドは再定義するとpublicメソッドに変わります"
end
end
parent = Parent.new
parent.private_method #=> エラー
parent.public_method #=> This is a public method in Parent
parent.call_private_method #=> This is a private method in Parent
child = Child.new
child.private_method #=> エラー
child.call_private_method_2 #=> This is a private method in Parent
grandchild = Grandchild.new
grandchild.private_method #=> Rubyのprivateメソッドは再定義するとpublicメソッドに変わります
grandchild.call_private_method_3 #=> Rubyのprivateメソッドは再定義するとpublicメソッドに変わります
上記の通り、Rubyのprivateは以下の特徴があります。
・クラス外からの呼び出しは不可
・自クラス内と継承先のクラス内で呼び出し可能
・publicメソッドとして再定義可能
今回趣旨から外れるのでselfの省略については詳しく触れませんが、後日「⑤『オブジェクト.メソッド』の形での呼び出し」で書きたいと思います。
[補足]
Ruby2.7以降では
「privateが適用されたインスタンスメソッドを呼び出す際にselfをつけてもエラーにならない」ようです。
スクールのバージョンが2.6.5だったので、その際に検証した時にはselfをつけた場合にエラーが出ていたのでおかしいなと混乱してしまいました。
selfをつけれない場合、putsなどをあたかも組み込み関数のように使えるので前までは使えなかったのかなと勝手に想像しています。
[余談]
「puts」についてはまた後日書くつもりですが、ざっくり下記にまとめます。
class Sample
end
sample = Sample.new
sample.puts("練習練習")#=> `<main>': private method `puts' called for #<Sample:0x000000010d399c30> (NoMethodError)
となり、クラス外で呼び出すと「privateメソッドですよ」と出ます。
全てのクラスはObjectクラスをスーパークラスに持つ為、putsはObjectクラスのprivateメソッドとして定義されていてそれを継承しているんだなとここからわかります。
class Sample
def sample_method
self.puts("練習")
end
end
sample = Sample.new
sample.sample_method #=> 練習
実際このように呼び出せます。
ちなみにクラス外でも
puts "練習練習" #=> 練習練習
self.puts("練習練習") #=> 練習練習
このようにselfを使って呼び出せます。
ではこのselfは何を表しているのかという疑問が湧くのですが、これはmainというインスタンスになります。クラス外の部分をトップレベルと呼び、トップレベルのインスタンスはObjectクラスのインスタンスであるmainという風に決まっています。
mainは特殊な為、
main.puts("練習練習") #=> エラー
というように呼び出すことはできません。
ちなみに
Kernel.puts("練習練習") #=> 練習練習
でもputsは使えます。
つまり、今までを整理すると
Kernelモジュールのmodule_functionでputsは指定されていて、ObjectクラスはKernelモジュールをミックスインしている為、privateメソッドとして使える
[追記]
モジュール関数について公式リファレンスより
module_function はメソッドにプライベートメソッドとモジュールの特異メソッドの 2 つを同時に定義するメソッドです。
モジュール関数とは「Kernel.puts("練習練習")」のような形で使えるという認識しかなく、privateが適用されるという認識がなかったので実際にmodule_functionで指定したメソッドはprivateが適用されるかは以下で試しました。
module SampleModule
def sample_method
puts("module_functionなしならpublicメソッド")
end
end
class Sample
include SampleModule
def call_public_sample_method
sample_method
end
end
sample = Sample.new
sample.sample_method #=> module_functionなしならpublicメソッド
sample.call_public_sample_method #=> module_functionなしならpublicメソッド
module SampleModule
def sample_method
puts("module_functionありならprivateメソッド")
end
module_function :sample_method
end
class Sample
include SampleModule
def call_private_sample_method
sample_method
end
end
sample = Sample.new
sample.sample_method #=> エラー
sample.call_private_sample_method #=> module_functionありならprivateメソッド
これより、
module_functionなしならpublicメソッド
module_functionありならprivateメソッド
として、ミックスインされたモジュールは擬似継承されることがわかります。