在不修改类本身的情况下实例化Paradox类的任何想法?
public final class Paradox {
private final Paradox paradox;
public Paradox(Paradox paradox) {
this.paradox = paradox;
if (this.paradox == null) throw new InceptionException();
}
private static class InceptionException extends RuntimeException {
public InceptionException() {
super("Paradox requires an instance of paradox to be instantiated");
}
}
}
答案 0 :(得分:16)
正如评论中已经指出的那样:可以使用<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas"></div>
类:
sun.misc.Unsafe
或者,可以使用JNI function AllocObject
,它也可以在不调用任何构造函数的情况下分配新对象。
编辑:Someone found another solution - 没有
import java.lang.reflect.Constructor; import sun.misc.Unsafe; public class ParadoxTest { public static void main(String[] args) throws Exception { Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor(); unsafeConstructor.setAccessible(true); Unsafe unsafe = unsafeConstructor.newInstance(); Paradox paradox = (Paradox) unsafe.allocateInstance(Paradox.class); System.out.println("This is paradox: "+paradox); } }
!EDIT2:但请注意,此解决方案还使用了Sun专有类,它们是不公共API的一部分,所以此解决方案仍然不可移植并且应该< strong>不用于生产代码!
sun.misc.Unsafe
EDIT3:仅为了完整性,并在评论中按要求:基于JNI的解决方案
如上所述,JNI function AllocObject
不会调用构造函数,因此这也可用于实例化此类对象。这是包含本机方法并加载本机库的调用类:
import java.lang.reflect.Constructor;
import sun.reflect.ReflectionFactory;
public class AnotherParadoxTest
{
public static void main(String[] args) throws Exception
{
ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
Constructor<?> declaredConstructor =
Object.class.getDeclaredConstructor();
Constructor<?> constructor = rf.newConstructorForSerialization(
Paradox.class, declaredConstructor);
Paradox paradox = (Paradox) constructor.newInstance();
System.out.println("This is paradox: "+paradox);
}
}
使用public class ParadoxTestWithJni
{
static
{
System.loadLibrary("Paradox");
}
public static void main(String[] args)
{
Paradox paradox = createParadox();
System.out.println("This is paradox: "+paradox);
}
private native static Paradox createParadox();
}
为此类创建的标头ParadoxTestWithJni.h
:
javah
相应的实施......“魔术发生的地方”:
#include <jni.h>
#ifndef _Included_ParadoxTestWithJni
#define _Included_ParadoxTestWithJni
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jobject JNICALL Java_ParadoxTestWithJni_createParadox
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
答案 1 :(得分:13)
让我们说Paradox
类在包test
中,就像这样(当然它可以在默认包中,但问题并没有真正指定它):
package test;
public final class Paradox {
private final Paradox paradox;
public Paradox(Paradox paradox) {
this.paradox = paradox;
if (this.paradox == null) throw new InceptionException();
}
private static class InceptionException extends RuntimeException {
public InceptionException() {
super("Paradox requires an instance of paradox to be instantiated");
}
}
}
该类的XML表示(如果已由XStream序列化)将如下所示:
<test.Paradox/>
鉴于此XML,可以在不调用构造函数的情况下对其进行反序列化:
public static void main(String[] args) {
XStream xstream = new XStream(new DomDriver());
Paradox paradoxFromXml = (Paradox) xstream.fromXML("<test.Paradox/>");
System.out.println(paradoxFromXml);
}
输出结果为:
test.Paradox@72d818d1
这个答案充分利用了XStream在反序列化期间不会调用构造函数的事实,如FAQ中所述:
在反序列化期间,XStream没有调用默认构造函数。
事实上,这与上述情况相同。 XStream使用与JDK序列化相同的机制。使用带有优化反射API的增强模式时,它不会调用默认构造函数。解决方案是实现readResolve或readObject,如上一个问题所示。
因此,通过使用XStream默认的直接XML表示,可以通过反序列化来初始化类,尽管该类不可序列化。
作为对此的进一步解释,在这种情况下,XStream可能使用SunLimitedUnsafeReflectionProvider
或SunUnsafeReflectionProvider
来初始化类,内部使用sun.misc.Unsafe
作为其Javadoc状态(感谢{{ 3}}用于指出这一点):
<强> SunLimitedUnsafeReflectionProvider
强>
/**
* Instantiates a new object bypassing the constructor using undocumented internal JDK features.
* <p>
* The code in the constructor will never be executed and parameters do not have to be known. This is the same method
* used by the internals of standard Java serialization, but relies on internal code (sun.misc.Unsafe) that may not be
* present on all JVMs.
* <p>
* <p>
* The implementation will use standard Java functionality to write any fields. This requires Java 5 as minimum runtime
* and is used as fallback on platforms that do not provide the complete implementation level for the internals (like
* Dalvik).
* <p>
*
* @author Jörg Schaible
* @author Joe Walnes
* @author Brian Slesinsky
* @since 1.4.7
*/
<强> SunUnsafeReflectionProvider
强>:
/**
* Instantiates a new object bypassing the constructor using undocumented internal JDK features.
* <p>
* The code in the constructor will never be executed and parameters do not have to be known. This is the same method
* used by the internals of standard Java serialization, but relies on internal code (sun.misc.Unsafe) that may not be
* present on all JVMs.
* <p>
* <p>
* The implementation will use the same internals to write into fields. This is a lot faster and was additionally the
* only possibility to set final fields prior to Java 5.
* <p>
*
* @author Joe Walnes
* @author Brian Slesinsky
* @author Jörg Schaible
* @since 1.4.7
*/
老实说,我只记得XStream有能力在没有调用构造函数的情况下初始化对象,而没有时间回答问题以进一步挖掘它。