47542


Transformerという抽象クラスを作り、それを継承するDecepticonクラスとAutobotクラスを作りました。その際、下記のコードのようにTransformer抽象クラスに作ったフィールドをDecepticonクラスとAutobotクラスのコンストラクタ内でthisキーワードを使って各々のフィールドにセットできました。しかし、thisキーワードをsuperに置き換えても上手くいきました。  
superにすると、Transformer抽象クラスのフィールドの値を書き換えているように思ったのですが、これはなぜでしょうか？  
よろしくお願いいたします。

[code]

    public abstract class Transformer {
    
      public int Strength;
      public int Intelligence;
      public int Speed;
      public int Endurance;
      public int Rank;
      public int Courage;
      public int Firepower;
      public int Skill;
    
      public abstract int calcOverall();
    
    }
    
[/code]

  

[code]

    public class Decepticon extends Transformer {
    
      Decepticon(int Strength, int Intelligence, int Speed, int Endurance, int Rank, int Courage, int Firepower, int Skill) {
        this.Strength = Strength;
        this.Intelligence = Intelligence;
        this.Speed = Speed;
        this.Endurance = Endurance;
        this.Rank = Rank;
        this.Courage = Courage;
        this.Firepower = Firepower;
        this.Skill = Skill;
      }
    
      @Override
      public int calcOverall() {
        int result = Strength + Intelligence + Speed + Endurance + Firepower;
        return result;
        }
      }
    
[/code]

  

[code]

    public class Soundwave extends Decepticon {
    
        Soundwave(int Strength, int Intelligence, int Speed, int Endurance, int Rank, int Courage, int Firepower, int Skill) {
          super(Strength, Intelligence, Speed, Endurance, Rank, Courage, Firepower, Skill);
        }
    
    }
    
[/code]


CC BY-SA 4.0
2018-08-15T08:37:45.443
47539
2018-08-23T03:21:02.473
28763
question
java
superキーワードとthisキーワードの違いについて


一般にクラス`A`をクラス`B`が継承するとき、単に同名のメソッドやフィールドを持つというよりは、クラス`B`がクラス`A`の **一種**
であることを示唆します。言い換えると、クラス`B`はクラス`A`と見なすこともできるということです。  
卑近な例を持ち出しますと、"動物"抽象クラスがあるとして、"犬"クラスはそれを継承するクラスとして定義できるでしょう。なぜなら"犬"は"動物"の一種であるからです。

今`Transformer`でいくつかのフィールドを定義しましたが、`Decepticon`や`Soundwave`でもそれらのフィールドが使えるのは、これらのクラスが`Transformer`の一種であるからです。あくまで`Transformer`固有の性質としてそれらのフィールドを持っているわけです。

それゆえ、`Transformer`の`Strength`、`Decepticon`の`Strength`という風に別々に管理されることはありません。それらは同じものを別の側面（それぞれのクラス）から見ているに過ぎないのです。

継承元と継承先のフィールドが「同じ」というのは次のようなコードを考えるとわかりやすいかもしれません。`B`側で設定した値が`A`側でも見えています。

[code]

    abstract class A {
        int field;
    }
    
    class B extends A {
        B(int f) {
            this.field = f;
        }
    }
    
    class Main {
        public static void main(String[] args) {
            B b = new B(42);
            System.out.println(b.field);
            // -> 42
            A a = b; // BをAとみなす
            System.out.println(a.field);
            // -> 42
        }
    }
    
[/code]


CC BY-SA 4.0
2018-08-15T10:01:55.783
47542
2018-08-15T10:01:55.783
13199
47539
answer


次のようにイメージすると分かりやすいのではないかと思います:

  * `this`: **自分から** 探し始める。無ければ順に継承元を辿っていく。
  * `super`: **親から** 探し始める。無ければ順に継承元を辿っていく。

* * *

例えば`Decepticon`インスタンス内で `this.Strength`と指定した場合、

  1. 自分、すなわち `Decepticon`で定義された`Strength`フィールドを探す 
    * 無いので親(`Transformer`)へ
  2. `Transformer`で定義された`Strength`フィールドを探す 
    * 存在するので`this.Strength`が指すのはこれである

という探索を行うイメージです。

一方`Decepticon`インスタンス内で `super.Strength`と指定した場合は、

  1. 親、すなわち`Transformer`で定義された`Strength`フィールドを探す 
    * 存在するので`super.Strength`が指すのはこれである

というイメージになります。

**結果として、今回の場合では** `this.Strength`, `super.Strength`ともに同じく "
_`Transformer`で定義された`Strength`フィールド_" を指すことになります。

* * *

次のような場合だと、`this`, `super`の指すものが変わります。

`Child.java`:

[code]

    abstract class Parent {
    
        // ↓をコメントアウトすると super.text を指すものがないのでコンパイルエラー
        public String text = "PARENT";
    
    }
    
    public class Child extends Parent {
    
        // ↓のコメントアウトを外すと this.text と super.text の指すものが変わります
        // public String text = "CHILD";
    
        private void exec() {
    
            System.out.println(this.text);
            System.out.println(super.text);
    
            super.text = "MODIFIED!!!";
            System.out.println("----");
    
            System.out.println(this.text);
            System.out.println(super.text);
        }
    
        public static void main(String[] args) {
            new Child().exec();
        }
    }
    
[/code]

* * *

英語になりますが、次の公式チュートリアルが今回の事象についてまさに説明している箇所です:

  * The Java™ Tutorials 
    * [Inheritance](https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html)
    * [Hiding Fields](https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html)
    * [Using the Keyword super](https://docs.oracle.com/javase/tutorial/java/IandI/super.html)


CC BY-SA 4.0
2018-08-23T03:14:15.250
47746
2018-08-23T03:21:02.473
2018-08-23T03:21:02.473
2808
2808
47539
answer