【问题标题】:Java null pointer exceptions - don't understand whyJava 空指针异常 - 不明白为什么
【发布时间】:2010-10-30 23:09:27
【问题描述】:

MovieList.java 中 main 方法的运行时错误。

我不确定我的程序设计从根本上来说是不是非常好,但我想知道它为什么会崩溃。提前致谢。

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);   
    }
}

【问题讨论】:

  • 虽然它是一个空指针异常我删除了指针标签。在 Java 中谈论指针是没有意义的。另外,如果这是家庭作业,请添加“家庭作业”标签。

标签: java exception null nullpointerexception


【解决方案1】:

程序在尝试将新的Movie 添加到myFavouriteMovies 时崩溃,因为myFavouriteMoviesnull

虽然myFavouriteMovies 被初始化为一个新的空ArrayList,但它在MovieList1 构造函数中被设置为null

目前,myFavouriteMoviesstatic,因此每个 MovieList1 实例之间只有一个共享此变量的副本。您可能希望从 myFavouriteMovies 声明中删除 static 修饰符。然后每个MovieList1 对象将有自己的myFavouriteMovies 字段。但是,您随后将向 MovieList1 类添加一个新方法,以允许您的 main 方法将电影添加到电影列表中,可能像这样:

List.add(TempMovie);

你还需要删除

this.myFavouriteMovies = null;

在构造函数中,因为已将其初始化为空的ArrayList,所以您不想将其设置回null

【讨论】:

    【解决方案2】:

    在你的构造函数中设置

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

    在您已经在上面声明了 myFavouriteMovies 之后。这可能会导致 NullPointer

    【讨论】:

    • 是的。 @James myFavouriteMovies 是静态的还是实例变量?选择一个并只实例化一次。
    【解决方案3】:

    当您调用 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 的每个实例都不同。然后,您将在 MovieList1 中有一个方法 addMovie()。此外,如果 NUM_OF_MOVIES 是常量,正如大写名称所暗示的那样,您应该将其声明为 final。

    【讨论】:

      【解决方案4】:

      以上所有答案都是正确的,但我怀疑你是否甚至需要 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) 方法或类似的东西,而不是直接在您的 main 方法中访问列表。

      您应该program to the interface 而不是将ArrayList 声明为myFavoriteMovies 的类型。

      没有必要覆盖构造函数中的值,因为您在声明它们时已经实例化或初始化了它们。

      调用 this.myFavoriteMovies 可能会收到警告,因为它是静态的。静态成员和方法应该由 ClassName.staticMethodOrVariable 访问。我之所以提到这一点,是因为this 所暗示的内容与静态内容之间存在很大差异。 This 指的是类型的当前引用,而 static 意味着是持久的。另外,在声明不可变的静态成员时,使用final 修饰符,但在这种情况下,我认为它不需要是静态的,但绝对可以是最终的。

      【讨论】:

        【解决方案5】:

        Richard 对问题所在有正确的答案。不过有更好的解决方案。

        当你声明一个变量时,你应该考虑你是否希望它改变。如果您没有将其标记为最终版本。

        所以:

        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,它们默认设置为。

        【讨论】:

          【解决方案6】:

          我观察到您没有很好地掌握编程逻辑。您还需要进一步了解 Java 运行时的流程和语言的行为。尽管如此,无论您使用 Java、C、C++ 还是英语进行交流,逻辑流程都是您需要掌握的技能。 (顺便说一句,尽管英语合成元素不一致,但它是一种分析逻辑语言。)

          首先,您声明一个静态 myFavouriteMovies 并将其实例化为一个 ArrayList。之后,您将其等同于 null。将变量等同于 null 后,您尝试将其用作

          myFavouriteMovies.add(TempMovie);
          

          当然,你会得到一个空指针。

          您需要熟悉编译器和运行时错误转储。 Java 运行时错误肯定会指出遇到您尝试从未受透支保护的空银行账户提款的语句编号。

          “VB 专家”编写的 C# 程序总是让我感到沮丧。我意识到这不是一个善意的回应,但我非常冒昧地说你很可能是一个精通 Visual Basic 的程序员。因此,我通过在开放性伤口上撒盐(盐是一种消毒剂)向所有熟练的 Visual Basic 程序员提供进一步的机会,你不应该将你在对象引用语言中的编程专业知识转移到面向对象的语言中。正如希腊语或希伯来语等综合逻辑语言的专业演讲者很难适应英语等分析逻辑语言一样,反之亦然。

          其次,您将 myFavouriteMovies 声明为静态的原因是什么?你了解静态变量的含义吗?

          第三,你不应该通过类实例引用“this”来引用静态变量。 myFavouriteMovies 是 Movie 类中的静态变量。因此,您应该将其称为

          Movie.myFavouriteMovies
          

          而不是像

          this.myFavouriteMovies
          

          Java 允许您执行这种异常引用,但 C# 不允许。 “this”应该保留给“instance variables”。

          最后,与其他“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:这个sun论坛主题已归档到 https://community.oracle.com/message/5266256#5266256 这需要一个 oracle 帐户注册才能访问。

          【讨论】: