QA@IT

java:Listインターフェースのメソッド実装についての質問です。

8756 PV

Javaのプログラムについての質問です。長くなってしまいますがご容赦下さい。
Listインターフェースの実装クラスの自作と、作成したクラスの全メソッドを呼び出すサンプルを作成せよ、という問題です。以下が現在までに作成したコードになります。

注意点として、java.util.Listの実装クラスは使用出来ません(ArrayListなど)。実装するメソッドは、コードの中にコメントを振ってあります。

import java.util.List;
import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;

// 何故かジェネリクス表記がプレビューで付けられていませんが、
MyListとListの後に表記があります。
class Mylist implements List{

  private int Count;
  private String Data[];

  // コンストラクタ
  public Mylist(){
   Data = new String[10];
   Count = 0;
  }

/**

  • 実装するaddメソッド
  • @return boolean APIの設定に従う
  • @param e エレメント(要素) **/

  public boolean add(E e){
   Data[Count] = (String)e;

  Count++;
  return true;
  }

  public void add(int i,Object str){
  }

  public boolean addAll(Collection c){
    return false;
  }

  public boolean addAll(int i,Collection c){
    return false;
  }

/**

  • 実装するclearメソッド **/

  public void clear(){
    Count = 0;
  }

  public boolean contains(Object str){
    return false;
  }

  public boolean containsAll(Collection c){
    return false;
  }

  public boolean equals(Object str){
    return false;
  }

/**

  • 実装するgetメソッド
  • @return E エレメント(要素)
  • @param i 指定されたインデックス番号 **/

  public E get(int i){

     /*
    エレメントeに、String型Data[i]を
    キャストして格納*/

    E e = (E)Data[i];
    return e;
  }

  public int hashCode(){
    return -1;
  }

  public int indexOf(Object str){
    return -1;
  }

  public boolean isEmpty(){
    return false;
  }

  public Iterator iterator(){
    return null;
  }

  public int lastIndexOf(Object str){
    return -1;
  }

  public ListIterator listIterator(){
    return null;
  }

  public ListIterator listIterator(int i){
    return null;
  }

   /**
  * 実装するremoveメソッド
  * @return E エレメント(要素)
  * @param index 指定されたインデックス番号
  **/

  public E remove(int index){

      /*
       Dataを最大まで回し、iをインクリメントしたData[i++]を
       String型Dataに格納する*/
     for(int i = index; i < Data.length; i++){
         Data[i] = Data[index++];
     }
     Count--;
     E e = (E)Data;
     return e;
}

public boolean remove(Object str){
    return false;
}

public boolean removeAll(Collection c){
    return false;
}

public boolean retainAll(Collection c){
    return false;
}

/**
 * 実装するsetメソッド
 * @return E エレメント(要素)
 * @param i 指定されたインデックス番号
 * @param element 置き換える要素
 **/

public E set(int i,E element){

    // String型Dataにelementをキャストして格納
   Data[i] = (String)element;

   // エレメントeにData[i]をキャストして格納
   E e = (E)Data[i];

   // 値を返す
   return e;

}

/**
 * 実装するsizeメソッド
 * @return int 指定されたインデックス番号
 **/

public int size(){
   return Count;
}

public List subList(int i,int j){
   return this;
}

public Object[] toArray(){
   return Data;
}

public Object[] toArray(Object[] a){
   return Data;
}

}

class Main {

/**

  • メインメソッド **/

public static void main(String args[]) {
Mylist sub = new Mylist();

  /*
  addメソッドを実装し、機体名を要素とする。
  addを最大まで回し、getメソッドで要素を取り出して表示する*/

 sub.add("ビルドバーニングガンダム");
 sub.add("ライトニングガンダム");
 sub.add("ウイニングガンダム");
 sub.add("ガンダムフェニーチェリナーシタ");
 sub.add("R・ギャギャ");
 sub.add("ユニコーンガンダム");

 for(int i = 0; i < sub.size(); i++){
     System.out.println(sub.get(i));
 }

 // sizeメソッド
 System.out.println("\r\n" + "機体数は" + sub.size() + "です" + "\r\n");

 // setメソッド
 sub.set(0,"ガンダムエピオン");
 for(int i = 0; i < sub.size(); i++){
     System.out.println(sub.get(i));
 }

// 改行
System.out.println();

// removeメソッド
sub.remove(1);
for(int i = 0; i < sub.size(); i++){
    System.out.println(sub.get(i));
}

// clearメソッド
sub.clear();
  System.out.println("\r\n" + "機体数が" + sub.size() + "になったので負けです");
}

}

このプログラムをコンパイルして実行すると、

