JavaRush /Java Blog /Random-JA /初心者 Java プログラマーの間違い。パート1
articles
レベル 15

初心者 Java プログラマーの間違い。パート1

Random-JA グループに公開済み

1. クラスの名前が、クラスが格納されているファイルの名前と異なります。

Javasoft JDK を含む、私が使用したすべての Java フレームワークは、public 修飾子を持つクラスのソース コードが、クラス名とまったく同じ名前で拡張子 .java が付いたファイルに保存されることを前提としています。この規則に従わないと、コンパイル中に多くの問題が発生する可能性があります。
初心者 Java プログラマーの間違い。 パート 1 - 1
初心者の学生 (プログラマ) は、この規則を忘れて、たとえば、課題に従ってファイル名を「Lab6.java」に設定してしまうことがよくあります。 間違った例: ファイル名Lab6.java
public class Airplane extends Vehicle
  Seat pilot;
  public Airplane() {
    pilot = new Seat();
  }
}
修正例: ファイル名Airplane.java
public class Airplane extends Vehicle
  Seat pilot;
  public Airplane() {
    pilot = new Seat();
  }
}
ご注意ください:クラス名は大文字で始まるものとみなされます。ファイル名で大文字と小文字を区別するオペレーティング システムでは、特に DOS ファイル命名システムに慣れている Unix で Java を学習している学生にとって、さらなる問題が発生する可能性があります。クラスはMotorVehicleファイルに保存する必要がありますMotorVehicle.javaが、motorvehicle.java.

2. を使用した比較==

Java では、文字列はクラスのオブジェクトですjava.lang.String。オブジェクトに適用される演算子は、==オブジェクトへの参照が等しいかどうかをチェックします。場合によっては、学生が演算子のセマンティクスを理解せず==、それを使用して文字列を比較しようとすることがあります。 間違った例:
// проверим, equals ли первый аргумент "-a"
if (args[0] == "-a") {
    optionsAll = true;
}
2 つの文字列が等しいかどうかを比較する正しい方法は、equals()クラスメソッドを使用することですjava.lang.Stringtrue文字列が同じ長さで、同じ文字が含まれている場合に返されます。(注: 実際には、これは等しいことを保証するものではありません。実際には、equals2 つの文字列が 1 文字ずつ等しいかどうかがチェックされます) 修正された例:
//  проверим, equals ли первый аргумент "-a"
if ("-a".equals(args[0])) {
    optionsAll = true;
}
実際、Java コードは構文的には正しいことが判明しますが、最終的には期待どおりに動作しないため、このエラーは愚かです。学生の中には、クラスメソッドの代わりに比較演算子>やを使用しようとする人もいます。このエラーはコンパイル段階でエラーを引き起こすため、検出が容易です。 <=compareTo()java.lang.String

3. 配列の要素であるオブジェクトを初期化するのを忘れました。

Java では、オブジェクトの配列は実際にはオブジェクト参照の配列です。配列の作成は、単に何も指さない (つまり、null である) 参照のセットを作成することです。実際にオブジェクトの「完全な」配列を作成するには、配列の各要素を初期化する必要があります。多くの学生はこれを理解していません。彼らは、オブジェクトの配列を作成すると、オブジェクト自体が自動的に作成されると信じています。(ほとんどの場合、学生はこの概念を C++ から持ち込んでいます。C++ では、オブジェクトの配列を作成すると、デフォルトのコンストラクターを呼び出してオブジェクト自体を作成することになります。) 以下の例では、学生はクラスの 3 つのオブジェクトを作成したいと考えていますStringBuffer。コードはエラーなしでコンパイルされますが、NullPointerException存在しないオブジェクトがアクセスされる最後の行で例外が発生します。 間違った例:
// Создаем массив из StringBuffer
StringBuffer [] myTempBuffers;
myTempBuffers = new StringBuffer[3];
myTempBuffers[0].add(data);
このエラーを回避するには、配列要素を忘れずに初期化する必要があります。 修正された例:
// Создаем массив из StringBuffer и инициализируем элементы
StringBuffer [] myTempBuffers;
myTempBuffers = new StringBuffer[3];
for (int ix = 0; ix < myTempBuffers.length; ix++)
     myTempBuffers[ix] = new StringBuffer();

