Static Inner Classes Bytecode Java [duplicate] - java

This question already has answers here:
Why is an anonymous inner class containing nothing generated from this code?
(5 answers)
Closed 7 years ago.
In the below code :
class EnclosingClass
{
public static class BiNode extends Sub.IBiLink { }
private static class Sub
{
private static class IBiLink
{
}
}
}
On compiling along with other .class files, I also see a file named "EnclosingClass$1.class" .Why has this been automatically created? Whats going on?

First have a look at the class access and propery modifier table from the JVM specifications.
Notice the ACC_SYNTHETIC flag which interpretation specify that it is not present in the source code (in simplier words, it will be added when the class is generated by the compiler).
Let's have a look at the bytecode of EnclosingClass$1.class (note that I will paste only the part that matter).
javap -v EnclosingClass$1.class
produce the following result
Classfile /C:/Users/jfrancoiss/Desktop/Nouveau dossier/EnclosingClass$1.class
Last modified 2015-03-31; size 190 bytes
MD5 checksum 5875440f1e7f5ea9a519d02fbec6dc8f
Compiled from "EnclosingClass.java"
class EnclosingClass$1
minor version: 0
major version: 52
flags: ACC_SUPER, ACC_SYNTHETIC
Notice that the access flags of the class contains ACC_SYNTHETIC.
The ACC_SYNTHETIC flag indicates that this class or interface was
generated by a compiler and does not appear in source code.
An other option to make sure the generated class is synthetic is to compile as
javac -XD-printflat EnclosingClass.java
which would produce
/*synthetic*/ class EnclosingClass$1 {
}
Great, but why generate a synthetic class ?
The Java reflection tutorial can help us understand this. Have a look at the comments in the SyntheticConstructor class
public class SyntheticConstructor {
private SyntheticConstructor() {}
class Inner {
// Compiler will generate a synthetic constructor since
// SyntheticConstructor() is private.
Inner() { new SyntheticConstructor(); }
}
}
So according on the comment, the synthetic class EnclosingClass$1.class was created because IBiLink was private.
Once again, the java reflection tutorial specify at this point
Since the inner class's constructor references the private constructor
of the enclosing class, the compiler must generate a package-private
constructor.
In our case, we do not see explicitely any constructor call, but we have this line
public static class BiNode extends Sub.IBiLink { }
Let's try compiling this code and see what happen
class EnclosingClass
{
//public static class BiNode extends Sub.IBiLink { }
private static class Sub
{
private static class IBiLink
{
}
}
}
No EnclosingClass$1.class generated.
More details noticed when debugging
Change
private static class IBiLink
to
protected static class IBiLink
notice that when compiling, EnclosingClass$1.class is not created.
why does protecting the class did not generate a synthetic class ?
Simply because when protecting the class, you implicitely get access to each of the super classes.
Why don't eclipse compiler generate a synthetic class ?
Eclipse use it built-in compiler, which you can configure it severity level.
By default, Access to a non-accessible member of an enclosing type is set to ignore as you can see on this image.
Change it for example to warning and you will get the following message.
which let me believe that eclipse, altought does not create an other class, will emulate it to simulate the synthetic member.

Related

Why prefer the indirect generic's import to the actual class?

Using eclipse if I write this interface in the package mypack:
package mypack;
public interface MyInterface<A>{
public interface Test{
void sayHi();
}
}
And if I write this class in no package.
public class Test implements mypack.MyInterface<mypack.MyInterface.Test> {
private Test test = new Test();
}
Eclipse trigger me an error at compile-time, that I must implement the method sayHi().
I see no way out!
If I Ctrl+LMB to the type of the field test it takes me to the Class.
Bug reported
A small bug is reported here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=488077
What is happening here is
Test test = new Test();
the Test is being taken as a nested-type of the MyInterface you inherit from.
I will look into the JLS to see if there is a reason it chooses the inherited class over it's own name.
Note: MyInterface doesn't have to be generic. A simpler form of this problem is
interface MyInterface {
interface Test {
}
}
class Test extends MyInterface {
Test test = new Test(); // thinks this is the MyInterface.Test
}
BTW: As this is very confusion combination of class structure and names, I suggest you never do this in reality.
A note from JLS 7.4.2
Unnamed packages are provided by the Java SE platform principally for convenience when developing small or temporary applications or when just beginning development.

javac gives no warning when a class with default access contains public members

Regarding the example code below, although the Test() constructor inside the class Test is public, the class Test itself isn't public, and so the Test() constructor can't be called from outside its own package.
Does that make the public keyword redundant? If so, I wonder why javac doesn't issue a warning about the redundant use of public, when used inside a class whose access is implicitly declared as default ("package private")?
Test.java, package test -
package test;
class Test {
public Test() {}
}
Main.java, package main -
package main;
class Main {
public static void main(String[] args) {
new test.Test(); // Expected error
}
}
EDIT:
Just to be clear: it's when I compile Test.java, that I get no warning.
The user comments made to my original post have helped me solve this problem: I now realise that an IDE will give me the information that I was after, and that just using javac on its own will not. Thanks.

What if main method is inside "non public class" of java file?

I have a java file containing more than one class, out of which one is public. If main method is inside a non-public class. I can't run that java file. Why is that? and there is no compilation error as well. If so, how can I use that main method?
Actually you can execute the main method in a non-public class. if you put this class
class A {
public static void main(String... args) {
System.out.println("This is not a public class!");
}
}
in a file named NonPubClass.java. You can compile this file using javac command but you will not get a NonPubClass.class, you will get a A.class instead. Use java a to invoke that class and you will see the printed string --- This is not a public class!
Have a look at this code:
Super.java
public class Super{ }
class Sub{
public static void main(String[] s){
System.out.println("Hello");
}
}
In order to print Hello you can compile and run the program as:
How this works?
The compiler generates separate .class file for every class in your program. So, instead of calling the main() of non-public class from the public class's main() you can print the output as shown above.
Note: As the convention says, you must put a public class in separate file <class_name>.java. And do not put more than one class in a single file (except if they are inner class) because if you would like to import them or use them with other classes then it will cause problem.
there is something i would like to add although everybody here believes that a public is necessary for the main in a class and that it won't work without main
you can have as many mains in a class as you desire, and you can have them without a public access modifier.
but be careful, only that class which is named after the file can be public
what i mean is if you name your file a.java , then only the class with name a can be public, none other can have this facility
here is a code to show this :
as you can see the name of the file is helping.java
//:initialization/helping.java
class b{
public static void main(){
System.out.println("hello its b");
}
}
class helping {
static void f(float i, Character... c) {
System.out.println("first");
}
static void f(char a, Character... args) {
System.out.println("second");
}
public static void main(String[] args) {
f(1,'a');
f('a','b');
c.main();
}
}
class c{
public static void main(){
System.out.println("hello its b");
}
}
//:~
/*
* output:
* first
* second
* hello its b
* */
Simple Answer. You can't. You need to have main method in a public class and its signature should be public static void main(String... args)
there is no compilation error
Why there would be? You are doing nothing wrong as far as compilation rules are concerned.
Only thing is that your non-public-class-main-method won't work as an entry point of your code.
It is a compile-time error if a top level type declaration contains any one of the following access modifiers: protected, private, or static.This link may be helpful.
It's not a compile time error as u mentioned that top level type declaration shouldn't be protected, static or private.
If u go through the link http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html#jls-7.6 well that u have shared ,then it's quite clear there that a top-level type declaration refers to only "top level Class and Interface type declarations" and these should not be protected, static or private at top level declarations, but we can use protected, static or private for any methods or variable declaration inside them.
With respect to above code, there is nothing wrong in declaration, and the code will compile and run successfully as all outer top level class are default and there is no violation.
The answer to the question asked at top is exactly as mentioned by few experts at top, that
"for sure we can have a file with main method inside non-public class and it will compile as well as run successfully, but make sure that at the time of running the program we have to pass the class name of "main method" to the java interpreter instead of the class which is public."
If we have 2 classes A(public) and B(non-public containing main method) , then the file will compile with "javac A.java" but while running the code we need to pass the command as "java B" .
You can certainly override main method and it does not violate any compiler rules and hence you will not have any compiler errors.
You check that inspite of the fact that you have more than one class a file that is declared as public is the name of the file you are trying to execute.
This is a convention that the file should be named after the same class which is public in that code.
Hence when you try to execute that class it does not have a main method from which it starts execution.So if you want to execute the main method in the non public class the only way to this is call that main from a main method of the public class.

Java: Multiple class declarations in one file

In Java, you can define multiple top level classes in a single file, providing that at most one of these is public (see JLS §7.6). See below for example.
Is there a tidy name for this technique (analogous to inner, nested, anonymous)?
The JLS says the system may enforce the restriction that these secondary classes can't be referred to by code in other compilation units of the package, e.g., they can't be treated as package-private. Is that really something that changes between Java implementations?
e.g., PublicClass.java:
package com.example.multiple;
public class PublicClass {
PrivateImpl impl = new PrivateImpl();
}
class PrivateImpl {
int implementationData;
}
Javac doesn't actively prohibit this, but it does have a limitation that pretty much means that you'd never want to refer to a top-level class from another file unless it has the same name as the file it's in.
Suppose you have two files, Foo.java and Bar.java.
Foo.java contains:
public class Foo
Bar.java contains:
public class Bar
class Baz
Let's also say that all of the classes are in the same package (and the files are in the same directory).
What happens if Foo refers to Baz but not Bar and we try to compile Foo.java? The compilation fails with an error like this:
Foo.java:2: cannot find symbol
symbol : class Baz
location: class Foo
private Baz baz;
^
1 error
This makes sense if you think about it. If Foo refers to Baz, but there is no Baz.java (or Baz.class), how can javac know what source file to look in?
If you instead tell javac to compile Foo.java and Bar.java at the same time, or if you had previously compiled Bar.java (leaving the Baz.class where javac can find it), or even if Foo happens to refer to Bar in addition to Baz, then this error goes away. This makes your build process feel very unreliable and flaky, however.
Because the actual limitation, which is more like "don't refer to a top-level class from another file unless it either has the same name as the file it's in or you're also referring to another class that's named the same thing as that file that's also in that file" is kind of hard to follow, people usually go with the much more straightforward (though stricter) convention of just putting one top-level class in each file. This is also better if you ever change your mind about whether a class should be public or not.
Newer versions of javac can also produce a warning in this situation with -Xlint:all:
auxiliary class Baz in ./Bar.java should not be accessed from outside its own source file
Sometimes there really is a good reason why everybody does something in a particular way.
My suggested name for this technique (including multiple top-level classes in a single source file) would be "mess". Seriously, I don't think it's a good idea - I'd use a nested type in this situation instead. Then it's still easy to predict which source file it's in. I don't believe there's an official term for this approach though.
As for whether this actually changes between implementations - I highly doubt it, but if you avoid doing it in the first place, you'll never need to care :)
I believe you simply call PrivateImpl what it is: a non-public top-level class. You can also declare non-public top-level interfaces as well.
e.g., elsewhere on SO: Non-public top-level class vs static nested class
As for changes in behavior between versions, there was this discussion about something that "worked perfectly" in 1.2.2. but stopped working in 1.4 in sun's forum: Java Compiler - unable to declare a non public top level classes in a file.
You can have as many classes as you wish like this
public class Fun {
Fun() {
System.out.println("Fun constructor");
}
void fun() {
System.out.println("Fun mathod");
}
public static void main(String[] args) {
Fun fu = new Fun();
fu.fun();
Fen fe = new Fen();
fe.fen();
Fin fi = new Fin();
fi.fin();
Fon fo = new Fon();
fo.fon();
Fan fa = new Fan();
fa.fan();
fa.run();
}
}
class Fen {
Fen() {
System.out.println("fen construuctor");
}
void fen() {
System.out.println("Fen method");
}
}
class Fin {
void fin() {
System.out.println("Fin method");
}
}
class Fon {
void fon() {
System.out.println("Fon method");
}
}
class Fan {
void fan() {
System.out.println("Fan method");
}
public void run() {
System.out.println("run");
}
}
Just FYI, if you are using Java 11+, there is an exception to this rule: if you run your java file directly (without compilation). In this mode, there is no restriction on a single public class per file. However, the class with the main method must be the first one in the file.
1.Is there a tidy name for this technique (analogous to inner, nested, anonymous)?
Multi-class single-file demo.
2.The JLS says the system may enforce the restriction that these secondary classes can't be referred to by code in other compilation units of the package, e.g., they can't be treated as package-private. Is that really something that changes between Java implementations?
I'm not aware of any which don't have that restriction - all the file based compilers won't allow you to refer to source code classes in files which are not named the same as the class name. ( if you compile a multi-class file, and put the classes on the class path, then any compiler will find them )
Yes you can, with public static members on an outer public class, like so:
public class Foo {
public static class FooChild extends Z {
String foo;
}
public static class ZeeChild extends Z {
}
}
and another file that references the above:
public class Bar {
public static void main(String[] args){
Foo.FooChild f = new Foo.FooChild();
System.out.println(f);
}
}
put them in the same folder. Compile with:
javac folder/*.java
and run with:
java -cp folder Bar
According to Effective Java 2nd edition (Item 13):
"If a package-private top-level class (or interface) is used by only
one class, consider making the top-level class a private nested class
of the sole class that uses it (Item 22). This reduces its
accessibility from all the classes in its package to the one class
that uses it. But it is far more important to reduce the accessibility
of a gratuitously public class than a package-private top-level class:
... "
The nested class may be static or non-static based on whether the member class needs access to the enclosing instance (Item 22).
No. You can't. But it is very possible in Scala:
class Foo {val bar = "a"}
class Bar {val foo = "b"}

Defining classes in Java files

I have found one error in my Java program:
The public type abc class must be defined in its own class
How can I resolve this error? I am using Eclipse. I am new to Java programming.
Each source file must contain only one public class. A class named ClassName should be in a file named ClassName.java, and only that class should be defined there.
Exceptions to this are anonymous and inner classes, but understanding you are a beginner to Java, that is an advanced topic. For now, keep one class per file.
Answering your addition: it is OK to inherit classes and that's totally fine. This does not matter, each class should still have its own file.
Public top-level classes (i.e. public classes which aren't nested within other classes) have to be defined in a file which matches the classname. So the code for class "Foo" must live in "Foo.java".
From the language specification, section 7.6:
When packages are stored in a file system (§7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
This rule, which doesn't have to be followed by compilers, is pretty much universally adhered to.
Ok, maybe an example will help.
In file MySuperClass.java:
public class MySuperClass {
// whatever goes here
}
public class MySubClass1 extends MySuperClass {
// compile error: public class MySubClass1 should be in MySubClass1.java
}
class MySubClass2 extends MySuperClass {
// no problem (non-public class does not have to be in a file of the same name)
}
In file MySubClass3.java:
public class MySubClass3 extends MySuperClass {
// no problem (public class in file of the same name)
}
Does that make things clearer?
A public class with the name of "abc" must be in a file called abc.java
You can create a new class an a existing file if it's private, but you should not do this.
Create one file per class.
Eclipse does that for you, if you create a new class.
For programming Java, you have to understand the construct of classes, packages and files. Even if Eclipse helps you, you have to know it for yourself. So start reading Java books or tutorials!

Categories

Resources