Авторские Материалы о событиях в Израиле на Ближнем Востоке и в мире

IsraMir.com - Израильская журналистика

Default color brown color green color red color blue color
Вы сейчас тут: Новости arrow Техотдел arrow Свет ученья arrow Работа над ошибками
Skip to content
Работа над ошибками Версия для печати Отправить на e-mail
Sunday, 05 March 2006 | Сайт SQL.ru для раздела Ученье – свет
Работанадошибкамиjavaisramir.comОт редакции IsraMir’а: чрезвычайно это полезная и нужная ведь: «разбор полетов», особенно, когда речь идет о начинающих изучать любое дело, в том числе и работу на Java. Именно поэтому материал, который я нашел и предлагаю вам сегодня (частично), показался мне очень полезным. Естественно, что наши решпекты и благодарности автору и владельцам сайта – на этот раз SQL.ru
 
Эта статья создана из топика ошибки начинающих java-программистов.
Оригинал статьи здесь: http://users.erols.com/ziring/java-npm.html
Перевод: Deady

Имя класса отличается от имени файла, в котором он хранится.
Все используемые мною среды java, включая Javasoft JDKs, предполагают,
что исходный код класса с модификатором public хранится в файле с точно
таким же именем, как и имя класса, и расширением .java. Несоблюдение этого
соглашения может стать причиной многих проблем, которые выявятся во время
компиляции.

Начинающие студенты (программисты) часто забывают об этом соглашении,
и, например, задают имя файла в соответствии с заданием: 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();
  }
}

Заметьте: предполагается, что имя класса начинается с заглавной буквы. В
операционных системах, которые учитывают регистр символов в именах файлов,
могут появиться дополнительные проблемы, особенно у студентов, изучающих
Java под Unix, и привыкших к системе именования файлов в DOS. Класс
MotorVehicle должен храниться в файле MotorVehicle.java, но не в файле
motorvehicle.java.


Сравнение с помощью ==
В Java строки - это объекты класса java.lang.String. Оператор ==, применяемый
к объектам, проверяет на равенство ссылки на объекты! Иногда студенты не
понимают семантики оператора == и пытаются применить его для сравнения
строк.

Ошибочный пример:
// проверим, равен ли первый аргумент "-a"
if (args[0] == "-a") {
    optionsAll = true;
}

Правильный способ сравнения 2-х строк на равенство – это использование метода
equals() класса java.lang.String. Он возвращает true, если строки одинаковой
длины и состоят из одних и тех же символов. (Прим. перев.: вообще-то это не
гарантирует равенство. На самом деле, equals проверяет, равны ли посимвольно
2 строки)

Исправленный пример:
//  проверим, равен ли первый аргумент "-a"
if ("-a".equals(args[0])) {
    optionsAll = true;
}

Эта ошибка - дурацкая, потому что на самом деле Java код получается
синтаксически правильным, а в итоге работает не так как нужно. Некоторые
студенты также пытаются применять операторы сравнения > и <=, вместо метода compareTo() класса java.lang.String. Эту ошибку обнаружить
проще, потому что она вызывает ошибки на этапе компиляции.

Забыл проинициализировать объекты, являющиеся элементами массива.
В Java массив объектов - это на самом деле массив ссылок на объекты. Создание
массива - это просто создание набора ссылок, ни на что не указывающих (то
есть равных null). Чтобы на самом деле создать "полноценный" массив
объектов, необходимо проинициализировать каждый элемент массива. Многие
студенты не понимают этого; они считают, что, создавая массив объектов, они
автоматически создают сами объекты. (В большинстве случаев, студенты
приносят эту концепцию из 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);


Помещение в один файл сразу нескольких классов с модификатором public
Файлы с исходным java-кодом определенным образом связаны с классами,
содержащимися в этих файлах. Связь можно охарактеризовать так:
  • Любой Java-класс хранится не более чем в одном файле
  • В любой файл с исходным кодом можно поместить не более 1-го класса с
    модификатором public
  • Если в файле с исходным кодом есть класс с модификатором public, имя
    файла и имя класса должны быть строго одинаковыми (прим. перев.: до
    регистра, см. п.1)

Иногда студенты забывают о 2-ом правиле, что приводит к ошибкам на этапе
компиляции. Сообщение об ошибке для 2-го и 3-го правила будет одинаковым
(в чем собственно и заключается трудность распознания этой ошибки).

Подмена поля класса локальной переменной.
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.имя_поля.
Более лучший способ - это переименовать поле класса или локальную
переменную, тогда подмены не произойдет. (прим. перев.: 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;
  }

Еще одно возможное место появления этой ошибки - задание имени параметра
метода таким же, как и имя поля класса. Это хорошо выглядит в конструкторах,
но для обычных методов не подходит.
прим. перев.

немного сумбурно, но смысл такой
public class Test {
   private int param = 0;
 
   public Test(int param) {
      this.param = param;
   }
}
то есть в конструкторе все смотрится красиво, но для обычных методов
применять это не следует.


На этом – все. Пока. На сегодня. Продолжение – следует.
 
 

Добавить комментарий

:D:lol::-);-)8):-|:-*:oops::sad::cry::o:-?:-x:eek::zzz:P:roll::sigh:


Автотранслитерация: выключена

Защитный код

Powered by jComments