Java inner class with the same name as other top level class - java

I have question related to Java inner classes.
Is there a way to access top level class A from top level class Main that define inner class A?
Below is sample code demonstrating the problem:
class A { // Outer Class A
{
System.out.println("A outer");
}
}
class B { // Outer Class B
{
System.out.println("B outer");
}
}
public class Main {
class A { // Inner Class A
{
System.out.println("A inner");
}
}
public void newA() {
class A { // Local Class A
{
System.out.println("A local");
}
}
new A();
}
public static void main(String[] args) {
new Main().newA(); // prints "A local"
new Main().new A(); // prints "A inner"
//new A(); // compiler error: No enclosing instance of type Main is Accessible.
new B(); // but this works and prints "B outer"
}
}

Use the fully qualified class name:
new com.mypackage.A();

If your classes are in packages, I'd expect that to be the simplest way of achieving this. I don't believe there's any equivalent of the C# global:: for Java, to force this sort of thing.
Ultimately though, I'd just try to change the class names to avoid the problem happening in the first place. That's usually a better approach than using workarounds.

You should provide different package names for your two As so that they are clearly different types, then you can reference them by their full names.
For example:
my.package.for.toplevel.A outerA = new my.package.for.toplevel.A(); // prints "A outer"
// if this is the
// package
Or even better, use two different names for two distinct classes.

The name of the inner class is said to shadow the name of the top-level class. The top-level class cannot be referenced by its simple name in the scope of the inner class; the top-level class can only be referenced via a qualified name.
If the top-level class is in the default package (in which case its canonical name is the same as its simple name), you can still access it via reflection.

Yep, just use packages or avoid naming them the same from the beginning. I wonder what's your reason to name them the same anyway?
To explain your error, it comes from the fact that it tries to access the inner A, but since that class is not declared as static and there's no Main instance available, it can't create a non-static inner A that requires a reference to parent Main instance.

Assumed the classes are in the default package. To resolve naming conflict in this case needs either rename the conflicting classes or use the named package. Then use FQCN to resolve the issue.

Related

Java: accessing protected fields from inner class

