I found a scenario where java program behaves differently after renaming a variable. I understand this isn't actually code that anyone would use but if someone knows whats going on it would be nice to have an explanation. I tried this with java 1.6 on Eclipse Kepler.
package _test;
public class TestClass{
public static void main(String...args){
Object testClazz$1 = new Object (){
public String toString() {
return "hello";
}
};
TestClass$1 test = new TestClass$1();
System.out.println(testClazz$1.toString());
test.doStuff();
}
}
class TestClass$1{
public void doStuff(){
System.out.println("hello2");
}
}
This outputs:
hello
Exception in thread "main" java.lang.NoSuchMethodError:
_test.TestClass$1.doStuff()V at _test.TestClass.main(TestClass.java:13)
As far as I understand the compiler creates a TestClass$1.class file for the testClazz$1 object and this causes a naming collision.
But after renaming the object to testClass$1:
package _test;
public class TestClass{
public static void main(String...args){
Object testClass$1 = new Object (){
public String toString() {
return "hello";
}
};
TestClass$1 test = new TestClass$1();
System.out.println(testClass$1.toString());
test.doStuff();
}
}
class TestClass$1{
public void doStuff(){
System.out.println("hello2");
}
}
The output is:
_test.TestClass$1#2e6e1408
hello2
Any ideas what is going on here?
Anonymous classes are named automatically by appending a $ sign and an increasing number to the name of the enclosing class.
In your first example the anoymous class will be named TestClass$1 which has no doStuff() method, you only override toString() that's why you get NoSuchMethodError error.
In your 2nd example you already have a local variable named TestClass$1, so the auto-generated name chosen by the compiler will be a different name, most likely TestClass$2. Since you instantiate TestClass$1 which is not an anonymous class but a class explicitly defined by you, that will be instantiated which has a doStuff() method which properly prints "hello2" and which does not override Object.toString() so printing the value returned by its toString() method will print the default value as specified in java.lang.Ojbect (which is the class name appended with a # sign followed by the default hash code in hexadecimal format).
Conclusion: While this is an interesting example, you should never use the $ sign in your class names and in identifier names.
When the classloader encounters the anonymous Object() {...} class it loads it under the name TestClass$1. This creates a conflict with class TestClass$1 {...} which was explicitly defined.
However, class name conflicts are handled rather ungracefully. This bit of documentation tells us that
If the class c has already been linked, then this method simply returns.
That's what happens in your case. You only ever load one of the two TestClass$1 classes.
The "different variable names" are not responsible for anything other than re-compiling and re-linking within your compiler. At this point, the classloader is free to pick whichever one of the two TestClass$1 likes better and use that everywhere.
If you're using something like eclipse (like I am) then your bytecode will get cached, until a new touch operation on the source file (and updating of timestamps...). Here's what I did to reproduce (running openjdk 1.7, Eclipse Kepler under RedHat):
Put this inside a source file TestClass.java:
package javaclasses.classes;
public class TestClass{
public static void main(String...args){
Object o = new Object (){
public String toString() {
return "hello";
}
};
TestClass$1 test = new TestClass$1();
System.out.println(o.toString());
test.doStuff();
}
}
class TestClass$1{
public void doStuff(){
System.out.println("hello2");
}
}
ctrl + F11 outputs:
javaclasses.classes.TestClass$1#42293b53
hello2
Open this in a console and touch TestClass.java
Go back in eclipse and ctrl + F11 now outputs:
hello
Exception in thread "main" java.lang.NoSuchMethodError: javaclasses.classes.TestClass$1.doStuff()V
at javaclasses.classes.TestClass.main(TestClass.java:13)
Conlusion: All that can be said definitively is that the default ClassLoader is unreliable for manually resolving classes with the same fully qualified names. Changing variable names doesn't matter, the updated timestamp on your source file does.
I modified your code to remove the "$" from the class names and renamed testClass$1 to t and changed the println slightly as follows:
public class TestClass{
public static void main(String...args){
Object t = new Object (){
public String toString() {
return "t.toString()";
}
};
TestClass1 tc1 = new TestClass1();
System.out.println(t.toString());
tc1.doStuff();
}
}
class TestClass1{
public void doStuff(){
System.out.println("TestClass1.doStuff()");
}
}
Output is now:
t.toString()
TestClass1.doStuff()
Is this what you expect?
Related
This is a question from this book: https://www.cl.cam.ac.uk/teaching/0506/ConcSys/cs_a-2005.pdf page 28
Can you write an additional Java class which creates an
object that, when passed to the test method causes it to
print “Here!”? As I say in the code, editing the class A
itself, or using library features like reflection, serialization,
or native methods are considered cheating! I’ll provide
some hints in lectures if nobody can spot it in a week or
so. None of the PhD students has got it yet.
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof A) {
System.out.println("Here!");
}
}
}
I know the question is a lot unclear. I can think of many different 'hack-ish' solutions but not sure if they will be counted as 'cheating' or not :)
I can't find the official answer so asking you for what would be a good answer.
If we consider that nesting class A does not "modify it" (as, technically, all lines of code are intact) then this solution is probably the only valid option:
class B
{
static
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof A) {
System.out.println("Here!");
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
A.test(new A());
}
}
What I mean is, technically it follows all the rules:
Can you write an additional Java class which creates an object that, when passed to the test method causes it to print “Here!”? - Done
As I say in the code, editing the class A itself ... considered cheating! - Technically, the class is unedited. I copy pasted it into my code.
... or using library features like reflection, serialization, or native methods are considered cheating! - Done
If, however, you decide that nesting class A should not be allowed, then I believe there is no proper solution to the problem given the current definition. Also, given the section of the book this task is given in, I bet that the author wanted to make the constructor protected but not private.
Somehow, I don't like this sort of questions. It's from a lecture back in 2005, and according to websearches, it seems that nobody has found "the" solution until now, and no solution has been published.
The constraints are clear, but the question of what is allowed or not is somewhat fuzzy. Every solution could be considered as "cheating", in one or the other way, because a class with a private constructor is not meant to be subclassed. That's a critical security mechanism, and the responsible engineers are working hard to make sure that this security mechanism cannot be trivially circumvented.
So of course, you have to cheat in order to solve this.
Nevertheless, I spent quite a while with this, and here's how I eventually cheated it:
1.) Download the Apache Bytecode Engineering Library, and place the bcel-6.0.jar in one directory.
2.) Create a file CreateB.java in the same directory, with the following contents:
import java.io.FileOutputStream;
import org.apache.bcel.Const;
import org.apache.bcel.generic.*;
public class CreateB
{
public static void main(String[] args) throws Exception
{
ClassGen cg = new ClassGen("B", "A", "B.java",
Const.ACC_PUBLIC | Const.ACC_SUPER, new String[] {});
ConstantPoolGen cp = cg.getConstantPool();
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(Const.ACC_PUBLIC, Type.VOID,
Type.NO_ARGS, new String[] {}, "<init>", "B", il, cp);
il.append(InstructionFactory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
cg.getJavaClass().dump(new FileOutputStream("B.class"));
}
}
3.) Compile and execute this class:
javac -cp .;bcel-6.0.jar CreateB.java
java -cp .;bcel-6.0.jar CreateB
(note: On linux, the ; must be a :). The result will be a file B.class.
4.) Copy the class that was given in the question (verbatim - without any modification) into the same directory and compile it.
5.) Create the following class in the same directory, and compile it:
public class TestA
{
public static void main(String[] args)
{
A.test(new B());
}
}
6.) The crucial step: Call
java -Xverify:none TestA
The output will be Here!.
The key point is that the CreateB class creates a class B that extends A, but does not invoke the super constructor. (Note that an implicit super constructor invocation would normally be added by the compiler. But there's no compiler involved here. The bytecode is created manually). All this would usually fail with a VerifyError when the class is loaded, but this verification can be switched off with -Xverify:none.
So in summary:
The class A itself is not edited (and also its byte code is not edited, I hope this is clear!)
No reflection
No serialization
No custom native methods
There are a few options here:
Create a class:
public class Y extends A {
public static void main(String[] args) throws Exception {
X.test(new Y());
}
}
And then edit the bytecode and remove the call to X.. Of course this violates the JVM specification and has to be run with -Xverify:none as said above. This is essentially the same as the one #Marco13.
Option 2:
import sun.misc.Unsafe;
public class Y extends A {
public static void main(String[] args) throws Exception {
Unsafe uf = Unsafe.getUnsafe();
X.test((X) uf.allocateInstance(X.class));
}
}
Compile the code and run it by putting your classpath in the sysloader (otherwise it won't work):
$ java -Xbootclasspath/p:. Y
Both work for me :) Of course, they are both cheating. The first option isn't Java. The second is, well, evil :)
If I find out another way, I'll post it :)
In any case this can't be done without low-level tricks. The JVM Specification explicitly prohibits the creation of an object without calling the constructor as the object in the stack is uninitialized. And the JVM Specification explicitly prohibits not calling the super constructor. And the JVM Specification explicitly requires verification of access protection.
Still funny, though :)
Java can support unicode class name:)
The A in "if (o instanceof A)" could be different from the A in "public class A"
For example, the code below will print "Here!" instead of "bad".
A.java
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
// A: U+0041
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof А) {
System.out.println("Here!");
}
}
}
А.java
public class А {
// A: U+0410, not A: U+0041
}
Main.java
public class Main {
public static void main(String[] args) {
A.test(new А());
}
}
I currently have two constructors in one of my classes, one going to my main class, and the other to another class that has most of the methods that I use. The reason I don't use static methods for my second class that I have a constructor, is that I don't want the code to be used by any other source, just mine. Here are the two constructors:
PrisonProfessionalMain plugin;
public PPCommandAdminMenu(PrisonProfessionalMain instance)
{
plugin = instance;
}
QuickMethods qm;
public PPCommandAdminMenu(QuickMethods instance)
{
qm = instance;
}
Then I am calling a method from the QuickMethods class here:
qm.getConfigString(plugin, "prefix")
Apparently, whatever method I call from this class it returns null. I do not think it is what I put inside of the method, but here is the method from the other class:
public String getConfigString(PrisonProfessionalMain instance, String configvar)
{
return colorize(instance.getConfig().getString(configvar));
}
I don't see a problem here, but I am wondering if I should use a static way instead. I want to try and stay away from static methods for the reason I stated above.
REMEMBER: Calling any other method from this class results in it returning null. I know this because in console it has a stack trace that reads it null. It says this on the line that is calling any method from this class.
I tried removing the Strings and instances from inside the method:
public String getConfigString()
{
return System.out.println("test");
}
This still however, resulted in another null pointer, pointing at the line that I called the method on.
My question is: How would I have the QuickMethods class stop returning null upon calling methods/strings from it.
Only one constructor can be called at a time, given your code it appears you need to combine your constructors like,
QuickMethods qm;
PrisonProfessionalMain plugin;
public PPCommandAdminMenu(PrisonProfessionalMain plugin, QuickMethods qm)
{
this.plugin = plugin;
this.qm = qm;
}
Otherwise (by definition) one will be null.
Also,
public String getConfigString()
{
return System.out.println("test");
}
isn't legal code because PrintStream.println() is void (and System.out is a PrintStream). You can use something like
String str = "test";
System.out.println(str);
return str;
I was working on SCJP6 dumps when I found this confusing exercise:
Given classes defined in two different files:
package packageA;
public class Message {
String getText() { return “text”; }
}
And:
package packageB;
public class XMLMessage extends packageA.Message {
String getText() { return “<msg>text</msg>”;}
public static void main(String[] args) {
System.out.println(new XMLMessage().getText());
}
}
What is the result of executing XMLMessage.main?
A. text
B. Compilation fails.
C. <msg>text</msg>
D. An exception is thrown at runtime.
The answer was: B, but I don't understand why; I think the answer should be C.
If the code you posted it's the one that is in the book, the correct answer as you mentioned is C, let me explain why.
Again, assuming you copied the code as it's shown in the book when you do, the following line:
String getText() { return “<msg>text</msg>”;}
Its not overriding the getText() method in packageA.Message class but declaring a new one, that will can be accessed for XMLMessage instances within packageB.
This would be different if the the main method is something like:
public static void main(String[] args) {
Message message = new XmlMessage();
System.out.println(message.getText());
}
In this case there is a compilation error since the Message.getText() methods is not exposed outside the package.
A package default method cannot be overridden because it is not visible in another package.
In your example, method getText() in class Message is only visible to members of packageA.
Method does not override package visible method in Eclipse
The method String getText() { return “text”; } is with package (default) scope . And hence it is not visible outside the package packageA .
so it is not possible to override the method in the class XMLMessage which is outside the packageA .
You can learn the basics of method overloading and overriding here
Constraints:
I have a maven source code generator that I wrote that is creating POJO classes
from some data files that have nested namespaces. I want each namespace to
be nested as an inner class. In some cases out of my control I end up
with inner classes that are the same simple name as the outermost
class.
All the classes must be public scope as this is for a type safe
wrapper over something like a properties file, but hierarchical..
I can't change the names otherwise I am changing the names meaning and the namespace
that is enclosing data.
Given than I have the following code:
public class A
{
public class B
{
public class A
{
}
}
}
Inner classes should append the name of the outer class to form a unique namespace such as A$B$A.class, I haven't found a valid reason for this not to compile.
Is there any trick to get this to compile?
No. From the JLS section on class declarations:
It is a compile-time error if a class has the same simple name as any of its enclosing classes or interfaces.
Note: I somehow managed to miss this on my first pass through looking for an explicit rule. Check the edit history if you want the tortuous way I got here.
You asked: Is there any trick to get this to compile?.
The answer is: Well, maybe....
Create a class like the following:
public class A
{
public class B
{
public class X
{
}
}
}
And a class where this class is going to be used
public class AUse
{
public static void main(String[] args)
{
A.B.X aba = new A().new B().new X();
System.out.println("Created "+aba+" of class "+aba.getClass());
}
}
Then, download the Apache Byte Code Engineering Library (BCEL), and create and run the following class:
import java.io.FileOutputStream;
import org.apache.bcel.Repository;
import org.apache.bcel.util.BCELifier;
public class CreateCreators
{
public static void main(String[] args) throws Exception
{
new BCELifier(
Repository.lookupClass("A"),
new FileOutputStream("ACreator.java")).start();
new BCELifier(
Repository.lookupClass("A$B"),
new FileOutputStream("A$BCreator.java")).start();
new BCELifier(
Repository.lookupClass("A$B$X"),
new FileOutputStream("A$B$XCreator.java")).start();
new BCELifier(
Repository.lookupClass("AUse"),
new FileOutputStream("AUseCreator.java")).start();
}
}
This uses the BCELifier class from the BCEL. This is a class that takes a .class file, and creates a .java file that can be compiled to a .class file, that, when it is executed, creates the .class file that it was originally fed with. (Side note: I love this library).
So the A$B$XCreator.java file that is created there contains the BCEL code that is necessary to create the A$B$X.class file. This consists of statements like the generation of the constant pool and the instructions:
...
_cg = new ClassGen("A$B$X", "java.lang.Object", "A.java",
ACC_PUBLIC | ACC_SUPER, new String[] { });
...
il.append(_factory.createFieldAccess("A$B$X", "this$1",
new ObjectType("A$B"), Constants.PUTFIELD));
Similarly, the AUseCreator.java contains the BCEL code that creates the AUse.class. For example, the instruction of the constructor invocation of `A$B$X':
...
il.append(_factory.createInvoke("A$B$X", "<init>", Type.VOID,
new Type[] { new ObjectType("A$B") }, Constants.INVOKESPECIAL));
Now you can simply replace the String occurrences of "A$B$X" with "A$B$A" in the A$B$XCreator.java and AUseCreator.java, and then compile and run these classes.
The result will be a A$B$A.class file, and a AUse.class file that uses the A$B$A.class. Executing the AUse will print
Created A$B$A#15f5897 of class class A$B$A
I'm not sure whether this is considered as a "trick", or whether it still can be called "compiling" at all, but there is a way, at least. The key point is here, of course, that the fact that it did not compile is solely due to a limitation of the language, but there is no reason why this should not be representable in form of class files, regardless of how they are created.
You can't get it to compile, but more importantly, why would you need to?
What's wrong with:
public class A
{
public class B
{
public class InnerA
{
}
}
}
This seems like a design problem that you need to fix. If you can't rename it, consider anonymous inner classes. Or take some of those classes outside. Or just don't even use them.
It's a bit of a hack, but this compiles at my machine:
class A
{
public class B
{
public class Α
{
}
}
}
Try it. Literally: copy-past this thing ;)
SPOILER:
The name of the inner class is a capital letter alpha of the Greek alphabet. It's a Unicode character.
Depending on what you're after, the following might work for you:
public class A {
class B extends C {
}
public static void main(String[] args) {
new A().new B().new A();
}
}
class C {
class A {
{
System.out.println(getClass());
}
}
}
Ok, this might be kiddies question in java. We can't define two public classes in one file. But, in one of the examples from the book SCJP study guide, this example was mentioned:
public abstract class A{
public abstract void show(String data);
}
public class B extends A{
public void show(String data){
System.out.println("The string data is "+data);
}
public static void main(String [] args){
B b = new B();
b.show("Some sample string data");
}
}
When I copy pasted this into netbeans immediately compile error was thrown, that public class A should me mentioned in separate file. Is that example from SCJP styudy guide really wrong? Also in some of the mock test I found many questions having such pattern but in none of the options was a compiler error was mentioned. Getting worried here
yes, 2 top level public classes are not allowed in one file
Well, if one is being so picky: you can have multiple classes defined with a public modifier in the same file, that is, using the static nested(inner) class.
like this:
File -> Test.java
public class Test {
public static class SomeNestedClass {
}
}
Yes you can have two classes in the same file. You can have them by removing the public access modifier from both the class name, like shown below,
abstract class A{
public abstract void show(String data);
}
class B extends A{
public void show(String data){
System.out.println("The string data is "+data);
}
public static void main(String [] args){
B b = new B();
b.show("Some sample string data");
}
}
you can make 2 public classes in one file , inside a class that contains them .
it's also recommended to add "static" for them , if you do not need any reference to the container class .
You can put two public classes in one file, for example in the file Circle.java:
public class Test {
public static void main(String args[]) {
double cir = Circle.findCircumference(7.5);
System.out.print("Circumference of circle=" + cir);
}
}
public class Circle {
public static double findCircumference(double radius) {
return 2 * Math.PI * radius;
}
}
If you then run javac Circle.java, you will get an error:
Circle.java:1: error: class Test is public, should be declared in a file named Test.java
public class Test {
^
1 error
But if you run it with java Circle.java, then it will work.
Why? Probably because the java command, since java 11 (see here), can run also single source-file programs.
Imagine you could place two public classes in one file, then think about the work of the compiler: it has to build a .class file from your .java file that represents exactly one class (otherwise the .class ending wouldn't make any sense).
The way the JAVA Compiler works it will simply create a .class file with the name of your file and will search for the class with the name of the file in your given file – so it depends on your file name which class will be correctly compiled and which will not.
Long story short: no, you can't put two public classes in one file because the compiler wouldn't be able to handle that correctly.
(Edit: it of course is possible to define new classes INSIDE the one public class that has the same name as your file.)