23
java -classpath ../classes;../jar;. parserTester

如何以编程方式获取上述命令中的功能?像,是否可以运行为:

java parserTester

并得到相同的结果?我尝试使用 URLClassLoader 但它修改了类路径并且没有添加到它。

谢谢!


感谢米尔豪斯的回复。但这就是我想要做的.. 怎么可能首先将 jar 放入类路径?我也尝试使用自定义类加载器:(

那行得通..但很抱歉我只需要运行它:java parserTester 我想知道这样的事情是否可能???

它必须如此,因为我在一个单独的文件夹中有 parserTester.java 和 .class。我需要保留文件结构。parserTester 在单独的 jar 文件夹中使用 jar。

4

7 回答 7

22

您可以使用 java.net.URLClassLoader 使用您希望的任何程序定义的 URL 列表加载类:

公共类 URLClassLoader 扩展 SecureClassLoader

此类加载器用于从引用 JAR 文件和目录的 URL 的搜索路径加载类和资源。假设任何以“/”结尾的 URL 都指向一个目录。否则,假定 URL 引用将根据需要打开的 JAR 文件。

创建 URLClassLoader 实例的线程的 AccessControlContext 将在随后加载类和资源时使用。

默认情况下,加载的类仅被授予访问在创建 URLClassLoader 时指定的 URL 的权限。

自:1.2

一点花哨的步法可以扩展它以支持使用通配符路径名来获取 JAR 的整个目录(这段代码有一些实用方法的引用,但它们的实现在上下文中应该是显而易见的):

/**
 * Add classPath to this loader's classpath.
 * <p>
 * The classpath may contain elements that include a generic file base name.  A generic basename
 * is a filename without the extension that may begin and/or end with an asterisk.  Use of the
 * asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match
 * the specified basename will be added to this class loaders classpath.  The case of the filename is ignored.
 * For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*"
 * means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files
 * that contain "abc" and end with ".jar".
 *
 */
public void addClassPath(String cp) {
    String                              seps=File.pathSeparator;                // separators

    if(!File.pathSeparator.equals(";")) { seps+=";"; }                          // want to accept both system separator and ';'
    for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens(); ) {
        String pe=st.nextToken();
        File   fe;
        String bn=null;

        if(pe.length()==0) { continue; }

        fe=new File(pe);
        if(fe.getName().indexOf('*')!=-1) {
            bn=fe.getName();
            fe=fe.getParentFile();
            }

        if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\\') { fe=new File(rootPath,fe.getPath()); }
        try { fe=fe.getCanonicalFile(); }
        catch(IOException thr) {
            log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+").");
            continue;
            }
        if(!GenUtil.isBlank(bn)) {
            fe=new File(fe,bn);
            }
        if(classPathElements.contains(fe.getPath())) {
            log.diagln("Skipping duplicate classpath element '"+fe+"'.");
            continue;
            }
        else {
            classPathElements.add(fe.getPath());
            }

        if(!GenUtil.isBlank(bn)) {
            addJars(fe.getParentFile(),bn);
            }
        else if(!fe.exists()) {                                                 // s/never be due getCanonicalFile() above
            log.diagln("Could not find classpath element '"+fe+"'");
            }
        else if(fe.isDirectory()) {
            addURL(createUrl(fe));
            }
        else if(fe.getName().toLowerCase().endsWith(".zip") || fe.getName().toLowerCase().endsWith(".jar")) {
            addURL(createUrl(fe));
            }
        else {
            log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.zip' or '.jar'");
            }
        }
    log.diagln("Class loader is using classpath: \""+classPath+"\".");
    }

/**
 * Adds a set of JAR files using a generic base name to this loader's classpath.  See @link:addClassPath(String) for
 * details of the generic base name.
 */
public void addJars(File dir, String nam) {
    String[]                            jars;                                   // matching jar files

    if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); }

    if(!dir.exists()) {
        log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }
    if(!dir.canRead()) {
        log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'");
        return;
        }

    FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true);
    if((jars=dir.list(fs))==null) {
        log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'");
        }
    else if(jars.length==0) {
        log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'");
        }
    else {
        log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'");
        Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER);
        for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); }
        }
    }

