Исключения нулевого указателя в Java - не понимаю, почему - PullRequest
2 голосов
/ 31 октября 2010

Ошибка времени выполнения основного метода в MovieList.java.

Я не уверен, что моя программа в целом очень хороша, но я хотел бы знать, почему она дает сбой.Заранее спасибо.

package javaPractical.week3;

import javax.swing.*;

public class Movie {
    //private attributes
    private String title;
    private String movieURL;
    private String year;
    private String genre;
    private String actor;

    // constructor
    Movie(String t, String u, String y, String g, String a) {
        this.title = t;
        this.movieURL = u;
        this.year = y;
        this.genre = g;
        this.actor = a;

    }
    //getters and setters
    public void setTitle(String t) {
        this.title = t;
    }

    public String getTitle() {
        return this.title;
    }

    public void set_url(String a) {
        this.movieURL = a;
    }

    public String get_url() {
        return this.movieURL;
    }

    public void setYear(String y) {
        this.year = y;
    }

    public String getYear() {
        return this.year;
    }

    public void setGenre(String g) {
        this.genre = g;
    }

    public String getGenre() {
        return this.genre;
    }

    public void setActor(String a) {
        this.actor = a;
    }

    public String getActor() {
        return this.actor;
    }


    //output movie details
    public String toString() {
        return ("Title: " + this.title + "\nURL: " + this.movieURL + "\nYear: "
            + this.year + "\nGenre: " + this.genre + "\nActor: "
            + this.actor);
    }

    public static void main(String[] args) {
        //testing Movie class
        Movie Movie1 = new Movie("Spiderman", "www.", "2002", "Action",
            "Tobey M");

        JOptionPane.showMessageDialog(null, Movie1.toString());
        //testing MovieList class
    }
}

package javaPractical.week3;

import javax.swing.*;

import java.util.ArrayList;

public class MovieList1 {

    private static ArrayList myFavouriteMovies = new ArrayList();
    private static int NUM_OF_MOVIES = 10;
    private int numberOfMovies = 0;
    private int index = 0;

    public MovieList1() {
        this.myFavouriteMovies = null;
        this.numberOfMovies = 0;
        this.index = 0;
    }

    public int getNumberOfMovies() {
        return this.myFavouriteMovies.size();
    }

    public boolean isEmpty() {
        if (this.myFavouriteMovies.isEmpty()) {
            return true;

        } else
        return false;

    }

    public static void main(String[] args) {
        MovieList1 List = new MovieList1();
        String titleADD;
        String movieURLADD;
        String yearADD;
        String genreADD;
        String actorADD;

        titleADD = JOptionPane.showInputDialog(null, "Enter title:");
        movieURLADD = JOptionPane.showInputDialog(null, "Enter URL:");
        yearADD = JOptionPane.showInputDialog(null, "Enter year:");
        genreADD = JOptionPane.showInputDialog(null, "Enter genre:");
        actorADD = JOptionPane.showInputDialog(null, "Enter actor:");

        Movie TempMovie = new Movie(titleADD, movieURLADD, yearADD, genreADD,
            actorADD);

        myFavouriteMovies.add(TempMovie);   
    }
}

Ответы [ 6 ]

8 голосов
/ 31 октября 2010

Сбой программы при попытке добавить новый Movie к myFavouriteMovies, потому что myFavouriteMovies равен null.

Хотя myFavouriteMovies инициализируется новым, пустым ArrayList, затем в конструкторе MovieList1 ему присваивается значение null.

На данный момент myFavouriteMovies равно static, поэтому существует только одна копия этой переменной, совместно используемая каждым экземпляром MovieList1. Вы, вероятно, хотите удалить модификатор static из объявления myFavouriteMovies. Тогда каждый объект MovieList1 будет иметь свое собственное поле myFavouriteMovies. Однако затем вы добавите новый метод в класс MovieList1, чтобы ваш метод main мог добавить фильм в список фильмов, возможно, так:

List.add(TempMovie);

Также вам нужно будет удалить

