Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/396.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:如何动态重写类的方法(类最终不在类路径中)?_Java_Reflection_Classpath_Openjdk_Nimbus - Fatal编程技术网

Java:如何动态重写类的方法(类最终不在类路径中)?

Java:如何动态重写类的方法(类最终不在类路径中)?,java,reflection,classpath,openjdk,nimbus,Java,Reflection,Classpath,Openjdk,Nimbus,如何动态+有条件地调用类的方法? (类最终在类路径中是而不是) 比方说,我需要类NimbusLookAndFeel,但在某些系统上它不可用(即OpenJDK-6) 因此,我必须能够: 了解类是否可用(在运行时) 如果不是这样,跳过整个过程 如何覆盖动态加载类的方法 (从而创建它的匿名内部子类) 代码示例 public static void setNimbusUI(最终i方法) 抛出不受支持的LookandFeelException{ //NimbusLookAndFeel现在可能可用 UI

如何动态+有条件地调用类的方法?
(类最终在类路径中是而不是

比方说,我需要类
NimbusLookAndFeel
,但在某些系统上它不可用(即
OpenJDK-6

因此,我必须能够:

  • 了解类是否可用(在运行时)
  • 如果不是这样,跳过整个过程
  • 如何覆盖动态加载类的方法 (从而创建它的匿名内部子类)
代码示例
public static void setNimbusUI(最终i方法)
抛出不受支持的LookandFeelException{
//NimbusLookAndFeel现在可能可用
UIManager.setLookAndFeel(新的NimbusLookAndFeel(){
@凌驾
公共UIDefaults getDefaults(){
UIDefaults ret=super.getDefaults();
方法:执行(ret);
返回ret;
}
});
}
编辑

现在,我按照建议编辑了代码,使用try-catch拦截
NoClassDefFoundError
。它失败了。我不知道,是不是OpenJDK的错。我得到了
InvocationTargetException
,这是由
NoClassDefFoundError
引起的。有趣的是,我无法捕获
InvocationTargetException
:它还是被抛出的

EDIT2:

发现原因:我在测试方法周围包装
SwingUtilities.invokeAndWait(…)
,当加载Nimbus失败时,调用
invokeAndWait
抛出
NoClassDefFoundError

EDIT3:

有人能澄清一下哪里会发生NoClassDefFoundError吗?因为似乎总是调用方法,而不是使用不存在的类的实际方法。

您可以使用类来实现这一点

即:


如果在当前类路径上找不到,上面的句子将抛出ClassNotFoundException。如果未引发异常,则可以使用
c
中的
newInstance()
方法创建your.package.YourClass类的对象。如果需要调用特定的构造函数,可以使用
getConstructors
方法获取一个构造函数,并使用它创建一个新实例。

使用BCEL动态生成动态子类


呃,您不能将要扩展的类放入编译时类路径中,像往常一样编写子类,并在运行时显式触发加载子类,并处理链接器引发的任何异常以指示缺少超类吗?

了解该类是否可用(在运行时)
将用法放入try块中

如果不是这样,请跳过整件事
... 并将捕捉块留空(代码气味?!)

如何覆盖动态加载类的方法
只要这样做,并确保编译时依赖关系得到满足。你把事情搞混了。重写发生在编译时,而类加载是运行时的事情

为了完整性,您编写的每个类都会在需要时由运行时环境动态加载

因此,您的代码可能如下所示:

public static void setNimbusUI(final IMethod<UIDefaults> method)
    throws UnsupportedLookAndFeelException {

    try {
        // NimbusLookAndFeel may be now available
        UIManager.setLookAndFeel(new NimbusLookAndFeel() {

            @Override
            public UIDefaults getDefaults() {
                final UIDefaults defaults = super.getDefaults();
                method.perform(defaults);
                return defaults;
            }

        });
   } catch (NoClassDefFoundError e) {
       throw new UnsupportedLookAndFeelException(e);
   }
}
public static void setNimbusUI(最终i方法)
抛出不受支持的LookandFeelException{
试一试{
//NimbusLookAndFeel现在可能可用
UIManager.setLookAndFeel(新的NimbusLookAndFeel(){
@凌驾
公共UIDefaults getDefaults(){
最终UIDefaults=super.getDefaults();
方法。执行(默认值);
返回默认值;
}
});
}捕获(NoClassDefFounde错误){
抛出新的不受支持的LookandFeelException(e);
}
}

以下代码应该可以解决您的问题。
Main
类模拟您的主类。类
A
模拟要扩展的基类(并且您无法控制)。Class
B
是Class
A
的派生类。接口
C
模拟Java没有的“函数指针”功能。让我们先看看代码

下面是class
A
,您想要扩展的类,但无法控制:


/* src/packageA/A.java */

package packageA;

public class A {
    public A() {
    }

    public void doSomething(String s) {
        System.out.println("This is from packageA.A: " + s);
    }
}
下面是class
B
,虚拟派生类。请注意,由于它扩展了
A
,因此必须导入
packageA.A
,并且类
A
必须在类
B
的编译时可用。带有参数C的构造函数是必需的,但实现接口
C
是可选的。如果
B
实现了
C
,则可以方便地直接(无反射)调用
B
实例上的方法。在
B.doSomething()
中,调用
super.doSomething()
是可选的,这取决于您是否需要,但调用
c.doSomething()
是必需的(如下所述):

下面是棘手的界面
C
。只需将所有要重写的方法放入此接口:


/* src/packageC/C.java */

package packageC;

public interface C {
    public void doSomething(String s);
}
以下是主要课程:


/* src/Main.java */

import packageC.C;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Main {
    public static void main(String[] args) {
        doSomethingWithB("Hello");
    }

    public static void doSomethingWithB(final String t) {
        Class classB = null;
        try {
            Class classA = Class.forName("packageA.A");
            classB = Class.forName("packageB.B");
        } catch (ClassNotFoundException e) {
            System.out.println("packageA.A not found. Go without it!");
        }

        Constructor constructorB = null;
        if (classB != null) {
            try {
                constructorB = classB.getConstructor(C.class);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }

        C objectB = null;
        if (constructorB != null) {
            try {
                objectB = (C) constructorB.newInstance(new C() {
                    public void doSomething(String s) {
                        System.out.println("This is from anonymous inner class: " + t);
                    }
                });
            } catch (ClassCastException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }

        if (objectB != null) {
            objectB.doSomething("World");
        }
    }
}
它为什么编译并运行?
您可以看到在
Main
类中,只导入了
packageC.C
,没有对
packageA.A
packageB.B
的引用。如果存在任何异常,则当类加载器尝试加载其中一个时,它将在没有
packageA.A
的平台上引发异常

它是如何工作的?
在第一个
Class.forName()
中,它检查平台上是否有Class
A
。如果是,请让类加载器加载类
B
,并将生成的
class
对象存储在
classB
中。否则,
ClassNotFou

/* src/packageB/B.java */

package packageB;

import packageA.A;
import packageC.C;

public class B extends A implements C {
    private C c;

    public B(C c) {
        super();
        this.c = c;
    }

    @Override
    public void doSomething(String s) {
        super.doSomething(s);
        c.doSomething(s);
    }
}

/* src/packageC/C.java */

package packageC;

public interface C {
    public void doSomething(String s);
}

/* src/Main.java */

import packageC.C;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Main {
    public static void main(String[] args) {
        doSomethingWithB("Hello");
    }

    public static void doSomethingWithB(final String t) {
        Class classB = null;
        try {
            Class classA = Class.forName("packageA.A");
            classB = Class.forName("packageB.B");
        } catch (ClassNotFoundException e) {
            System.out.println("packageA.A not found. Go without it!");
        }

        Constructor constructorB = null;
        if (classB != null) {
            try {
                constructorB = classB.getConstructor(C.class);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }

        C objectB = null;
        if (constructorB != null) {
            try {
                objectB = (C) constructorB.newInstance(new C() {
                    public void doSomething(String s) {
                        System.out.println("This is from anonymous inner class: " + t);
                    }
                });
            } catch (ClassCastException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }

        if (objectB != null) {
            objectB.doSomething("World");
        }
    }
}

    @Override
    public void doSomething(String s) {
        super.doSomething1(s);
        c.doSomethingAfter1(s);
        super.doSomething2(s);
        c.doSomethingAfter2(s);
    }
$ mkdir classes $ $ $ $ javac -cp src -d classes src/Main.java $ java -cp classes Main packageA.A not found. Go without it! $ $ $ $ javac -cp src -d classes src/packageB/B.java $ java -cp classes Main This is from packageA.A: World This is from anonymous inner class: Hello