JavaFX开发Stopwatch秒表应用启动报ClassNotFoundException异常求解决
JavaFX秒表应用ClassNotFoundException异常解决
问题描述
我正在尝试开发一款Stopwatch秒表应用,这是我第一个具备一定规模的Java项目,已经困扰多日,始终遇到相同的运行时异常,无法定位问题根源,恳请各位提供解决建议,十分感谢。以下是项目完整代码及运行时抛出的异常栈信息:
项目代码
TimerStopWatch.java
import java.text.DecimalFormat; import java.util.Optional; import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.event.ActionEvent; import javafx.geometry.Pos; import javafx.scene.Parent; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.Label; import javafx.scene.control.TextInputDialog; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.util.Duration; class TimerStopWatch { private ImageView dialImageView = new ImageView(); private ImageView handImageView = new ImageView(); private String dialImageName = "clockface.png"; private String handImageName = "hand.png"; private Image dialImage = new Image(getClass().getResourceAsStream(dialImageName)); private Image handImage = new Image(getClass().getResourceAsStream(handImageName)); private StackPane analogContainer = new StackPane(); private Text digitalLabel = new Text(); private Text timerLabel = new Text(); private Label championLabel = new Label(); private VBox timeInfoBox = new VBox(); private Label lapTimeLabel = new Label(); private Text record1Label = new Text(); private Text record2Label = new Text(); private Text record3Label = new Text(); private VBox recInfoBox = new VBox(); private HBox infoBox = new HBox(); private Button funcButton = new Button("Record"); private Button recButton = new Button("Start"); private HBox buttonsBox = new HBox(); private GridPane grid = new GridPane(); private double tickTimeInSeconds = 0.01; private double angleDeltaPerSeconds = 6.0; double secondsElapsed = 0; private Timeline timeline; private KeyFrame keyFrame; private String timeInfo = "00:00.00"; private int timerStartTime = 60; private double timerSecondsLeft = 60.00; private int timeUpTag = 0; private Alert notNumbersAlert = new Alert(Alert.AlertType.ERROR,"Insert only integers!", ButtonType.CLOSE); private DecimalFormat dfTimer = new DecimalFormat("#.00"); private DecimalFormat dfRec = new DecimalFormat("00"); private double oldTime = 0.00; private int numberOfRecords = 0; public TimerStopWatch(){ setupTimer(); setupUI(); setupTimeline(); setupButtonAction(); } private void setupTimer(){ TextInputDialog dialog = new TextInputDialog(""); dialog.setTitle("Timer Start Time Set Up"); dialog.setHeaderText("Set up the start time:"); dialog.setContentText("Please set up the start time (Integer):"); boolean legalTime = false; while(!legalTime){ Optional<String> input = dialog.showAndWait(); if(input.isPresent()){ if((input.get().matches("[0-9]+") && input.get().length() > 0 ) == false){ notNumbersAlert.showAndWait(); }else{ timerStartTime = Integer.valueOf(input.get()); legalTime = true; } } } timerSecondsLeft = timerStartTime; } private void setupUI(){ dialImageView.setImage(dialImage); handImageView.setImage(handImage); analogContainer.getChildren().addAll(dialImageView, handImageView); digitalLabel.setText(timeInfo); digitalLabel.setFont(Font.font ("Verdana", 30)); timerLabel.setText("Timer: " + String.valueOf(timerSecondsLeft) + ".00"); timerLabel.setFont(Font.font ("Verdana", 20)); championLabel.setText("Champion: 00:00:00"); championLabel.setFont(Font.font ("Verdana", 20)); lapTimeLabel.setText("Lap Time"); lapTimeLabel.setFont(Font.font ("Verdana", 20)); record1Label.setText("Rec 00 +00:00.00"); record1Label.setFont(Font.font ("Verdana", 18)); record2Label.setText("Rec 00 +00:00.00"); record2Label.setFont(Font.font ("Verdana", 18)); record3Label.setText("Rec 00 +00:00.00"); record3Label.setFont(Font.font ("Verdana", 18)); infoBox.setAlignment(Pos.CENTER); infoBox.setSpacing(20); infoBox.getChildren().addAll(timeInfoBox, recInfoBox); timeInfoBox.setAlignment(Pos.CENTER); timeInfoBox.setSpacing(10); timeInfoBox.getChildren().addAll(digitalLabel, timerLabel, championLabel); recInfoBox.setAlignment(Pos.CENTER); recInfoBox.setSpacing(5); recInfoBox.getChildren().addAll(lapTimeLabel, record1Label, record2Label, record3Label); buttonsBox.setAlignment(Pos.CENTER); buttonsBox.setSpacing(10); buttonsBox.getChildren().addAll(funcButton, recButton); grid.setVgap(30); grid.setHgap(10); grid.setAlignment(Pos.CENTER); grid.add(analogContainer, 0, 0); grid.add(infoBox, 0, 1); grid.add(buttonsBox, 0, 2); } private void setupTimeline(){ if(isRunning()){ timeline.stop(); } keyFrame = new KeyFrame(Duration.millis(tickTimeInSeconds*1000), (ActionEvent event) -> { update(); }); timeline = new Timeline(keyFrame); timeline.setCycleCount(Animation.INDEFINITE); } private void setupButtonAction(){ recButton.setOnAction((ActionEvent event) -> { if(timeline.getStatus() != Animation.Status.RUNNING){ timeline.play(); recButton.setText("Stop"); funcButton.setText("Record"); }else { timeline.stop(); recButton.setText("Start"); funcButton.setText("Reset"); } }); funcButton.setOnAction((ActionEvent event) -> { if(timeline.getStatus() == Animation.Status.RUNNING){ if(timerLabel.getText() != "Time's Up!"){ numberOfRecords++; if(numberOfRecords == 1){ championLabel.setText("Champion: " + getMessage(secondsElapsed)); } if((numberOfRecords % 3) == 1){ record1Label.setText("Rec " + dfRec.format(numberOfRecords) + " +" + getMessage(secondsElapsed - oldTime)); }else if ((numberOfRecords % 3) == 2){ record2Label.setText("Rec " + dfRec.format(numberOfRecords) + " +" + getMessage(secondsElapsed - oldTime)); }else{ record3Label.setText("Rec " + dfRec.format(numberOfRecords) + " +" + getMessage(secondsElapsed - oldTime)); } oldTime = secondsElapsed; }else{ timeUp(); } }else{ reset(); } }); } public void timeUp(){ Alert alert = new Alert(Alert.AlertType.INFORMATION, "Time is up... No more records..."); alert.setTitle("Time is up!!!"); alert.setHeaderText("Alert"); alert.show(); } public void reset(){ secondsElapsed = 0.0; timerSecondsLeft = timerStartTime; handImageView.setRotate(0.0); funcButton.setText("Record"); digitalLabel.setText("00:00:00"); timerLabel.setText("Timer: " + String.valueOf(timerSecondsLeft) + ".00"); championLabel.setText("Champion: 00:00.00"); record1Label.setText("Rec 00 +00:00.00"); record2Label.setText("Rec 00 +00:00.00"); record3Label.setText("Rec 00 +00:00.00"); timeUpTag = 0; numberOfRecords = 0; oldTime = 0.00; } public boolean isRunning(){ if(timeline != null){ if(timeline.getStatus() == Animation.Status.RUNNING){ return true; } } return false; } public void update(){ secondsElapsed += tickTimeInSeconds; double rotation = secondsElapsed * angleDeltaPerSeconds; handImageView.setRotate(rotation); digitalLabel.setText(getMessage(secondsElapsed)); timerSecondsLeft -= tickTimeInSeconds; if(timerSecondsLeft <= 0.0 && timeUpTag == 0){ timerLabel.setText("Time's Up!"); timeUpTag = 1; }else if(timeUpTag == 0){ timerLabel.setText("Timer: " + dfTimer.format(timerSecondsLeft)); } } public String getMessage(double secondsElapsed){ timeInfo = (String.format("%02d:", (int)secondsElapsed/60) + String.format("%02d.", (int)secondsElapsed%60) + String.format("%02d", (int)((secondsElapsed*100)%100))); return timeInfo; } public Double getWidth(){ if(dialImage != null) return dialImage.getWidth(); else return 0.0; } public Double getHeight(){ if(dialImage != null) return dialImage.getHeight(); else return 0.0; } public Parent getRootGrid(){ return grid; } }
StopWatch.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.StackPane; import javafx.stage.Stage; public class StopWatch extends Application { @Override public void start(Stage primaryStage) { TimerStopWatch timerStopWatch = new TimerStopWatch(); Scene scene = new Scene(timerStopWatch.getRootGrid(), timerStopWatch.getWidth() + 200, timerStopWatch.getHeight() + 220); primaryStage.setTitle("Timer Stopwatch"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } }
运行异常信息
Exception in Application start method java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389) at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767) Caused by: java.lang.RuntimeException: Exception in Application start method at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917) at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.NoClassDefFoundError: stopwatch/TimerStopWatch at stopwatch.StopWatch.start(StopWatch.java:24) at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863) at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326) at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) ... 1 more Caused by: java.lang.ClassNotFoundException: stopwatch.TimerStopWatch at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 10 more
解决方案
本次异常为Java类加载失败错误,JVM运行时无法找到预期的stopwatch.TimerStopWatch类,对应解决方法如下:
- 补充包声明:你提供的两份Java代码均未声明包名,但异常栈显示类加载预期的包路径为
stopwatch,直接在两个Java文件的第一行添加package stopwatch;即可对齐类的全限定名。 - 全量重新编译:清理项目旧的编译产物,重新编译整个项目,确保
TimerStopWatch.class文件被正确生成并放置在类路径下的stopwatch目录中。 - 调整类访问权限:如果两个类分属不同包,将
TimerStopWatch的类声明改为public class TimerStopWatch,开放跨包访问权限。
额外注意:解决类加载问题后,还需要确认
clockface.png和hand.png两张图片放置在类路径的根目录下,否则初始化阶段会抛出空指针异常。
内容的提问来源于stack exchange,提问作者Azoros
相关产品推荐
相关产品推荐