Recently I've faced a problem getting a runtime error java.lang.IllegalAccessError when trying to access from inner class a protected field declared in outer's parent class that was loaded by a different class loader. Briefly:
Class Parent has protected field p.
Class Outer extends Parent.
Class Inner is an inner class defined in class Outer.
Inside Inner class there's a code: Outer.this.p.
All classes are declared in the same package.
Normally it's compiled and runs fine until Parent and Outer class are loaded by different class loaders. In this case we get java.lang.IllegalAccessError when trying to access Outer.this.p from Inner.
I found an old bug report (which appeared to be a feature) describing this behavior:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6258289
But resolution sounds contradictive to me:
The key is that in the failing case the inner class isn't in the same
package (and isn't a subclass of) ConcreteCommand/AbstractCommand.
This is simply a violation of the Java specification for protected
classes.
It sounds correct. But if we declare Parent and Outer classes in different packages but load with the single class loader (simply create sample console app without any jar loadings) we don't get any errors. So technically it's a violation of Java spec for protected classes but since we use an inner class it works.
So we have different behavior for two cases of "different packages".
Declared in different packages, loaded by single class loader - OK.
Declared in single package, loaded by different class loaders - NOT OK.
Could someone give a clear explanation of how inner class gets access to parent's fields and why it works differently for two cases?
Same class loader it seems to be working
Did I get the question right?
Do you have any unit test case to reproduce your issue?
Parent Class
package p1;
public class Parent {
protected String p = "Value from Parent";
public void test() {
System.out.println(p);
}
}
Outer Class
package p1;
public class Outer extends Parent {
class Inner {
public void test() {
Outer.this.p = "Value set from Inner";
System.out.println(Outer.this.p);
}
}
public void test() {
new Inner().test();
}
}
Main Class
package p1;
public class Main {
public static void main(String[] args) {
Parent p = new Parent();
p.test();
p = new Outer();
p.test();
}
}
Output
Value from Parent
Value set from Inner
Declared in different packages, loaded by single class loader - OK
'protected' access is considerate about parent-child relation among classes and allows child classes to access 'protected' members of parent even if they are in different packages. So, I think this is as expected.
Declared in single package, loaded by different class loaders - NOT OK
This has to do with runtime packages. Check this.
Now we know that Parent is in different runtime package than Outer and Inner due to being loaded via two different class loaders. At the same time, we also have to remember that Outer is 'child' of Parent but Inner is not. Inner doesn't have an 'Is-a' relation with Parent.
Putting it all together :
Since Parent is in a different runtime package, Inner is not able to access Parent's 'protected' members as Inner is not a child of Parent.

Generate inner class

my annotation processor reads a class like this:
#Foo
public class Bar (){
}
Now I want to generate an inner class Bar$MyGeneratedClass so that at the end I have a class MyGeneratedClass that to the compiler / jvm looks like this:
public class Bar (){
// Generated by annotation processor
public static class MyGeneratedClass () { ... }
}
Is this possible? I think so, I guess I just have to name the generated class Bar$MyGeneratedClass right?
Does anybody know how to generate such a inner class with java poet?
You can use javapoet to create new classes. It's not possible modify existing class with javapoet.
On jvm level there is no such things as inner classes.
So while compiling both classes (the inner and the outer) are transfomed to simulate that effect.
The inner class gets a constructor parameter. With that parameter you need to pass in an instance of the outer class.
As both class types can access private members package private accessors are created.
Especially the second transformation requires you to change the outer class.

Class definition in java

I'm new to Java and i want a refinement:
First of all,i am not sure if i can have 2 classes in the same file.
My question is what is each class when you see this sequence of code:
class Something {
//code here
} //end of class Something
public class SomethingElse {
//NO code here!!!
public static void main(String[] args) {
//code of main here
}//end of main
}
What's the role of the class Something Else and why there is no code inside?I know that is a very stupid question but there are some details that i don't really get and i want some help...
You can have more than one class per file, but only one class can be public and its name must match the name of the file (e.g. public MyClass in MyClass.java).
The public class of a file will be visible to the outside world, and in particular if the class has a public static main(String[] args) method, it can be used to start an application.
In your case for example, once you have compiled your file using javac, you will get files Something.class and SomethingElse.class.
Using the command java SomethingElse will tell the Java Virtual Machine to do the following:
Find the SomethingElse class, which must be in the SomethingElse.class file
call the main method, matching the signature I pasted above on this class (and putting any given argument in the args array).
You cannot call java Something because the class isn't public and doesn't have a main method. But other classes in your program (and in particular, SomethingElse, can use your Something class).
You can have just one public class per file, and the file must have the same name of the class. But you can have other private classes that just the file class will see. For example:
File Something.java
public class Something {
//Something can access SomethingElse's doSomething method.
private class SomethingElse {
public void doSomething() {
}
}
}
class SomethingToo {
}
File OtherSomething.java
public class OtherSomething {
//OtherSomething cannot access SomethingElse's doSomething method.
//But can access SomethingToo, if they are in the same package
}
You can have multiple classes defined in a same file. However there should only one class defined as public and file name will be that public class name.
In the No code here!!! you can have class variables and methods defined. Your main() is one such example.
In the above file, there are two classes SomethingElse (public) and Something. Now, this is normally done when the non-public class is called internally by the public class. Also, in the above code fragment, SomethingElse seems to be a 'driver' class. In other words, it does not have any functionality/data of its own, but is used to execute (drive) other classes (probably Something in this case)
You can have nested classes, but two separate, public classes are not allowed. Each public class should be in it's own file named the same as the class.
While it's possible to have 2 classes in the same file, its considered bad practice. Besides the decreased readability, it will eventually become difficult to find out where that class declaration actually took place. Plus, if you declare a variable relating to the class, but not the class sharing the .java name, javac will most likely have issues compiling.
If you have to do it, make sure the only place you are using the second class is within the class sharing the .java name. (E.g. only use a Something object within the SomethingElse class). Otherwise, separate all your classes into separate .java files.
Yes, you can have 2 or more classes in single Java file.
The only condition is only one class will contain main method with signature(public static void main(String[] args)).
And only one public class will be there. And with that public class name you can save your file - the file name has to match the name of the public class.

Is there a syntax to get the reference to an anonymous inner class from a further anonymous inner class?

Consider this case:
public class SomeClass {
public void someMethod() {
new SomeInterface() {
public void someOtherMethod() {
new SomeOtherInterface() {
new someThirdMethod() {
//My question is about code located here.
}
};
}
};
}
}
Is there a syntax to reference the instance of the anonymous inner class represented by SomeInterface at the commented code? For SomeClass you can do SomeClass.this Is there an equivalent to get the implementation of SomeInterface?
If not, of course you can just define a final local variable in the SomeInterface implementation and reference it, but I was just wondering if there is in fact direct language support to reference the instance.
The reason why SomeInterface.this doesn't compile is because the enclosing class is not SomeInterface, but rather some anonymous type.
You can't use qualified this with anonymous type. That's why they're anonymous; you can't refer to them by name, and qualified this works by explicitly naming an enclosing type.
It's tempting to try something like:
SomeClass$1.this
But then you get an error SomeClass$1 cannot be resolved to a type; despite the fact that if you let this code compile without this line, it will (in all likelihood) create a SomeClass$1.class.
You can either use a non-anonymous class and use qualified this, or you can use the final local variable technique you mentioned.
References
JLS 15.8.4 Qualified this

Private variables in a class can be accessed from main in Java?

I've recently started learning Java using JDK1.6. If this is a silly question, please excuse me.
If private variables can be directly accessed by objects in main() how are they 'private'?
public class Account1
{
private int accountNum;
private String name;
Account1() {
accountNum = 1101;
name = "Scott";
}
public void showData() {
System.out.println("Account Number: " + accountNum +
"\nName: " + name);
}
public static void main(String[] args) {
Account1 myA1 = new Account1();
myA1.showData();
System.out.println(myA1.accountNum); //Works! What about "Private"?!
}
}
Which gives the output:
Account Number: 1101
Name: Scott
1101
Your main is in the Account1 class, so it's still in the same scope.
Private variables can be accessed from any code belonging to the same type. If your main method was in a separate class then it wouldn't be able to access them (without using reflection).
The "main" method of a given class is part of that class. Methods that are part of a class have access to private members of that class. That makes sense to me. Doesn't necessarily mean you should use it, of course.
One way to think about it is to think about one class's knowledge of another class's internal workings. My Person class shouldn't know what happens inside my Order class; it just calls public methods on it. But anything inside Person will of course know about the internal structure of Person -- even a different instance of Person.
This is because the main() function is a member of the class. It has access to all members of the class.
In real world code, the main function is usually situated in a "harness" class that actually bootstraps the rest of the code. This harness class is usually very lightweight and instantiates other classes that do the real work.
They are private in that they can only be accessed by that class. This means they are accessible from static methods of that class (such as main) and also from instance methods (such as showData).
One instance of the class can also access private members of another instance of the class.
If you had a separate class, say, Account2, it would not be able to access provate members of Account1.

Categories

Resources