0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rubyは全てがオブジェクト「①JavaとRubyの違い」

Last updated at Posted at 2023-04-12

本日は「JavaとRubyの違い」について書いていきます。

メジャー言語の代表であるJavaもRubyと同じくオブジェクト指向言語ですが、大きく違うところが何点かあります。
今回は個人的に大きな違いだと思った4点を比較しながら書いていきます。

1.コンパイラ言語かインタプリタ言語の違い

・コンパイラ言語
全てのコードを機械語に翻訳してから実行する言語。
Javaはこちらに分類されます。
コンパイルという機械語への翻訳作業が必要。
実行速度が速い。

・インタプリタ言語
コードを実行する際に機械語に翻訳していく言語。
Rubyはこちらに分類されます。
実行速度が遅い。
記述が短い。

2.静的型付け言語か動的型付け言語の違い

・静的型付け言語
変数などのデータ型の宣言が必要。
Javaはこちらに分類。

・動的型付け言語
変数などのデータ型の宣言が不要。
Rubyはこちらに分類。
さらにRubyでは他言語にあるプリミティブ型がなく、全てがオブジェクト型である為、「Rubyは全てがオブジェクト」と言われる一因になっているようです。
これは型がないわけではなく、オブジェクト型の中でデータ型の分類をしているということです。

代表例として文字列型について取り上げると
 Ruby→オブジェクト型のStringクラス
となっており

qiita.rb
str = “文字列”
str = String.new(“文字列”)

上記のようにRubyの文字列は自動的にStringクラスのインスタンスを作成していることになります。
つまり、「全てがオブジェクト」とは「全てクラスで定義されている」とも言えます。

同じ動的型付け言語の中でも、PHPやJSにはプリミティブ型がある為、Rubyは動的言語の中でも特殊だと思います。
訂正:Javaの文字列型はプリミティブ型ではないです。

3.メソッドの引数について

・Javaは「.メソッド()」の「()」は省略不可
「メソッド呼び出し」か「変数へのアクセス」かを区別。

・Rubyは「.メソッド()」の「()」は省略可
「.」に続く呼び出しは「メソッドの呼び出し」。

他言語にあるような組み込み関数がなく、全てがメソッド。
→Rubyは全て「オブジェクト.メソッド(引数)」という形でオブジェクトにメソッドでアクセスしています。

「いや、putsみたいに組み込み関数のように使えているのもありますよね???」

と私も最初に思いました。しかし厳密にはputsも組み込み関数ではなくメソッドです。これについてはかなり長くなるので後々書きたいと思います。

4.privateについて

・Javaの「private」はクラス内部からのみアクセスが可能で、他のクラスからはアクセス不可

・Rubyの「private」は継承関係にある他のクラスからのアクセスや再定義が可能

Rubyのprivateは特殊です。
以下が例です。

qiita.rb
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」についてはまた後日書くつもりですが、ざっくり下記にまとめます。

qiita.rb
class Sample
end

sample = Sample.new
sample.puts("練習練習")#=> `<main>': private method `puts' called for #<Sample:0x000000010d399c30> (NoMethodError)

となり、クラス外で呼び出すと「privateメソッドですよ」と出ます。
全てのクラスはObjectクラスをスーパークラスに持つ為、putsはObjectクラスのprivateメソッドとして定義されていてそれを継承しているんだなとここからわかります。

qiita.rb
class Sample
  def sample_method
    self.puts("練習")
  end
end

sample = Sample.new
sample.sample_method #=> 練習

実際このように呼び出せます。
ちなみにクラス外でも

qiita.rb
puts "練習練習" #=> 練習練習
self.puts("練習練習") #=> 練習練習

このようにselfを使って呼び出せます。
ではこのselfは何を表しているのかという疑問が湧くのですが、これはmainというインスタンスになります。クラス外の部分をトップレベルと呼び、トップレベルのインスタンスはObjectクラスのインスタンスであるmainという風に決まっています。
mainは特殊な為、

qiita.rb
main.puts("練習練習") #=> エラー

というように呼び出すことはできません。
ちなみに

qiita.rb
Kernel.puts("練習練習") #=> 練習練習

でもputsは使えます。

つまり、今までを整理すると

Kernelモジュールのmodule_functionでputsは指定されていて、ObjectクラスはKernelモジュールをミックスインしている為、privateメソッドとして使える

[追記]
モジュール関数について公式リファレンスより
module_function はメソッドにプライベートメソッドとモジュールの特異メソッドの 2 つを同時に定義するメソッドです。

モジュール関数とは「Kernel.puts("練習練習")」のような形で使えるという認識しかなく、privateが適用されるという認識がなかったので実際にmodule_functionで指定したメソッドはprivateが適用されるかは以下で試しました。

qiita.rb
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メソッド
qiita.rb
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メソッド
として、ミックスインされたモジュールは擬似継承されることがわかります。

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?