myTempBuffers[0].add(data);

4. 修飾子を含む複数のクラスを 1 つのファイルに一度に配置するpublic

Java ソース ファイルは、それらのファイルに含まれるクラスと特定の方法で関連付けられています。この関係は次のように特徴づけられます。 Java クラスは 1 つのファイルのみに保存されます。どのソース コード ファイルにも、修飾子を含むクラスは 1 つだけ配置できますpublic。ソース コード ファイルに修飾子を持つクラスがある場合public、ファイル名とクラス名は厳密に同じである必要があります (翻訳注: 場合によっては、ポイント 1 を参照してください) 生徒が 2 番目のルールを忘れることがあり、それがエラーにつながります。ステージコンピレーションにて。2 番目と 3 番目のルールのエラー メッセージは同じになります (これが実際にこのエラーを認識することを難しくしています)。

5. クラスフィールドをローカル変数に置き換えます。

Java では、クラスのフィールドと名前が一致する変数をメソッド内で宣言できます。この場合、ローカル変数が優先され、フィールドの代わりに使用されます。同じ名前の変数の型が異なる場合、コンパイラはエラーをスローします。同じ型であればコンパイルエラーにはならず、プログラムが誤動作する原因が不明になります。 間違った例:
public class Point3 {
    int i = 0;
    int j = 0;
    int k = 0;

    public boolean hits(Point[] p2list) {
      for(int i = 0; i < p2list.length; i++) {
        Point p2 = p2list[i];
        if (p2.x == i && p2.y == j)
          return true;
      }
      return false;
    }
}
このエラーを修正するにはいくつかの方法があります。最も簡単な方法は、暗黙的なthis:ポインタを使用してクラス フィールドにアクセスすることですthis.Name_поля。最善の方法は、クラス フィールドまたはローカル変数の名前を変更することです。そうすれば、置換は行われません。(おおよその翻訳: 2 番目の方法は私たちの方法ではありません。さらに、いつか変数のフィールドを誤って置き換えないという保証もありません。継承ではさらに大きな問題が発生します。どのフィールドが分​​からない場合です。クラスには があります) 修正された例:
// One way to fix the problem
  int i = 0;
  int j = 0;
  int k = 0;

  public boolean hits(Point[] p2list) {
    for(int i = 0; i < p2list.length; i++) {
      Point p2 = p2list[i];
      if (p2.x == this.i && p2.y == this.j)
        return true;
    }
    return false;
  }

  // *****************************
  // Лучший способ
  int x = 0;
  int y = 0;
  int z = 0;

  public boolean hits(Point[] p2list) {
    for(int i = 0; i < p2list.length; i++) {
      Point p2 = p2list[i];
      if (p2.x == x && p2.y == y)
        return true;
    }
    return false;
  }
このエラーが発生するもう 1 つの場所は、メソッドのパラメーター名をクラスのフィールド名と同じに設定することです。これはコンストラクターでは適切に見えますが、通常のメソッドには適していません。

約。翻訳

少し混乱していますが、それが要点です

public class Test {
   private int param = 0;

   public Test(int param) {
      this.param = param;
   }
}

つまり、コンストラクターではすべてが美しく見えますが、これは通常のメソッドには使用しないでください。

6. 親 (スーパークラス) コンストラクターを呼び出すのを忘れた

