This question already has answers here:
Difference between String[] arg and String[] args?
(7 answers)
Closed 2 years ago.
Why does
" public static void main(String[] arg) { "
work instead of
"public static void main(String[] args) { " ?
Does it have anything to do with the String-Array?
And how exactly does it work?
May using "arg" instead of "args" just be a tiny bit more efficient?
There is absolutely no difference, beyond the normal differences of parameter names (as in, you have to use the right name within the method body). The name of the parameter to the main method is entirely by convention. It's entirely valid to write:
public static void main(String[] dontUseJavaUtilDate)
as the declaration for your entry point.
From JLS 12.1.4 which uses Test
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 specify a formal parameter (§8.4.1) whose declared type is array of String.
There's no specification of the parameter name.
Ditto from the JVM specification section 5.2:
The Java Virtual Machine starts up by creating an initial class, which is specified in an implementation-dependent manner, using the bootstrap class loader (§5.3.1). The Java Virtual Machine then links the initial class, initializes it, and invokes the public class method void main(String[]). The invocation of this method drives all further execution. Execution of the Java Virtual Machine instructions constituting the main method may cause linking (and consequently creation) of additional classes and interfaces, as well as invocation of additional methods.
Related
When I want to refer to the method in the current scope I still need
to specify class name (for static methods) or this before ::
operator. For example, I need to write:
import java.util.stream.Stream;
public class StreamTest {
public static int trimmedLength(String s) {
return s.trim().length();
}
public static void main(String[] args) {
System.out.println(Stream.of(" aaa ", " bb ", " c ")
.mapToInt(StreamTest::trimmedLength).sum());
}
}
It's not so big problem for this, but sometimes look overcrowded for static methods as the class name can be quite long. It would be nice if compiler allowed me to write simply ::trimmedLength instead:
public static void main(String[] args) {
System.out.println(Stream.of(" aaa ", " bb ", " c ")
.mapToInt(::trimmedLength).sum());
}
However Java-8 compiler doesn't allow this. For me it seems that it would be quite consistent if class/object name were resolved in the same manner as it's done for normal method call. This would also support static imports for method references which also can be useful in certain cases.
So the question is why such or similar syntax was not implemented in Java 8? Are there any problems which would arise with such syntax? Or it was not simply considered at all?
I can’t speak for the Java developers but there are some things to consider:
There are certain kind of method references:
Reference to a static method, e.g. ContainingClass::staticMethodName
Reference to an instance method of a particular object, e.g. containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type, e.g. ContainingType::methodName
Reference to a constructor, e.g. ClassName::new
The compiler already has to do some work to disambiguate the forms 1 and 3 and sometimes it fails. If the form ::methodName was allowed, the compiler had to disambiguate between three different forms as it could be any of the three forms from 1 to 3.
That said, allowing the form ::methodName to short-cut any of the form 1 to 3 still wouldn’t imply that it is equivalent to the form methodName(…) as the expression simpleName ( argopt ) may refer to
an instance method in the scope of the current class or its superclasses and interfaces
a static method in the scope of the current class or its superclasses
an instance method in the scope of an outer class or its superclasses and interfaces
a static method in the scope of an outer class or its superclasses
a static method declared via import static
So saying something like “::name should be allowed to refer to any method name(…) may refer to” implies to combine the possibilities of these two listings and you should think twice before making a wish.
As a final note, you still have the option of writing a lambda expression like args -> name(args) which implies resolving name like a simple method invocation of the form name(args) while at the same time solving the ambiguity problem as it eliminates the option 3 of the method reference kinds, unless you write explicitly (arg1, otherargs) -> arg1.name(otherargs).
Given the following classes:
public abstract class Super {
protected static Object staticVar;
protected static void staticMethod() {
System.out.println( staticVar );
}
}
public class Sub extends Super {
static {
staticVar = new Object();
}
// Declaring a method with the same signature here,
// thus hiding Super.staticMethod(), avoids staticVar being null
/*
public static void staticMethod() {
Super.staticMethod();
}
*/
}
public class UserClass {
public static void main( String[] args ) {
new UserClass().method();
}
void method() {
Sub.staticMethod(); // prints "null"
}
}
I'm not targeting at answers like "Because it's specified like this in the JLS.". I know it is, since JLS, 12.4.1 When Initialization Occurs reads just:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
...
T is a class and a static method declared by T is invoked.
...
I'm interested in whether there is a good reason why there is not a sentence like:
T is a subclass of S and a static method declared by S is invoked on T.
Be careful in your title, static fields and methods are NOT inherited. This means that when you comment staticMethod() in Sub , Sub.staticMethod() actually calls Super.staticMethod() then Sub static initializer is not executed.
However, the question is more interesting than I thought at the first sight : in my point of view, this shouldn't compile without a warning, just like when one calls a static method on an instance of the class.
EDIT: As #GeroldBroser pointed it, the first statement of this answer is wrong. Static methods are inherited as well but never overriden, simply hidden. I'm leaving the answer as is for history.
I think it has to do with this part of the jvm spec:
Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.
This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.
In chapter 5 in the jvm spec they also mention:
A class or interface C may be initialized, among other things, as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic). These instructions reference a class or interface directly or indirectly through either a field reference or a method reference.
...
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
It seems to me the first bit of documentation states that any symbolic reference is simply resolved and invoked without regard as to where it came from. This documentation about method resolution has the following to say about that:
[M]ethod resolution attempts to locate the referenced method in C and its superclasses:
If C declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (§2.9), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1).
The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.
Otherwise, if C declares a method with the name and descriptor specified by the method reference, method lookup succeeds.
Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.
So the fact that it's called from a subclass seems to simply be ignored. Why do it this way? In the documentation you provided they say:
The intent is that a class or interface type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes.
In your example, you alter the state of Super when Sub is statically initialized. If initialization happened when you called Sub.staticMethod you would get different behavior for what the jvm considers the same method. This might be the inconsistency they were talking about avoiding.
Also, here's some of the decompiled class file code that executes staticMethod, showing use of invokestatic:
Constant pool:
...
#2 = Methodref #18.#19 // Sub.staticMethod:()V
...
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method Sub.staticMethod:()V
3: return
The JLS is specifically allowing the JVM to avoid loading the Sub class, it's in the section quoted in the question:
A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
The reason is to avoid having the JVM load classes unnecessarily. Initializing static variables is not an issue because they are not getting referenced anyway.
The reason is quite simple: for JVM not to do extra work prematurely (Java is lazy in its nature).
Whether you write Super.staticMethod() or Sub.staticMethod(), the same implementation is called. And this parent's implementation typically does not depend on subclasses. Static methods of Super are not supposed to access members of Sub, so what's the point in initializing Sub then?
Your example seems to be artificial and not well-designed.
Making subclass rewrite static fields of superclass does not sound like a good idea. In this case an outcome of Super's methods will depend on which class is touched first. This also makes hard to have multiple children of Super with their own behavior. To cut it short, static members are not for polymorphism - that's what OOP principles say.
According to this article, when you call static method or use static filed of a class, only that class will be initialized.
Here is the example screen shot.
for some reason jvm think that static block is no good, and its not executed
I believe, it is because you are not using any methods for subclass, so jvm sees no reason to "init" the class itself, the method call is statically bound to parent at compile time - there is late binding for static methods
http://ideone.com/pUyVj4
static {
System.out.println("init");
staticVar = new Object();
}
Add some other method, and call it before the sub
Sub.someOtherMethod();
new UsersClass().method();
or do explicit Class.forName("Sub");
Class.forName("Sub");
new UsersClass().method();
When static block is executed Static Initializers
A static initializer declared in a class is executed when the class is initialized
when you call Sub.staticMethod(); that means class in not initialized.Your are just refernce
When a class is initialized
When a Class is initialized in Java After class loading, initialization of class takes place which means initializing all static members of class. A Class is initialized in Java when :
1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class is assigned.
4) an static field of class is used which is not a constant variable.
5) if Class is a top level class and an assert statement lexically nested within class is executed.
When a class is loaded and initialized in JVM - Java
that's why your getting null(default value of instance variable).
public class Sub extends Super {
static {
staticVar = new Object();
}
public static void staticMethod() {
Super.staticMethod();
}
}
in this case class is initialize and you get hashcode of new object().If you do not override staticMethod() means your referring super class method
and Sub class is not initialized.
Object is the super type of all classes in Java. Consider my following class
public class Test {
public static void main1(Object[] args) {
System.out.println("I accept an object array");
}
public static void main(String[] args) {
main1(args);
}
}
Due to object superiority object array can accept any object type arrays. But Still java doesn't consider following class contains a main method.
public class Test {
public static void main(Object[] args) {
}
}
Why java never give this opportunity while object is ultimate supper type for all classes in java.
because java looks explicitly for public static void main(String[] args) when running.
specified in 12.1.4 of the jls
The method main must be declared public, static, and void. It must specify a formal parameter (§8.4.1) whose declared type is array of String. Therefore, either of the following declarations is acceptable:
Object wouldn't make sense, because you can not pass an other object through the console.
The main Method of Java is specified with strings as parameters. So the compiler can't detect the main-method with objects as args. I guess the resaon for this is, that the main method are usally called due an console command, and there you have only the opportunity to set strings as parameters.
The String[] were for command-line arguments, strings are what the user enters at the command line. Objects can't be entered from Command line.
From JLS:
The method main must be declared public, static, and void. It must
specify a formal parameter whose declared type is array of String.
Therefore, either of the following declarations is acceptable:
public static void main(String[] args)
public static void main(String... args)
there are a few ways to answer this
"because". the main() entry point to a program is specified like this and canot be overloaded to accept other arguments
as hinted by assylias, the main() method is expected to be invoked from a comamnd line or shell. this means that the arguements will always be strings. whatever you type on a command line is a string.
One point as all explain there is no way to pass object from console so it's meaningless.
Still as I also think Object is super class so why jvm does not understand it, but there is also other point that if jvm allowed to accept Object arguments than user can pass non-string variable as well so there jvm will create error that's why I think jvm make restrict to pass string variable.
JVM calls main() as a thread. When we call main() from another method in java, we call it as function or method.
Actually the confusion here is " why auto casting is not applicable when we try to call main(Object args) from console."
May be this restriction has been put in native methods of JVM to avoid the complications.
I you guys observe same case u will find for
catch(Object e)
Summery line: it is the native methods code of JVM which restricts the auto casting, to avoid complications.
The arguments passed to the main method are from command line. So they are String
main method can also be written like this
public static void main(String... args) {
}
This question already has answers here:
Why is String[] args required in Java?
(6 answers)
Closed 9 years ago.
When I see Java programs, many leave the String args[] on even though the program doesn't use them. Why is this? Anything in particular?
String args[] is part of the method signature for main. If you don't have it you will get the exception below when you try and run the code.
Exception in thread "main" java.lang.NoSuchMethodError: main
If it is for a main(String[]) it is to fulfill the method signature & therefore vital.
Its required by the specification.
The method main must be declared public, static, and void. It must
specify a formal parameter (§8.4.1) whose declared type is array of
String. Therefore, either of the following declarations is acceptable:
public static void main(String[] args)
public static void main(String... args)
Specification
The code within the main may not directly use it, but it is still required. 'String args[]' is where any command line arguments are passed. Even if you pass in 0 arguments, there needs to be a way for that to be verified. It is also the required signature for main by the requirements of the JVM.
New Java programmers often encounter messages like the following when they attempt to run a Java program. (Different Java tools, IDEs and so on give a variety of diagnostics for this problem.)
Error: Main method not found in class MyClass, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
Error: Main method not found in the file, please define the main method as:
public static void main(String[] args)
Error: Main method is not static in class MyClass, please define the main method as:
public static void main(String[] args)
Error: Main method must return a value of type void in class MyClass, please
define the main method as:
public static void main(String[] args)
java.lang.NoSuchMethodError: main
Exception in thread "main"
What does this mean, what can cause it, and what should one do to fix it?
When you use the java command to run a Java application from the command line, e.g.,
java some.AppName arg1 arg2 ...
the command loads the class that you nominated and then looks for the entry point method called main. More specifically, it is looking for a method that is declared as follows:
package some;
public class AppName {
...
public static void main(final String[] args) {
// body of main method follows
...
}
}
The specific requirements for the entry point method are:
The method must be in the nominated class.
The name of the method must be "main" with exactly that capitalization1.
The method must be public.
The method must be static 2.
The method's return type must be void.
The method must have exactly one argument and argument's type must be String[] 3.
(The argument may be declared using varargs syntax; e.g. String... args. See this question for more information. The String[] argument is used to pass the arguments from the command line, and is required even if your application takes no command-line arguments.)
If anyone of the above requirements is not satisfied, the java command will fail with some variant of the message:
Error: Main method not found in class MyClass, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
Or, if you are running an extremely old version of Java:
java.lang.NoSuchMethodError: main
Exception in thread "main"
If you encounter this error, check that you have a main method and that it satisfies all of the six requirements listed above.
1 - One really obscure variation of this is when one or more of the characters in "main" is NOT a LATIN-1 character … but a Unicode character that looks like the corresponding LATIN-1 character when displayed.
2 - Here is an explanation of why the method is required to be static.
3 - String must be the standard java.lang.String class and not to a custom class named String that is hiding the standard class.
The problem is that you do not have a public void main(String[] args) method in the class you attempt to invoke.
It
must be static
must have exactly one String array argument (which may be named anything)
must be spelled m-a-i-n in lowercase.
Note, that you HAVE actually specified an existing class (otherwise the error would have been different), but that class lacks the main method.
Other answers are doing a good job of summarizing the requirements of main. I want to gather references to where those requirements are documented.
The most authoritative source is the VM spec (second edition cited). As main is not a language feature, it is not considered in the Java Language Specification.
2.17.1 Execution - Virtual Machine Start-up
5.2 Virtual Machine Start-up
Another good resource is the documentation for the application launcher itself:
java - the Java application launcher
If you are running the correct class and the main is properly defined, also check if you have a class called String defined in the same package. This definition of String class will be considered and since it doesn't confirm to main(java.lang.String[] args), you will get the same exception.
It's not a compile time error since compiler just assumes you are defining a custom main method.
Suggestion is to never hide library java classes in your package.
The name of the exception suggests that the program tried to call a method that doesn't exist. In this context, it sounds like the program does not have a main method, though it would help if you posted the code that caused the error and the context in which the code was run.
This might have happened if the user tried to run a .class file or a .jar file that has no main method - in Java, the main method is the entry point to begin executing the program.
Normally the compiler is supposed to prevent this from happening so if this does happen, it's usually because the name of the method being called is getting determined ar run-time, rather than compile-time.
To fix this problem, a new programmer must either add the midding method (assuming still that it's main that's missing) or change the method call to the name of a method that does exist.
Read more about the main method here: http://csis.pace.edu/~bergin/KarelJava2ed/ch2/javamain.html
Generally, it means the program you are trying to run does not have a "main" method. If you are going to execute a Java program, the class being executed must have a main method:
For example, in the file Foo.java
public class Foo {
public static void main(final String args[]) {
System.out.println("hello");
}
}
This program should compile and run no problem - if main was called something else, or was not static, it would generate the error you experienced.
Every executable program, regardless of language, needs an entry point, to tell the interpreter, operating system or machine where to start execution. In Java's case, this is the static method main, which is passed the parameter args[] containing the command line arguments. This method is equivalent to int main(int argc, char** argv) in C language.
I feel the above answers miss a scenario where this error occurs even when your code has a main(). When you are using JNI that uses Reflection to invoke a method. During runtime if the method is not found, you will get a
java.lang.NoSuchMethodError: No virtual method
If you are using VSCode:
Choose: Clean Workspace
Choose: Restart and delete
Keep coding :-)
For those who encountered this problem in Kotlin Project.
You can try deleting .idea folder and running the project again - for me it solved the issue. (better close IntelliJ first)
Seems like sometimes IntelliJ gets all confused about the main method signature and expecting the java signature instead of the Kotlin one.
Few min back i was facing " main method not defined".Now its resolved.I tried all above thing but nothing was working.There was not compilation error in my java file.
I followed below things
simply did maven update in all dependent project (alt+F5).
Now problem solved.Getting required result.