質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.36%

個々のインスタンスに番号を振りたいです。サブクラスの扱い方等、、

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 863

前提・実現したいこと

各インスタンスに格納される数値に番号をつけたいです。

色々な図形の大きさを設定して面積を求めるメソッドを含むサブクラスを作りました。それらを使って別のクラスに各図形の面積を表す文字列を乱数発生させてコンソールに表示させたいのです。その際に各図形の面積にNo.1... のように番号を振りたいです。

各図形の面積に関するサブクラスは

package object;

public class Circle1 extends Figure {
    private double radius = 0;

    Circle1(){
    this.radius = 20;
    }
    public Circle1() {
        // TODO 自動生成されたコンストラクター・スタブ
    }
    void Circle(double r){
        this.radius = r;
    }
    void setRadius(double r) {
    }
    void setSize(double r) {
        setRadius(r);
    }
    double getRadius() {
    return this.radius;
    }
    @Override
    double getArea() {
        area = Math.PI * this.radius * this.radius;
        return area;
        // TODO 自動生成されたメソッド・スタブ
    }
    void identify() {
        System.out.println("I am a Circle1 with area" + getArea() + "and" + getNumber() + ".");
        // TODO 自動生成されたメソッド・スタブ

    }
    private String getNumber() {
        // TODO 自動生成されたメソッド・スタブ
        return null;
    }
    @Override
    void iduntify() {
        // TODO 自動生成されたメソッド・スタブ

    }

}

と、同様にRectangle、Square、Triangleを作成しています。

複数のサブクラスに渡って番号をふることができません。

実行したいクラスのコードは以下のようです

エラーメッセージ
「暗黙的スーパー・コンストラクターFigure()は未定義です。別のコンストラクターを目地的によびだす必要があります。」
と表示されますが、どういうことなのかいまいちよくわかりません。

該当のソースコード

package object;

public class Figures{
    public static void main(String[] args) {
        Figure[] figures1 = new Figure[9];
        Figure[] figures2 = new Figure[9];
        Rectangle r1 = new Rectangle();
        Rectangle r2 = new Rectangle(30, 20);    
        int i = 0;

        System.out.println("The area of r1 is" + r1.getArea());
        System.out.println("The area of r2 is" + r2.getArea());

        r1.setWidth(40);
        r1.setHeight(30);
        System.out.println("The area of r1 is" + r1.getArea());

        r2.setSize(60,  40);
        System.out.println("The area of r2 is" + r2.getArea());

        figures1[i++] = r1;
        figures1[i++] = r2;

        Circle1 c1 = new Circle1();
        Circle1 c2 = new Circle1(20);
        figures1[i++] = c1;
        figures1[i++] = c2;
        System.out.println("The area of c1 is" + c1.getArea());
        System.out.println("The area of c2 is" + c2.getArea());

        Triangle t1 = new Triangle(3, 5);
        Triangle t2 = new Triangle(30, 20);
        Triangle t3 = new Triangle(300, 200);
        System.out.println("The area of t1 is" + t1.getArea());
        System.out.println("The area of t2 is" + t2.getArea());
        System.out.println("The area of t3 is" + t3.getArea());

        figures1[i++] = t1;
        figures1[i++] = t2;
        figures1[i++] = t3;

        Square2 s1 = new Square2();
        Square2 s2 = new Square2(20);
        System.out.println("The area of s1 is " + s1.getArea());
        System.out.println("The area of s2 is " + s2.getArea());

        figures1[i++] = s1;
        figures1[i++] = s2;

        System.out.println();
        for(int j=0; j<figures1.length; j++) {
            figures1[j].iduntify();
        }

        System.out.println();
        i = 0;
        for (int j=0; j<figures2.length; j++) {
            figures2[j] = figures1[choose()];
        }
        for (int j=0; j<figures2.length; j++) {
            figures2[j].iduntify();
        }
    }
    static int choose() {
        int x = (int)(Math.random()*9);
        return x;
    }


}

試したこと

スーパークラスに

package object;

public abstract class Figure {
    double area = 0;
    abstract double getArea();
    abstract void iduntify();
    void identify() {
        // TODO 自動生成されたメソッド・スタブ
    }
    public static void main(String[] args) {
        int[] array = new int[10];
        for(int i=0;i<=array.length;i++) {
            array[i]=i+1;
        }
    }
}

というコードを書いてみました。

補足情報(FW/ツールのバージョンなど)

初心者なので用語の正しい定義を理解していない部分があるかと思います。いくつもクラスが分かれてしまって自分でもよくわからなくなってしまったので、同じようなコードを作成したことがある方がいらっしゃいましたら何かアドバイスがいただけたら幸いです、、、

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • BeatStar

    2021/01/05 20:49

    Circleのコンストラクタ( int i を引数にとっている方 ) 必要ですかね?
    引数使っていないんですが…

    キャンセル

  • shimajiro1917

    2021/01/05 21:51

    何かのエラーメッセージにしたがって何度も直していたらそうなっていたようです!
    (int i)は不要ですね、ありがとうございます。

    キャンセル

  • BeatStar

    2021/01/06 16:56

    あと、修正してください。
    修正時に "<コード>" (あるいは "<code>" となっている) のボタンを押して、その中に書いてください。
    このままだと、インデントが無視されるので、非常に読みづらいです。
    読む気も失せます。

    キャンセル

  • shimajiro1917

    2021/01/06 21:48

    すみません、初めてこのサイトを利用したので書き方がわからず読みづらい投稿をしてしまいました。
    修正しました。

    キャンセル

回答 1

checkベストアンサー

+1

