gpt4 book ai didi

Java:为什么打包成jar文件的代码会阻止外部类访问?

转载 作者:行者123 更新时间:2023-12-01 17:30:49 25 4
gpt4 key购买 nike

我的 Java 应用程序有一个插件系统。我使用 URL 类加载器调用外部类。无论是当我的应用程序作为类文件运行时,还是当我的应用程序采用 JAR 形式时,该部分都运行良好。我遇到的问题是,插件文件可以很好地运行自己的独立代码,但它们创建了一个 JPanel。当我尝试将该 JPanel 添加到主应用程序类中的 JPanel 时,出现引用主类的空指针异常。 (com.cpcookieman.app.Main) 但是,如果我运行应用程序的类文件,只有在打包时,这种情况就不会发生。我该如何解决这个问题?

为什么我的代码打包到 jar 文件中会阻止外部类访问 jar 内的类?

编辑:根据要求,堆栈跟踪。

java.lang.NullPointerException
at TestPlugin2.Main.<init>(Main.java:23)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at com.cpcookieman.ph.PluginLoader$2.run(PluginLoader.java:74)
at java.lang.Thread.run(Unknown Source)

编辑2:类加载代码

    String pluginsPath;
if (Main.os.equals("Windows"))
{
pluginsPath = "C:\\plugins\\";
}
else
{
pluginsPath = "~/plugins/";
}
File file = new File(pluginsPath);
if (!file.exists())
{
System.out.println("DEBUG: Plugin path could not be found!");
}
try
{
URL url = file.toURI().toURL();
final URL[] urls = new URL[]{url};
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
ClassLoader cl = new URLClassLoader(urls);
Class plugin = cl.loadClass(text + ".Main");
plugin.newInstance();
close();
}
**snip catch statements**
}
}).start();
}
**snip catch statements**

该插件使用其构造函数加载,并创建一个要添加到 JAR 文件内的类之一内的框架的面板。如果有人对此感到困惑,JAR 是主要应用程序。

最佳答案

我确实不知道你的项目结构,不过我做了一个小示例代码给你看,你看一下。

考虑我的项目位于 C:\Mine\JAVA\J2SE\src\testingjar>

其中我的目录结构如下:

                         testingjar
|
----------------------------------
| | | |
classes src manifest.text test.jar(this .jar we be creating shortly)
| |
| (Almost same as classes folder, just .java files)
---------------
| |
actualtest test
| |
*.class *.class

我的类将成为 .jar 文件的一部分,如下所示:

package test;

import java.awt.*;
import javax.swing.*;

public class CustomPanel extends JPanel
{
public CustomPanel()
{
setOpaque(true);
setBackground(Color.DARK_GRAY);

JLabel label = new JLabel(
"I am a JLabel from Java Swing", JLabel.CENTER);
label.setOpaque(false);
label.setForeground(Color.WHITE);
add(label);
}

@Override
public Dimension getPreferredSize()
{
return (new Dimension(500, 300));
}
}

我使用以下命令编译了这个类:

C:\Mine\JAVA\J2SE\src\testingjar>javac -d classes src\test\CustomPanel.java

现在为JAR文件创建Manifest文件,其内容如下:

Main-Class: test.CustomPanel

请记住冒号 (:) 和包名称之间的空格,即 test,然后在 CustomPanel 后按 Enter 并保存文件。

现在创建一个名为 test.jar 的 JAR 文件,我写了这些命令:

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>jar -cfm ..\test.jar ..\manifest.txt test

现在将使用此 .jar 文件的类将如下所示:

package actualtest;

import test.CustomPanel;

import java.awt.*;
import javax.swing.*;

public class ActualImplementation
{
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Testing Jar Implementation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

CustomPanel panel = new CustomPanel();
frame.setContentPane(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ActualImplementation().createAndDisplayGUI();
}
});
}
}

我通过编写这些命令来编译它:

C:\Mine\JAVA\J2SE\src\testingjar\classes>cd..

C:\Mine\JAVA\J2SE\src\testingjar>javac -classpath test.jar -d classes src\actualtest\ActualImplement
ation.java

现在要运行我编写了这些命令:

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>java actualtest.ActualImplementation

输出

JAR IMPLEMENTATION

一定要符合步骤,可能你会遗漏一些东西,因为它在我这边工作得很好。

最新编辑:按照要求,我以相反的方式做了,现在 JFrame位于 .jar 文件内且 JPanel正在使用它。

将成为 .jar 文件一部分的类如下:

package test;

import java.awt.*;
import javax.swing.*;

public class CustomFrame extends JFrame
{
public CustomFrame(String title)
{
super(title);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}

manifest.txt 文件的内容将更改如下:

Main-Class: test.CustomFrame

将使用 .jar 文件中的 CustomFrame 类的类如下:

package actualtest;

import test.CustomFrame;

import java.awt.*;
import javax.swing.*;


// http://stackoverflow.com/a/11150286/1057230
public class CustomPanel extends JPanel
{
private CustomFrame frame;

public CustomPanel()
{
setOpaque(true);
setBackground(Color.DARK_GRAY);

JLabel label = new JLabel(
"I am a JLabel from Java Swing", JLabel.CENTER);
label.setOpaque(false);
label.setForeground(Color.WHITE);
add(label);
}

private void createAndDisplayGUI()
{
frame = new CustomFrame("Testing Jar Implementation");
frame.setContentPane(this);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

@Override
public Dimension getPreferredSize()
{
return (new Dimension(500, 300));
}

public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new CustomPanel().createAndDisplayGUI();
}
});
}
}

编译顺序与之前非常相似,如下:

C:\Mine\JAVA\J2SE\src\testingjar>javac -d classes src\test\CustomFrame.java

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>jar -cfm ..\test.jar ..\manifest.txt test

C:\Mine\JAVA\J2SE\src\testingjar\classes>cd..

C:\Mine\JAVA\J2SE\src\testingjar>javac -classpath test.jar -d classes src\actualtest\CustomPanel.jav
a

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>java actualtest.CustomPanel

我得到的输出仍然相同。

最新编辑:

我刚刚发现,有时这个东西可以工作,而不是后来,当使用 JAR 文件时,你必须指定包含点运算符的类路径 . ,就像

C:\Mine\JAVA\J2SE\src\testingjar>java -classpath test.jar;.; actualtest.CustomPanel

这是我带来actualtest的时候package里面testingjar文件夹,那么上面的命令适用于这种情况。

关于Java:为什么打包成jar文件的代码会阻止外部类访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11149895/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com