this.myFavouriteMovies = null;

из конструктора, поскольку инициализировав его пустым ArrayList, вы не захотите возвращать его в null.

2 голосов
/ 31 октября 2010

В вашем конструкторе вы устанавливаете

 public MovieList1() {
   this.myFavouriteMovies = null;
   this.numberOfMovies = 0;
   this.index = 0;
 }

после того, как вы уже объявили myFavouriteMovies выше.Это может привести к NullPointer

1 голос
/ 31 октября 2010

Все вышеперечисленные ответы точны, но я спрашиваю, нужен ли вам вообще класс MovieList1. По сути, вы просто предоставляете обертку вокруг List. Я не уверен, что у вас есть планы по расширению поведения в списке фильмов, но, как есть, вы могли бы просто сделать:

List<Movie> movies = new ArrayList<Movie>();
String titleADD = JOptionPane.showInputDialog(null, "Enter title:");
String movieURLADD = JOptionPane.showInputDialog(null, "Enter URL:");
String yearADD = JOptionPane.showInputDialog(null, "Enter year:");
String genreADD = JOptionPane.showInputDialog(null, "Enter genre:");
String actorADD = JOptionPane.showInputDialog(null, "Enter actor:");

Movie TempMovie = new Movie(titleADD, movieURLADD, yearADD, genreADD, actorADD);
movies.add(TempMovie);  

Пара других заметок ...

Вероятно, у вас должен быть метод addMovie(Movie movie) или что-то подобное в классе списка фильмов, а не доступ к списку непосредственно в вашем основном методе.

Вы должны запрограммировать интерфейс вместо объявления ArrayList в качестве типа myFavoriteMovies.

Нет необходимости перезаписывать значения в конструкторе, потому что вы уже создали или инициализировали их при объявлении.

Вы, вероятно, получаете предупреждение, вызывая this.myFavoriteMovies, потому что он статический. Статические члены и методы должны быть доступны ClassName.staticMethodOrVariable. Я упоминаю об этом только потому, что существует большая разница между тем, что подразумевает this, и тем, что является статическим. This относится к текущей ссылке типа, в то время как static является постоянным. Кроме того, при объявлении неизменяемых статических элементов используйте модификатор final, но в этом случае я не думаю, что он должен быть статическим, но определенно может быть окончательным.

1 голос
/ 31 октября 2010

Когда вы вызываете конструктор для MovieList1, вы устанавливаете ArrayList MyFavouriteMovies в null. Если вы вызываете методы на MyFavouriteMovies, возникает исключение нулевого указателя (на myFavouriteMovies.add(TempMovie);).

this.myFavouriteMovies = null; должно быть this.myFavouriteMovies = new ArrayList(); и private static ArrayList myFavouriteMovies = new ArrayList(); должно быть private ArrayList myFavouriteMovies;

Кстати, я бы не стал делать myFavouriteMovies статичным, поскольку он отличается для каждого экземпляра MovieList1. Затем у вас будет метод addMovie () в MovieList1. Кроме того, если NUM_OF_MOVIES является константой, как предполагает название в верхнем регистре, вы должны объявить его окончательным.

0 голосов
/ 31 октября 2010

Я наблюдаю, что вы не обладаете хорошим знанием логики программирования. Вам также необходимо дополнительно понять поток времени выполнения Java и поведение языка. Тем не менее, логический поток - это навык, который вам необходимо приобрести, независимо от того, общаетесь ли вы на Java, C, C ++ или английском языке. (Кстати, английский язык, несмотря на наличие противоречивых синтетических элементов, является аналитически логичным языком.)

Сначала вы объявляете статические myFavouriteMovies и создаете их экземпляр для ArrayList. После этого вы приравниваете его к нулю. Приравнивая переменную к нулю, вы пытаетесь использовать ее как

myFavouriteMovies.add(TempMovie);

Конечно, вы получите нулевой указатель.