private URL createUrl(File fe) {
    try {
        URL url=fe.toURI().toURL();
        log.diagln("Added URL: '"+url.toString()+"'");
        if(classPath.length()>0) { classPath+=File.pathSeparator; }
        this.classPath+=fe.getPath();
        return url;
        }
    catch(MalformedURLException thr) {
        log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL");
        return null;
        }
    }
于 2008-12-31T08:55:51.697 回答
1

我必须同意其他两张海报,听起来你让测试课变得过于复杂。将 .java 和 .class 文件放在单独的文件夹中,而在第三个文件夹中依赖于 jar 文件,而无需以编程方式更改类路径,这并不罕见。如果您这样做是因为您不想每次都在命令行上键入类路径,我建议您使用 shell 脚本或批处理文件。更好的是,一个 IDE。我真正遇到的问题是,您为什么要尝试在代码中管理类路径?

于 2008-12-31T06:32:17.197 回答
0

您可以编写批处理文件或 shell 脚本文件来导出类路径并运行 java 程序。在 Windows 中,

set classpath=%classpath%;../classes;../jars/* java ParserTester

在 Unix 中,导出 classpath=%classpath%:../classes:../jars/* java ParserTester

如果您将文件名命名为 parser.bat 或 parser.sh,您可以通过在相应操作系统中调用 parser 来运行它。

从 java 1.6 开始,您可以通过说 /* 将目录中的所有 jar 包含到类路径中

如果您尝试动态生成 java 文件,请编译并添加到类路径中,请事先在类路径中设置生成类文件的目录。它应该加载类。如果你正在修改已经生成的java类,基本上是修改后重新编译,如果你想加载新的类,你需要使用你的自定义类加载器来避免类的缓存。

于 2008-12-31T07:21:34.680 回答
0

您可以实现自己的类加载器,但该类/jar 必须在类路径中才能执行。

尝试

java -cp *.jar:. myClass

或者

export CLASSPATH=./lib/tool.jar:.
java myClass

或者

java -jar file.jar
于 2008-12-31T04:56:05.643 回答
0

我认为您想要的是“执行包装器”或特定于平台的“启动器”...通常此组件用于检测您的操作系统和体系结构以及依赖项,然后在启动应用程序之前进行调整。这是一种老式的设计模式(80 年代或更早),但今天仍然被大量使用。这个想法是您的程序可以与系统和环境无关,启动器将做好准备并告诉软件它需要知道的一切。许多现代开源程序使用 Shell 脚本和批处理文件等来执行此操作……例如 Apache Tomcat。您可以轻松地在 java 中制作包装器,并让它使用命令行 exec 启动软件(确保在 *NIX 中的 exec 命令末尾添加“&”,以便您的包装器可以退出,只留下您的软件运行。 . . 还可以让您在不终止进程的情况下关闭 shell 窗口)

于 2011-06-27T13:43:28.530 回答
-1

我理解对了吗?!你有它的唯一原因是你想在不指定类路径的情况下启动你的类并在运行时加载它?...

java parserTester

代替

java -classpath ../classes;../jar;. 解析器测试器

可能我没有得到你的理由。但是,如果“这就是”您想要的,您可以执行以下操作(尽管对我来说没有多大意义)

  • 开课
  • 从 main 方法 lauch 另一个类以编程方式在那里设置类路径。
  • 历史的终结。

类似于以下“java -pseudo code”

public static void main( String [] args ) {
    String classpath = "classes;../jar";
    Runtime.getRuntime().execute("java + classpath + " parserTester ");
}

如果我做对了,请告诉我。如果您想做其他事情,我很乐意提供帮助。

于 2008-12-31T06:17:37.463 回答
-2

优秀的好帖子,就我而言,我这样做是为了很好地工作(注意:特定于 Windows):

set classpath=%classpath%;../lib/*
java -cp %classpath% com.test.MyClass 
于 2011-03-31T15:53:35.747 回答