Java compilation of a .java file without a public class - java

Okay, so a java source file must have at least one public class and the file should be called "class-name.java". Fair enough.
Hence, if I have a class, then the following would compile:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!"); // Display the string.
}
}
But what bugs me is that if I remove the 'public' access modifier from the above code, the code still compiles. I just don't get it. Removing it, the code looks like:
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!"); // Display the string.
}
}
In the above code, since I removed the public access modifier, my class has default or package access, i.e. it can't be accessed from the outside world, only from within the package.
So my question is, how does the above code compile ? The file HelloWorld.java in this case does not have a public HelloWorld class (only a package-private HelloWorld.class) and thus to my understanding should not compile.

a java source file must have at least one public class and the file should be called class-name.java
Incorrect, a top level class does not have to be declared public. The JLS states;
If a top level class or interface type is not declared public, then it may be accessed only from within the package in which it is declared.
See http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#104285 section 6.6.1.

You can place non-public class in a file, and it's not a bug but feature.
Your problem is on level of packaging, not compile. Because you can compile this file with non-public class, but you can't call it from outside, so it's not working as application base class
Like this:
// [+] single file: SomeWrapper.java
public class SomeWrapper {
ArrayList<_PrivateDataType> pdt;
}
// [-] single file: SomeWrapper.java
// [+] single file: _PrivateDataType.java
class _PrivateDataType {
// members, functions, whatever goes here
}
// [-] single file: _PrivateDataType.java

A main method is just like any other method. The only difference is that it may be invoked from the command line with the java command. Even if the main method is not visible from the command line, the class can still be used like any other Java class, and your main method may be invoked by another class in the same package. Therefore i makes sense that it compiles.
In Java main function are not special in any sense. There just exists a terminal command that is able to invoke static methods called main...

There are valid usages for a non public classes. So the compiler does not give error when you try to compile the file.

That's nothing to wonder about. I suppose this behavior is similar to the one of some C/C++-compiler.
Code like "void main() { /.../ }" will be compiled correctly by those compilers, although it is not standards-compliant code. Simply said, the compiler exchanges the "void" with "int".
I think a similar behavior is implemented by the java compiler.

When you do not specify the access modifier of the class (or its field or method), it is assigned "default" access. This means it is only accessible from within the same package (in this case, the default package).
The website Javabeginner.com has an article on the subject - you should become familiar with access modifiers in Java, either from this site, or others.

Related

Warning: main methods should not be directly called

I currently work on a Java project which has many main methods. Now, I do some refactoring, which affects all main methods. However, some of the main methods are actually called directly from other methods. I think this is bad style and it actually makes the refactoring harder. Thus, I want to be able to identify all places where a main method is called. Currently, I use my IDE tools to find all references to a given main method, however this is tedious and it is easy to forget to check this for one of the main methods.
My question is, whether there is some checkstyle rule or Eclipse compiler warnings setting that produces a warning whenever a main method is called directly. I was unable to find one.
If you are concerned that people may have formatted the "main" methods in variety of ways, and that you may miss some of them when you use "pattern matching" ...
Could "javap -public MyClass.class" work for you? When I tried it on ...
public class Main1 {
public
static
void
main
(
String
[]
args
)
{
System.out.println("Main1: Hello World");
}
}
It produced the following output:
Compiled from "Main1.java"
public class Main1 {
public Main1();
public static void main(java.lang.String[]);
}
Admittedly, it doesn't 'detect' if this 'main' is calling another 'main', it will be helpful just in finding all the 'main's.
Source derived from Post: Java Program to disassemble Java Byte Code
As #Jeutnarg suggested in the comments:
[...] you could use Eclipse's Java search. Search for 'main', only searching for 'Method' with Limit to 'References' with Search in 'Sources' with a scope of your project.
This is what I ended up doing and it actually worked much better than I expected.

Default Classes imported in java

I have a simple code:
public class Hello
{
public static void main(String[] args)
{
System.out.println("Hello World");
}
}
I know that Object class is imported by default in every java program, but I wanted to ask whether PrintStream class is also imported by default if we are using print() or println() functions?
Because Object class belongs to java.lang package and PrintStream class belongs to java.io package, so if it is not imported by default, then how we are able to use the println() method of PrintStream class?
If it (PrintStream class) is not imported by default, then why the decompiler is importing it?
This is the output after decompiling it:
The types of intermediate expressions in your Java program do not need to be imported on the source code level. It's only when you assign the value of such an expression to a declared variable that you have to make its type explicit; at that moment you have to add the import (or use the qualified name).
In your case, System.out is such an intermediate expression; its type is indeed java.io.PrintStream, which is not imported by default as it is not in java.lang. If you would modify your class to
import java.io.PrintStream;
public class Hello {
public static void main(String[] args)
{
PrintStream myOut = System.out;
myOut.println("Hello World");
}
}
you need to add the import statement, or use the qualified name as in
public class Hello {
public static void main(String[] args)
{
java.io.PrintStream myOut = System.out;
myOut.println("Hello World");
}
}
On the bytecode level the story is different: since all dependencies need to be loaded for the JVM to be able to execute the code, all of them are listed in the .class file, including the types of intermediate expressions. Apparently the decompiler used in the screenshot of the OP isn't clever enough to realise that such imports are unnecessary on the source code level, and so it just creates import statements for all dependencies listed in the .class file.
I wanted to ask whether PrintStream class is also imported by default if we are using print() or println() functions
No, from the JLS:
A compilation unit automatically has access to all types declared in its package and also automatically imports all of the public types declared in the predefined package java.lang.
So you can use System because it belongs to java.lang.
so if it is not imported by default,then how we are able to use the println() method of PrintStream class?
Because System.out is accessible to your type, so you can use all visible method of System.out
why the decompiler is importing it
Looks like a bug in the decompiler you are using. This import is completely unnecessary here.
You can program without imports at all, just using the fully-qualified class names like this:
java.io.PrintStream out = System.out;
Imports are used just for convenience, so you can use simple class names in your code. It's possible that the same simple name appears in different packages (for example, java.awt.List and java.util.List) so to resolve this ambiguity you have to either use full class name or import the one you want (in case you want to use both of them, you will still have to use the full name for one of them). As you correctly mentioned, only classes from java.lang are imported always by default. Again, this is done for convenience, so you can use just System instead of java.lang.System (though java.lang.System.out.println() is also valid).
In your example as you don't directly mention the PrintStream in the source, no need to import it. Imports have nothing in common with class loading (which happens in runtime, not during the compilation).

String class make confusion

Recently I just got an error in java that
Exception in thread "main" java.lang.NoSuchMethodError: main
Even if my class was just of 3 line of code.
public class Test{
public static void main(String[] args){
System.out.println("hello");
}
}
I was wondering why this happens, but later on i get to know there was a public class String which i had tried & created in same package.
so now new question arise is what happen in this kind of situation though String is not a keyword defined in java (you can use in your code)
Then I just deleted String.java & String.class file from the package but it sounds odd that you could not use String class as well.
Question: Does java gives major priority to our custom class?
Your main method needs to match
public static void main(java.lang.String[] args){ ... }
If you create your own String class in the same package where the class with your main method is, it will become
public static void main(your.own.package.String[] args){ ... }
which is valid, but will not allow the runtime launcher to find a main method anymore, since it expects java.lang.String[] as parameter.
The classes from java.lang are imported automatically by default, so you don't need an explicit import statement - that probably made it even more confusing to you.
As a rule of thumb, I would avoid to name my own classes the same as classes from the Java Runtime, whenever possible - especially from java.lang.
See also the JLS: Chapter 7. Packages:
A package consists of a number of compilation units (§7.3). A compilation unit automatically has access to all types declared in its package and also automatically imports all of the public types declared in the predefined package java.lang.
You can always use a fully qualified name:
public static void main(java.lang.String[] args) ...
The story you are telling says that we can use String as the name for one of our classes. But, like in real life, if there are two people named "John" around, you sometimes need to disambiguate them.

Why a class containg a main method doesn't need to be public in Java? [duplicate]