Вам необходимо ознакомиться с дампами ошибок компилятора и среды выполнения. Ошибка времени выполнения Java, безусловно, указала бы на номер выписки, в котором она обнаружила вашу попытку снять деньги с пустого банковского счета, не защищенного от овердрафта.

Программы на C #, написанные "экспертами VB", всегда расстраивают меня. Я понимаю, что это не очень хороший ответ, но я очень самонадеянно заявляю, что вы, скорее всего, опытный программист на Visual Basic. Поэтому я пользуюсь дополнительной возможностью для всех опытных программистов на Visual Basic, бросая соль на открытую рану (соль является дезинфицирующим средством), чтобы вы НИКОГДА не передавали свои знания в области программирования на языке объектных ссылок на объектно-ориентированные языки. Подобно тому, как опытному носителю синтетического логического языка, такого как греческий или иврит, трудно приспособиться к аналитически логическому языку, такому как английский, и наоборот.

Во-вторых, с чем связано объявление myFavouriteMovies в качестве статического? Вы понимаете значение статической переменной?

В-третьих, вы не должны ссылаться на статическую переменную через ссылку на экземпляр класса "this". myFavouriteMovies - это статическая переменная в классе Movie. Поэтому вы должны ссылаться на него как

Movie.myFavouriteMovies

а не как

this.myFavouriteMovies

Java позволяет вам выполнять такие аберрационные ссылки, но C # не будет. «this» следует зарезервировать для «переменных экземпляра».

Наконец, по сравнению с другими "экспертами по VB", существует высокая вероятность того, что вам потребуется дополнительное понимание того, какие переменные экземпляра являются статическими переменными. Статическая переменная существует без необходимости создания экземпляра класса. Следовательно, он «разделяется» всеми экземплярами класса; и если он является общедоступным или защищенным, он используется совместно с любыми элементами процесса, которым подвергается эта статическая переменная.

Обычно, когда у вас есть статический список, ваш метод get не должен возвращать ссылку на эту статическую переменную. Вы должны вернуть подмножество списка. Например, вы можете иметь статический список всех поклонников каждого фильма. Когда вам нужно вернуть список из списка Поклонников определенного фильма, вы не возвращаете весь статический список, а только подмножество этого статического списка. Вы должны понимать, когда можно использовать статические переменные, и ограничивать себя в развертывании статических ссылок. Это означает, что НЕ объявляйте статическую переменную, если сделаете ее экземпляром класса.

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

Маленькие мелочи: Знаете ли вы, что вы можете выполнять статические манипуляции в Java, используя статический блок? Если имеется более одного статического блока, они будут обрабатываться в порядке их объявления. Как обычно, любая переменная, объявленная внутри блока кода, не видна за пределами этого блока.

class Hello{
  static {
    // perform static manipulation here
  }

  public void setAnInstanceValue(int a){
    ...
  }
  static {
    // another static block of code here
  }
  .....
}

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

Читать это: Поток выполнения для блока статического кода - http://forums.sun.com/thread.jspa?threadID=5418566. 2017-06-30: эта тема на солнечном форуме была заархивирована на https://community.oracle.com/message/5266256#5266256, для доступа к которой требуется регистрация оракула. ​​

0 голосов
/ 31 октября 2010

Ричард имеет правильный ответ на вопрос, в чем проблема. Хотя есть лучшее решение.

Когда вы объявляете переменную, вы должны подумать, хотите ли вы когда-нибудь ее изменить. Если вы не пометите его как окончательный.

Итак:

private final String title;
private final String movieURL;
private final String year;
private final String genre;
private final String actor;

private static final int NUM_OF_MOVIES = 10;
private final List myFavouriteMovies = new ArrayList();
private int numberOfMovies;
private int index;

Это будет означать, что вам нужно избавиться от большинства методов setXXX - если вы подумаете об этом, вы никогда не захотите изменять значения после создания экземпляра в любом случае. Предполагается, что numberOfMovies и index нужно изменить, поэтому они не являются окончательными. Наконец (без каламбура!) Вам не нужно устанавливать переменные экземпляра в 0, null или false, они по умолчанию установлены на это.

...