色々な考え方、作り方があるかと思いますが、Figureクラスを継承したクラスのインスタンスごとに一意なID(すなわちインスタンス番号)を振りたいとすると、ベースとしたFigureクラスで一意の番号を生成するクラスのstaticフィールドを用意し、Figureクラスを継承したクラスのインスタンス生成時にそのメソッドで呼び出し、実際の値を割り当てる、という考え方で実装することができます。

インスタンス番号を生成するものとしては、単純に1から始めてインスタンス生成時に+1していくようなクラスを用意すれば良い訳ですが、雑に作るとマルチスレッド、並列プログラミングのような場合に正しくインスタンス番号を生成できないことがあります。勉強の為の習作であればそれでも良いでしょうか、質問者さんの後の質問
stackとqueueの実行エラーについて - teratail#314536
などでは既に java.util.concurrent.atomic.AtomicInteger を使おうと言う意思があるので、こちらが適切でしょう。本回答でもそれで例を示します。

まず、Figureクラスを継承したクラスのインスタンス全体として一意とするとために、staticフィールドとしてAtomicIntegerを追加します。FigureクラスではJavaの構文である「初期化子(initializer)」を利用して、個々のインスタンス生成時にaddAndGet()メソッドで更新した値をそのinstanceNumberフィールドにセットします。初期化子を使うことでFigureクラスを継承したクラスでは特にコンストラクタ内で改めて初期化せずとも、自動的にinstanceNumberフィールドが初期化されることとなり、好都合です。

// Figure.java
package object;

import java.util.concurrent.atomic.AtomicInteger;

abstract class Figure {
    // Figureクラスを継承したクラスのインスタンスで一意の番号(インスタンス番号)
    // とする為、クラスフィールドにする。
    private static final AtomicInteger counter = new AtomicInteger(0);

    // 個々のインスタンスの番号
    private final int instanceNumber;

    // 初期化子(initializer)で初期化する。
    {
        instanceNumber = counter.addAndGet(1);
    }

    double area = 0;

    abstract double getArea();
    abstract void identify();

    public int getNumber() {
        return this.instanceNumber;
    }
}


上記例では初期化子を使わずともprivate final int instanceNumber = counter.addAndGet(1);でも大丈夫です。初期化子では{}内でコンストラクタのように複数の処理を記述できるので、適時、使い分けてください。

次に、抽象クラスであるFigureを継承したRectangleCircle1クラスを示します。ソースコードを簡単にするために Main.java内に一緒に定義します。

// Main.java
package object;

class Rectangle extends Figure {
    private double height = 0;
    private double width = 0;

    Rectangle(){
        this.width = 20;
        this.height = 10;
    }

    Rectangle(double width, double height){
        this.width = width;
        this.height = height;
    }

    @Override
    double getArea() {
        return width * height;
    }

    @Override
    void identify() {
        System.out.println("I am a Rectangle(instance number=" + getNumber() + ") with area " + getArea() + ".");
    }
}

class Circle1 extends Figure {

    private double radius = 0;

    Circle1() {
        // this.radius = 20;
        // オーバーロード版 Circle1(double r)を呼ぶことも可能
        this(20);
    }

    Circle1(double r){
        this.radius = r;
    }

    @Override
    double getArea() {
        area = Math.PI * this.radius * this.radius;
        return area;
    }

    @Override
    void identify() {
        System.out.printf("I am a Circle(instance number=%d) with area %f.\n", getNumber(), getArea());
    }
}

public class Main {
    public static void main(String[] args) {

        Figure[] figures1 = new Figure[4];
        int i = 0;

        Rectangle r1 = new Rectangle();
        Rectangle r2 = new Rectangle(40, 30);
        System.out.println("The area of r1 is " + r1.getArea());
        System.out.println("The area of r2 is " + r2.getArea());
        figures1[i++] = r1;
        figures1[i++] = r2;

        Circle1 c1 = new Circle1();
        Circle1 c2 = new Circle1(30);
        System.out.println("The area of c1 is " + c1.getArea());
        System.out.println("The area of c2 is " + c2.getArea());
        figures1[i++] = c1;
        figures1[i++] = c2;

        for (int j = 0; j < figures1.length; j++) {
            figures1[j].identify();
        }
    }
}

これをWindowsのコマンドプロンプト上で実行すると、以下のようになります。インスタンス番号が1から始まり、RectangleCircle1のそれぞれのインスタンスに割り当てられていることが分かります。実行例はJava SE 11ですが、Java SE 8でも同様の結果となります。

C>java -version
java version "11.0.9" 2020-10-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.9+7-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.9+7-LTS, mixed mode)

C>javac object\Main.java

C>java  object.Main
The area of r1 is 200.0
The area of r2 is 1200.0
The area of c1 is 1256.6370614359173
The area of c2 is 2827.4333882308138
I am a Rectangle(instance number=1) with area 200.0.
I am a Rectangle(instance number=2) with area 1200.0.
I am a Circle(instance number=3) with area 1256.637061.
I am a Circle(instance number=4) with area 2827.433388.

C>

一応指摘しておきますと、インスタンス番号の更新に使うAtomicIntegerクラスのaddAndGet(1)は単純に+1するだけなので、intの最大値である0x7fffffffを越えると桁あふれを起こして値が正負と共にでんぐり返ります。コードが勉強の為の習作であるならば特に問題にはならないはずですが、もしインスタンス番号をファイルに保存するなどして永続化を計るような製品のコードの場合は更に検討が必要になるはずなので、将来の為に頭に留め置くと良いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/08 22:43

    とてもご丁寧にありがとうございます。親クラスのシンプルなコードで動いて感動しました、、とても勉強になりました。dodox86さんのようなコードが書けるようにがんばります!
    長々と質問にお付き合いいただきありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る