クラスが別のクラスを拡張する場合、各サブクラス コンストラクターはスーパークラス コンストラクターを呼び出す必要があります。super(x)これは通常、コンストラクターの最初の行に配置されたメソッドを使用してスーパークラス コンストラクターを呼び出すことによって実現されます。コンストラクターの最初の行に呼び出しがない場合super(x)、コンパイラー自体がこの呼び出しを挿入しますが、パラメーターはありませんsuper()。(おおよそのtrans.: x...seですが、私は知りませんでした) 時々、生徒がこの要件を忘れてしまうことがあります。通常、これは問題にはなりません。スーパークラス コンストラクターへの呼び出しはコンパイラーによって挿入され、すべてが正常に動作します。ただし、スーパークラスにデフォルトのコンストラクターがない場合、コンパイラーはエラーをスローします。以下の例では、すべてのスーパークラス コンストラクターにjava.io.File1 つまたは 2 つのパラメーターがあります。 誤った例:
public class JavaClassFile extends File {
    String classname;
    public JavaClassFile(String cl) {
        classname = cl;
    }
}
この問題の解決策は、正しいスーパークラス コンストラクターへの明示的な呼び出しを挿入することです。 修正された例:
public class JavaClassFile extends File {
    String classname;
    public JavaClassFile(String cl) {
        super(cl + ".class");
        classname = cl;
    }
}
スーパークラスにデフォルトのコンストラクターがあるにもかかわらず、オブジェクトが完全に初期化されていない場合、さらに不快な状況が発生します。この場合、コードはコンパイルされますが、プログラムの出力が正しくないか、例外が発生する可能性があります。

7. 例外を誤ってキャッチする

Java の例外処理システムは非常に強力ですが、初心者にとっては理解するのが困難です。C++ や Ada に習熟している学生は、通常、C や Fortran のプログラマーと同じような困難を抱えていません。以下の例は、よくある間違いを示しています。この例では、例外に名前が付けられていません。コンパイラはコンパイル段階でこのエラーを示すため、自分で簡単に修正できます。 間違った例:
try {
    stream1 = new FileInputStream("data.txt");
} catch (IOException) {
    message("Could not open data.txt");
}
修正された例:
try {
   stream1 = new FileInputStream("data.txt");
} catch (IOException ie) {
   message("Could not open data.txt: " + ie);
}
ブロックの順序によって、catch例外がキャッチされる順序が決まります。このような各ブロックは、指定されたクラスまたはそのサブクラスのすべての例外をキャッチすることを考慮する必要があります。これを考慮しないと、到達不能な catch ブロックが発生し、コンパイラによって指摘される可能性があります。以下の例には、SocketExceptionのサブクラスがありますIOException間違った例:
try {
    serviceSocket.setSoTimeout(1000);
    newsock = serviceSocket.accept();
} catch (IOException ie) {
    message("Error accepting connection.");
} catch (SocketException se) {
    message("Error setting time-out.");
}
修正された例:
try {
    serviceSocket.setSoTimeout(1000);
    newsock = serviceSocket.accept();
} catch (SocketException se) {
    message("Error setting time-out.");
} catch (IOException ie) {
    message("Error accepting connection.");
}
コード内でどのブロックにもキャッチされない例外が発生する可能性がある場合はtry-catch、この例外をメソッド ヘッダーで宣言する必要があります。(これは例外、つまりクラスのサブクラスの場合はRuntimeException必要ありません)。学生は、メソッドを呼び出すと例外がスローされる可能性があることを忘れることがあります。これを修正する最も簡単な方法は、メソッド呼び出しをブロックに入れることですtry-catch間違った例:
public void waitFor(int sec) {
    Thread.sleep(sec * 1000);
}
修正された例:
public void waitFor(int sec) throws InterruptedException {
    Thread.sleep(sec * 1000);
}

8. アクセス方法にはタイプがありますvoid

これは非常に単純な間違いです。学生は変数にアクセスするメソッドを作成しますが、メソッドが何も返さないように指定します (voidメソッド ヘッダーに修飾子を置きます)。このエラーを修正するには、正しい戻り値の型を指定する必要があります。 間違った例:
public class Line {
    private Point start, end;
    public void getStart() {
      return start;
    }
}
修正された例:
public class Line {
    private Point start, end;
    public Point getStart() {
      return start;
    }
}
間違った戻り値の型を指定すると、一連のエラーが生成されます。通常、コンパイラはこれらのエラーを認識し、学生が自分で修正できるように報告します。著者: A. Grasoff™ 続きを読む ソースへのリンク:初心者 Java プログラマーの間違い
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION