class HelloWorld {
public static void main(String arg[]) {
System.out.println("Hello World!");
}
}
Using javac HelloWorld.java and java HelloWorld, the code compiles and runs well. Since default access specifier in Java is package, how is it possible? It must have protection from outsider...
Access modifier restricts access during compile time. But it is allowed to load a class with any access modifier, use reflection to find the main method and run it. This is what java tool does when lanching from a class. See http://docs.oracle.com/javase/6/docs/technotes/tools/windows/java.html
Default Access modifier means you can only access that class in that package.
what you are doing here is, running and compiling the class.
This has nothing to do with modifiers and accessibility.
You will always Run & Compile classes like that.
What matters is that your class is accessible in the class or package that is being run.
You can not access a class with Default modifier in sub package or other package. A default class will only be accessible i the same package, otherwise you will get compile time error.
As far as your code is concerned you are doing nothing like that.
Suppose -
class HelloWorld {
public static void main(String arg[]) {
System.out.println("Hello World!");
}
}
And
Class Hello extends HelloWorld{
// some code here
}
Now if you compile class Hello, then it will give you following error.
class, interface, or enum expected
Related
How to pass the value of an enum declared within another class to a method of that class?
In my other class which is in a different package from where the enum is defined, I have declared the enum as:
public static enum Status
{
SUCCESS, FAILURE;
}
I've tried to import the Enum using import static as follows:
import static com.org.xx.yy.classname.Status
and
import com.org.xx.yy.classname.Status;
With both the cases in my test program, I am able to compile but I am getting a run time error:
Exception in thread "main" java.lang.NoClassDefFoundError: com.org.xx.yy.classname$Status
If you aren't getting a compile error for missing that class but you are getting the runtime NoClassDefFoundError then that means you must have linked against that class at compile time, without actually compiling it into your executable code, then you run your code without that class on the classpath so it can't find it.
Make sure that your build path is setup correctly to compile that class and try re-building your project OR, if that should be an external class, then add it to your classpath at runtime.
This compiles for me and prints out "SUCCESS"
Main.java
package com.xx.yy.Main;
import com.aa.bb.OtherClass.Status; // <-- Other class in other package
public class Main {
public static void main(String[] args) {
System.out.println(Status.SUCCESS.name());
}
}
OtherClass.java
package com.aa.bb;
public class OtherClass {
public static enum Status {
SUCCESS, FAILURE;
}
}
enum and nested enum - package local, final and static. No need to set static enum. import com.org.xx.yy.classname.Status should work.
I'm reading the draft of the Java 9 specification but this phrase is not clear to me:
The opens directive specifies the name of a package to be opened by the current module. This makes public and protected types in the package, and their public and protected members, be accessible to code in other modules at run time only. It also makes all types in the package, and all their members, be accessible via the reflection libraries of the Java SE Platform.
If the opens makes public and protected accessible at runtime only, what does meaning that all types in the packages area accessible via reflection?
I don't understand the difference between runtime and reflection.
It seems like the opened package makes accessible only public and protected at runtime (via reflection?) and also other packages not specified with type and members accessible vie reflection (also private...).
Let's say you write some code that uses a public class from a library.
import somelibrary.somepackage.SomeClass; // <-- public class from a library.
public class Main {
public static void main(String[] args) {
SomeClass.doSomething();
}
}
You then compile this code, and it compiles fine, since the class you're using is public.
Now, in the next version of the library, the package is added to a module, but not exported. That means that if you try to run your code with this new module on the runtime module path, it would throw an exception because you're trying to access an encapsulated package.
In order to make your code work again, you could use the command line option to open this module to your code, so that it can continue to use the encapsulated package.
Alternatively, the creator of the library could add opens somepackage; to the module definition of the library. That would allow you to run your code using this new version, but not compile with it. I.e. the public and protected members are only accessible at runtime, but there is no reflection involved.
The same goes for when you extend a class, and want to access a protected member of a super class that is in the encapsulated package.
But the opens directive does not change the fact that, if in the next version of a library, a method or field is made private, that you get an IllegalAccessError if you try to use it:
class SomeClass { // <-- the class in the library
public static void doSomething() {
System.out.println("doSomething"); // contrived example code
}
}
...
public class Main {
public static void main(String... args) throws Exception {
SomeClass.doSomething(); // this call compiles fine,
}
}
Then, in the next version of the library doSomething is made private:
private static void doSomething() {...}
And re-compiled. But if you try to run the old version of Main with the new version of SomeClass you get an IllegalAccessError.
In short, opens only works for members that are still public or protected in the new version of the library.
However, in the case of reflection, you can always access a private member, by using setAccessible(true):
public static void main(String... args) throws Exception {
Method m = SomeClass.class.getDeclaredMethod("doSomething");
m.setAccessible(true);
m.invoke(null); // works Fine
}
So in the case of reflection, opens would also make encapsulated private members accessible again.
A package opened by a module, may be qualified or unqualified.
The opens directive in a module declaration declares a package to be
open to allow all types in the package, and all their members, not
just public types and their public members to be reflected on by APIs
that support private access or a way to bypass or suppress default
Java language access control checks.
--Documentation
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.
When I create a new main.java file in the default package in my Eclipse project, it generates a main method that looks like:
public static void main(String[] args)
{
}
This immediately raises a warning that says This method has a constructor name. The suggested fix is to remove the void:
public static main(String[] args)
{
}
Now rather than a warning, I get an error: Illegal modifier for the constructor in type main; only public, protected & private are permitted. If I remove the static, my code now looks like:
public main(String[] args)
{
}
This time, I still get an error, but a different one that says:
Error: Main method not found in class main, please define the main method as:
public static void main(String[] args)
Argggh! But that takes me right back to where I started. How do I define the main method so that I don't get any errors or warnings?
I'm using Eclipse Juno Service Release 2 and JavaSE-1.7. Please note, I'm very new to Java; I come from a C# background. Also, this is probably a duplicate question, but I can't find it.
Don't call your class main, but Main.
In general, stick to the Java coding standards: start class names with a capital (Main instead of main) and you won't run into these problems.
If you name the file main.java the class has to be named main too, which is against standard (classes start with a capital letter) but possible. In a class a method named the same as the class is considered a constructor. So to fix your problem and fit the standard rename your class and the file to Main with a capital "M"
Change the name of your class from main to Main or to something else. Also, following the JavaBean API specification, your classes must be in CamelCase with the first letter in capital.
Not 100% related with question, but you should also do not create classes with the names of Java JDK classes, for example String:
public class String {
public static void main(String[] args) {
System.out.println("Try to execute this program!");
}
}
This won't only give problems to compiler/JVM but also for future readers (remember that you are a future reader of your own code as well).
Note: to fix the code above, just refer to java.lang.String class using its full name:
public class String {
public static void main(java.lang.String[] args) {
System.out.println("Try to execute this program!");
}
}
Or even better, change the name of the class.
In java, the class name and file name must match. If you have a file named main.java, then the class name has to be Main too, and in that case, the constructor method would be named main, so you couldn't have a main method.
Change your file and class name to something other than main.
class Main {
public static void main(String[] args) {
....
}
}
Starting the program through the shell: java Main works as expected but starting the program through ant:
<target name="run" depends="cmp">
<java classname="Main" classpath="."/>
</target>`
causes this error:
java.lang.IllegalAccessException: Class org.apache.tools.ant.taskdefs.ExecuteJava can not access a member of class Main with modifiers "public static"
JLS Section 12.3.3 Resolution of Symbolic References:
IllegalAccessError: A symbolic reference has been encountered that
specifies a use or assignment of a field, or invocation of a
method, or creation of an instance of a class, to which the code
containing the reference does not have access because the field or
method was declared private, protected, or default access (not
public), or because the class was not declared public.
So org.apache.tools.ant.taskdefs.ExecuteJava can't execute the method because it's enclosing class is private, but if I start the jvm pointed at a .class with a private method, it doesn't go through the same security mechanism?
This question is similar but I still don't understand
The answer is all in the question you linked to. When you run it through the JVM it has access to absolutely everything regardless of access level. When you run it through ant, which itself is another java program, it has to obey by the same rules as any other program - which means that it cannot see your main method.
If you declare your class as public class Main the problem should go away.
As to why the jvm has made this decision to allow access to private classes when starting is another matter indeed. As per the specification
12.1.4 Invoke Test.main
Finally, after completion of the initialization for class Test (during
which other consequential loading, linking, and initializing may have
occurred), the method main of Test is invoked. The method main must be
declared public, static, and void. It must accept a single argument
that is an array of strings. This method can be declared as either
public static void main(String[] args) or public static void
main(String... args)
This specifically states that the method must be public but says nothing about the class in questions, which why it works when you invoke main through the VM directly.
Try to add public modifier to the class like this:
public class Main {
public static void main(String[] args) {
....
}
}
Use public access-modifier.
Eg:
public class Main {
public static void main(String[] args) {
// Your code..
}
}