C:\JAVA>java Main
ビルドバーニングガンダム
ライトニングガンダム
ウイニングガンダム
ガンダムフェニーチェリナーシタ
R・ギャギャ
ユニコーンガンダム

機体数は6です

ガンダムエピオン ←setメソッドで置き換え
ライトニングガンダム
ウイニングガンダム
ガンダムフェニーチェリナーシタ
R・ギャギャ
ユニコーンガンダム

ガンダムエピオン
ライトニングガンダム ←removeメソッドで削除したいが・・・・
ウイニングガンダム
ガンダムフェニーチェリナーシタ
R・ギャギャ
(ユニコーンガンダム) ←1番最後の要素が削除されている

機体数が0になったので負けです

上記のように表示されています。ここで質問なのですが、

①removeメソッドが機能していない、という問題があります。思うに、removeメソッドの
for(int i = index; i < Data.length; i++){
部分が何か微妙に違うと思うのですが・・・・・

②現在addは箱を10個用意するように設定していますので、11個目のaddの中身をメインクラスに書き足せば、当然例外が発生します。それを、例外を発生させず、新たに箱を用意するように設定しろ、という後だしジャンケン的な仕様が加わりました。ならArrayList使わせろよ。。。という感じなのですが、今回は使用禁止となっています。ここが考えてもさっぱり分からない、1番重症と言える箇所です。

③要素を削除するclearメソッドですが、現在のコード上でsizeメソッド・getメソッドと共に数少なく真面目に稼動してくれているメソッドです。いや、そうだと思っていました。現在のコード上では真面目に動いているように見えますが、clearなので全要素を削除するはずなのに、要素が取り出せてしまうという致命的なオチを発見してしまいました。ここまででがっかりと言うか何と言うか。

ドヤ顔でコンパイルしてからの実行でこの3点が見つかり、昨日は精魂尽き果ててしまいました。気を取り直して、この3連休で終わらせようと思います。現在50%かそれ以下でしょうが、①から③の問題について、考え方などを御教授して頂けないでしょうか?何卒よろしくお願い致します。

回答

// 何故かジェネリクス表記がプレビューで付けられていませんが、

コードブロックの書き方はヘルプや昔私が投げたパッチなどを参照してください。
現在であればコードブロックボタンがついてますのでそれも利用してください。
(全部選択しておいて </> ボタンを押せばコードブロック化してくれるハズ )
そのまま書いてもHTMLとして認識されてしまうので表示されません。


まず、最初の。

removeメソッドがそう動作するようにできています。
このremoveメソッドの仕様は、
「indexで指定された要素を返し、内部のアイテムの総数情報をデクリメントする」
となっています。
ですので、元のループと比較すると

  • ループする数は1回少なくなる( sizeで変えるのが 1少なくなるから)
  • 配列は変更されていないしsizeが1減るだけだから最後の要素が表示されなくなる。
  private int Count;

  public E remove(int index){

    /*
      Dataを最大まで回し、iをインクリメントしたData[i++]を
      String型Dataに格納する*/
    for(int i = index; i < Data.length; i++){
      Data[i] = Data[index++];
    }

    Count--;
    E e = (E)Data;
    return e;
  }

二番目の問題にある

「②現在addは箱を10個用意するように設定していますので、11個目のaddの中身をメインクラスに書き足せば、当然例外が発生します。それを、例外を発生させず、新たに箱を用意するように設定しろ、という後だしジャンケン的な仕様が加わりました。」

ですが、多分この課題は「動的に要素を用意するのって難しいでしょ?Listって便利でしょ?」
といった事を気づかせる部分もあるんじゃないかと思います。
List<E>を実装する段階でそういう変更が起こりうることを感じていないとですね。

本題ですけど、2,3 いずれも「結局配列は何も変わっていない」事が問題です。
配列のサイズを変更してください。
(そしてそれこそがこの課題のポイントです。)

配列のサイズを途中で変更することはできません(できたらArrayListいらないですし)。
ただし新しい配列と差し替えることはできます。
要素を減らしたいなら、要素数の1つ少ない配列を新たに作り値を詰め直してあげて古い配列と差し替えるしかありません。

増やす方も( ①の問題)同じ考え方でできます。
また、最終的には Count変数はいらなくなると思います。


このあたりは課題なのでどこまで既存のメソッド使っていいかわからないですね。
配列をコピーするメソッドはあったりはするんですが、まぁ10件しかないので時間があるなら新しい配列を作る部分も自分で作った方がいいでしょう。
コードも提出するなら( xxメソッドはあるのは知ってましたが自分で実装してみました )とか書いてみるといいかもしれませんね。

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。