A friend of mine asked me, if there was any way to extend the String
class in Java. The usual answer would be no, because the String
class is final, but I tried to play around with the sun.misc.Unsafe
class, to achieve this.
My idea was to modify the String
class and remove the final flag, and then compile a class extending String
at runtime. I was able to remove the final flag, but compilation of the new class resulted in a JVM crash. Is there any way to fix this? Is there any other way to achieve what I am trying todo, without additional JVM parameters? Would it maybe be possible to load a class not extending String, and later add the 'extends String' to the class signature?
The code I am using:
public static void main(String[] args) throws Exception {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
Class cs = String.class;
long offset = 72;//http://ift.tt/2qXRft3
unsafe.putShort(cs, offset, (short) (unsafe.getShort(cs, offset) & ~Modifier.FINAL));
if((String.class.getModifiers() & Modifier.FINAL) != 0) {
System.out.println("Class is final!");
System.exit(0);
}
else {
System.out.println("Class is not final");
}
File file = new File("StringExtend.java");
Class c = compile(file);
System.out.println(c.newInstance());
}
public static Class compile(File file) {
try {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
List<String> optionList = new ArrayList<>();
boolean success;
try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
Iterable<? extends JavaFileObject> units;
units = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(file));
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, optionList, null, units);
success = task.call();
}
if (success) {
return load(new File(file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - 5) + ".class"));
} else {
return null;
}
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
private static Class load(File file) {
try {
URL url = new File(file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - file.getName().length())).toURI().toURL();
ClassLoader cl = new URLClassLoader(new URL[]{url}, RuntimeCompiler.class.getClassLoader());
Class c = cl.loadClass(file.getName().substring(0, file.getName().length() - 6));
return c;
} catch (MalformedURLException | ClassNotFoundException ex) {
ex.printStackTrace();
return null;
}
}
StringExtend.java
public class StringExtend extends String {
public boolean equals(Object o) {
return true;
}
}
Aucun commentaire:
Enregistrer un commentaire