This question already has answers here:
Package-private class within a .java file - why is it accessible?
(4 answers)
Java compilation of a .java file without a public class
(6 answers)
Closed 9 years ago.
I wrote the following code
class Hello //Note the class is not public
{
public static void main(String args[]) {
System.out.println("Hello");
}
}
So, when I run it, it runs fine and prints the output "Hello".
However, if JVM spec mandates that main method should be public since "it can't see main otherwise", shouldn't it apply to the class as well? If the JVM "can't see" Hello.main() when it is not declared public, how is it able to see the class A itself.
Is there any explanation for this other than "because the specification says so"?
And if the JVM is able to see all classes and methods as it is the "security/visibility enforcer" itself then why does the main method needs to be declared as public.
Just for kicks, a demo that private classes can also hold main:
class Outer {
private static class Inner {
public static void main(String[] args) {
System.out.println("Hello from Inner!");
}
}
}
Compiles and runs fine from the command line:
C:\junk>javac Outer.java
C:\junk>java Outer$Inner
Hello from Inner!
C:\junk>
if JVM spec mandates that main method should be public since "it can't
see main otherwise"
It can see but it doesn't see it as the entry point and that is why it gives NoSuchMethodError: main if you try to execute a class having no such method.
By classic design, the main entry point-
Must be named main
Must be public
Must be static
Must be void
Must have one argument that is an array of string
Hence,
public static void main(String args[])
Being static, JVM can call it without creating any instance of class which contains the main method. Not sure if it is the main reason for main being static by design.
A class with default access like Hello in your example is only visible to other classes in the same package.
I don't think the specification says that the class has to be Public.
Refer to the examples on the official java tutorial. None of the classes with main method in the examples are declared as Public.
This was discussed previously on stackoverflow. Refer: Package-private class within a .java file - why is it accessible?
Explains it well.
Mind that main is an early language feature. My guess is that it was thought that a private method could disappear in the .class file, maybe inlined, maybe given a shorter name. So it is a simple overrestricting (?) convention for retrieval of the correct method:
static void main(String[])
the default access specifier is package.Classes can access the members of other classes in the same package.but outside the package it appears as private but JVM has access to all the classes thus JVM can alter the visibility just to find the beginning of the program thus it makes it default by default
Of so first let's consider this
1. Since main method is static Java virtual Machine can call it without creating any instance of class which contains main method.
this:
2.Anything which is declared in class in Java comes under reference type and requires object to be created before using them but static method and static data are loaded into separate memory inside JVM called context which is created when a class is loaded. If main method is static than it will be loaded in JVM context and are available to execution.
and finally this:
3. Main method is entry point for any Core Java program. Execution starts from main method.
So in conclusion: Java first charge your Main method, the public make this method accessible from everywhere for the JVM, and static set the method in the JVM context so the first thing that the JVM loads it's your main method!
Class Hello{}
just make your class accessible to all classes from the same package.
Here's a similar question with quite a straightforward answer.
Basically, the JVM can access the main in any class that is either of default access or of public access because it is the entry point. If the class is private or protected you will get a compile error.
when JVM starts it loads the class specified in the command line (see the jls java virtual machine start up), and you cannot have protected or private specifier in the class so the only option for you is to either have public or just blank default and both these access specifier allows the class to be accessed inside the same package. So there is no need for specifying public keyword for the class to load.
Hope its clear.

Use two classes in the same java file

I have file TestClass.java
package com.fido.android.sample.dsm.SoftPin.Core;
public class TestClass
{
public int mValue1;
public String mValue2;
}
Now in this file (TestClass.java) I want to declare one more class, but when I write for example:
public class SecondClass
{
// Class members goes here.
}
Compiler do not allow me to do that, if I remove public everything is Okay, but I can use SecondClass only in the TestClass.java, I can't write
SecondClass sc = new SecondClass();
out of TestClass.java class. Now I want to know if there is a way to do such thing, to have two classes in the same file and to use them from everywhere (not inner classes).
Question is: Why would you want to declare a second public class within the same Java class file? It is a rule in Java that each public class must be declared in a single class file - except for nested classes like Graham Borland pointed out.
Short answer: You can't.
That's how Java works.
You can only declare a single public class per file, with the class name the same as the file name.
You can use inner-classing as Graham suggested, or better yet, move the second class in a new file.
If you have SecondClass inside TestClass (i.e. nested inside the class definition), with public visibility, then you can refer to TestClass.SecondClass everywhere.
No, you can't, if the compiler chooses to enforce this rule from the Java 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 restriction implies that there must be at most one such type per compilation unit.
So this is optional in that it's still "legal Java" to include more than one public top-level class in a single source file - but it's also valid for the compiler to reject it. In practice, I think every file-based Java compiler I've ever used enforces this rule.
Now you could try to find a different compiler if you really wanted, but there's a reason for this: Java programmers are used to finding the source code for a public top-level type (and usually any top-level type) in a source file with the same name.
To ask a return question provocatively: why do you want to make your source code hard to navigate?
You cannot.
What you can do is to have inner classes.
According to java conventions, A public class should be created in a separate file having same name as of class name.
So you cannot make two public classes in same file.
you can try either removing public from one class or making inner class.
Since public classes must have the same name as the source file , there can only one pulbic class inside a java file.

Categories