Pregunta

La firma del método de un Java. principal() método es:

public static void main(String[] args){
    ...
}

¿Existe alguna razón para que este método sea estático?

¿Fue útil?

Solución

El método es estático porque de lo contrario habría ambigüedad: ¿a qué constructor debería llamarse? Especialmente si su clase se ve así:

public class JavaClass{
  protected JavaClass(int x){}
  public void main(String[] args){
  }
}

¿Debería la JVM llamar a new JavaClass(int)? ¿Qué debería pasar para x?

Si no es así, ¿debería la JVM instanciar JavaClass sin ejecutar ningún método de construcción? Creo que no debería ser así, porque eso hará un caso especial de toda su clase: a veces tiene una instancia que no se ha inicializado y debe verificarla en cada método que se pueda llamar.

Hay demasiados casos extremos y ambigüedades para que tenga sentido que la JVM tenga que instanciar una clase antes de que se llame al punto de entrada. Es por eso que main es estático.

No tengo idea de por qué public siempre está marcado como <=>.

Otros consejos

Esto es sólo una convención.De hecho, incluso el nombre main() y los argumentos pasados ​​son puramente convencionales.

Cuando ejecuta java.exe (o javaw.exe en Windows), lo que realmente sucede son un par de llamadas a la interfaz nativa de Java (JNI).Estas llamadas cargan la DLL que es realmente la JVM (así es, java.exe NO es la JVM).JNI es la herramienta que utilizamos cuando tenemos que unir el mundo de las máquinas virtuales y el mundo de C, C++, etc.Lo contrario también es cierto: no es posible (al menos que yo sepa) ejecutar una JVM sin utilizar JNI.

Básicamente, java.exe es una aplicación C súper simple que analiza la línea de comando, crea una nueva matriz de cadenas en la JVM para contener esos argumentos, analiza el nombre de clase que usted especificó que contiene main(), usa llamadas JNI para encontrar el main() método en sí, luego invoca el método main(), pasando la matriz de cadenas recién creada como parámetro.Esto es muy, muy parecido a lo que haces cuando usas la reflexión de Java: en su lugar, usa llamadas a funciones nativas con nombres confusos.

Sería perfectamente legal que escribieras tu propia versión de java.exe (la fuente se distribuye con el JDK) y que hiciera algo completamente diferente.De hecho, eso es exactamente lo que hacemos con todas nuestras aplicaciones basadas en Java.

Cada una de nuestras aplicaciones Java tiene su propio iniciador.Principalmente hacemos esto para obtener nuestro propio icono y nombre de proceso, pero ha resultado útil en otras situaciones en las que queremos hacer algo además de la llamada normal a main() para que todo funcione (por ejemplo, en un caso estamos haciendo interoperabilidad COM, y de hecho pasamos un identificador COM a main() en lugar de una matriz de cadenas).

Entonces, largo y corto:la razón por la que es estático es porque es conveniente.La razón por la que se llama 'main' es que tenía que ser algo, y main() es lo que hacían en los viejos tiempos de C (y en aquellos días, el nombre de la función era importante).Supongo que java.exe podría haberle permitido especificar simplemente un nombre de método principal completo, en lugar de solo la clase (java com.mycompany.Foo.someSpecialMain), pero eso hace que sea más difícil para los IDE detectar automáticamente el ' Clases lanzables en un proyecto.

El main() método en C++, C# y Java son estáticos
Porque luego pueden ser invocados por el motor de ejecución. sin tener que crear una instancia de cualquier objeto, entonces el código en el cuerpo de main() hará el resto.

¿Por qué public static void main (String [] args)?

Así es como se diseña Java Language y Java Virtual Machine se diseña y se escribe.

Especificación del lenguaje Oracle Java

Consulte Capítulo 12 Ejecución - Sección 12.1.4 Invocar Test.main :

  

Finalmente, después de completar la inicialización para la prueba de clase (durante la cual pueden haberse producido otras cargas, enlaces e inicializaciones consecuentes), se invoca el método principal de Test.

     

El método main debe declararse público, estático y nulo. Debe aceptar un único argumento que es una matriz de cadenas. Este método puede declararse como

public static void main(String[] args)
     

o

public static void main(String... args)

Especificación de máquina virtual Java de Oracle

Consulte Capítulo 2 Conceptos del lenguaje de programación Java - Sección 2.17 Ejecución :

  

La máquina virtual Java comienza la ejecución invocando el método main de alguna clase especificada y pasándole un único argumento, que es una matriz de cadenas. Esto hace que la clase especificada se cargue (& # 167; 2.17.2), se vincule (& # 167; 2.17.3) a otros tipos que usa y se inicialice (& # 167; 2.17. 4) El método main debe declararse público, estático y nulo.

Fuente Oracle OpenJDK

Descargue y extraiga el archivo fuente y vea cómo se escribe JVM, consulte ../launcher/java.c, que contiene el código C nativo detrás del comando java [-options] class [args...]:

/*
 * Get the application's main class.
 * ... ...
 */
if (jarfile != 0) {
    mainClassName = GetMainClassName(env, jarfile);

... ...

    mainClass = LoadClass(env, classname);
    if(mainClass == NULL) { /* exception occured */

... ...

/* Get the application's main method */
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                   "([Ljava/lang/String;)V");

... ...

{    /* Make sure the main method is public */
    jint mods;
    jmethodID mid;
    jobject obj = (*env)->ToReflectedMethod(env, mainClass,
                                            mainID, JNI_TRUE);

... ...

/* Build argument array */
mainArgs = NewPlatformStringArray(env, argv, argc);
if (mainArgs == NULL) {
    ReportExceptionDescription(env);
    goto leave;
}

/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

... ...

Simplemente imaginemos que static no sería necesario como punto de entrada de la aplicación.

Una clase de aplicación se vería así:

class MyApplication {
    public MyApplication(){
        // Some init code here
    }
    public void main(String[] args){
        // real application code here
    }
}

La distinción entre el código del constructor y el método main es necesaria porque en OO speak un constructor solo se asegurará de que una instancia se inicialice correctamente. Después de la inicialización, la instancia se puede usar para el & Quot; service & Quot ;. Poner el código completo de la aplicación en el constructor lo estropearía.

Entonces, este enfoque obligaría a tres contratos diferentes sobre la aplicación:

  • Debe debe ser un constructor predeterminado. De lo contrario, la JVM no sabría a qué constructor llamar y qué parámetros deberían proporcionarse.
  • debe ser un abstract método 1 . Ok, esto no es sorprendente.
  • La clase no debe ser <=>. De lo contrario, la JVM no podría crear una instancia.

El enfoque <=> por otro lado solo requiere un contrato :

  • Debe haber un <=> método 1 .

Aquí ni <=> ni los constructores múltiples son importantes.

Dado que Java fue diseñado para ser un lenguaje simple para el usuario , no es sorprendente que también el punto de entrada de la aplicación se haya diseñado de manera simple usando el contrato one y no de manera compleja utilizando tres contratos independientes y frágiles.

Tenga en cuenta: este argumento no trata sobre la simplicidad dentro de la JVM o dentro de la JRE. Este argumento trata sobre la simplicidad para el usuario .


1 Aquí la firma completa cuenta como un solo contrato.

Si no fuera así, ¿qué constructor debería usarse si hay más de uno?

Hay más información sobre la inicialización y ejecución de programas Java disponibles en Especificación del lenguaje Java .

Antes de llamar al método principal, no se instancian objetos. Tener la palabra clave estática significa que se puede llamar al método sin crear ningún objeto primero.

Porque de lo contrario, necesitaría una instancia del objeto para ejecutarse. Pero debe llamarse desde cero, sin construir primero el objeto, ya que generalmente es tarea de la función main () (bootstrap), analizar los argumentos y construir el objeto, generalmente usando estos argumentos / parámetros del programa.

¿Cuál es el significado de public static void main(String args[])?

  1. public es un especificador de acceso, lo que significa que cualquiera puede acceder / invocarlo, como JVM (Java Virtual Machine.
  2. static permite llamar a main() antes de que se haya creado un objeto de la clase. Esto es necesario porque la JVM llama a void antes de que se cree ningún objeto. Como es estático, se puede invocar directamente a través de la clase.

    class demo {    
        private int length;
        private static int breadth;
        void output(){
            length=5;
            System.out.println(length);
        }
    
        static void staticOutput(){
            breadth=10; 
            System.out.println(breadth);
        }
    
        public static  void main(String args[]){
            demo d1=new demo();
            d1.output(); // Note here output() function is not static so here
            // we need to create object
            staticOutput(); // Note here staticOutput() function is  static so here
            // we needn't to create object Similar is the case with main
            /* Although:
            demo.staticOutput();  Works fine
            d1.staticOutput();  Works fine */
        }
    }
    

    Del mismo modo, usamos static en algún momento para métodos definidos por el usuario, de modo que no necesitamos hacer objetos.

  3. String[] args indica que el método args se declara no devuelve un valor.

  4. String especifica el único parámetro en el método <=>.

    <=>: un parámetro que contiene una matriz de objetos de tipo de clase <=>.

Permítanme explicar estas cosas de una manera mucho más simple:

public static void main(String args[])

Todas las aplicaciones Java, excepto los applets, comienzan su ejecución desde main().

La palabra clave public es un modificador de acceso que permite llamar al miembro desde fuera de la clase.

static se utiliza porque permite llamar a void sin tener que crear una instancia particular de esa clase.

<=> indica que <=> no devuelve ningún valor.

Se construyen applets, midlets, servlets y beans de varios tipos y luego se les aplican métodos de ciclo de vida. Invocar main es todo lo que se hace a la clase main, por lo que no es necesario mantener un estado en un objeto que se llama varias veces. Es bastante normal anclar main en otra clase (aunque no es una gran idea), lo que obstaculizaría el uso de la clase para crear el objeto principal.

Es solo una convención, pero probablemente más conveniente que la alternativa. Con un main estático, todo lo que necesita saber para invocar un programa Java es el nombre y la ubicación de una clase. Si no fuera estático, también tendría que saber cómo crear una instancia de esa clase, o requerir que la clase tenga un constructor vacío.

Si el método principal no fuera estático, necesitaría crear un objeto de su clase principal desde fuera del programa. ¿Cómo le gustaría hacer eso?

Cuando ejecuta la máquina virtual Java (JVM) con el comando java,

java ClassName argument1 argument2 ...

Cuando ejecuta su aplicación, especifica su nombre de clase como argumento para el comando java, como arriba

la JVM intenta invocar el método principal de la clase que especifique

  

& # 8212; en este punto, no se han creado objetos de la clase.

     

Declarando main como estática allows la JVM a invoke main without creando   un instance de la clase.

volvamos al comando

ClassName es un command-line argument para la JVM que le dice qué clase ejecutar. Después de ClassName, también puede especificar un list of Strings (separado por espacios) como argumentos de línea de comandos que la JVM pasará a su aplicación. -Estos argumentos podrían usarse para especificar opciones (por ejemplo, un nombre de archivo) para ejecutar la aplicación; es por eso que hay un parámetro llamado String[] args en el principal

Referencias: Java & # 8482; Cómo programar (primeros objetos), décima edición

Creo que la palabra clave 'static' hace que el método principal sea un método de clase, y los métodos de clase solo tienen una copia y pueden ser compartidos por todos, y además, no requiere un objeto de referencia. Entonces, cuando se compila la clase de controlador, se puede invocar el método principal. (Estoy en el nivel alfabético de Java, perdón si me equivoco)

main () es estático porque; en ese punto del ciclo de vida de la aplicación, la pila de aplicaciones es de naturaleza procesal debido a que aún no hay objetos instanciados.

Es una pizarra limpia. Su aplicación se está ejecutando en este punto, incluso sin que se declare ningún objeto (recuerde, hay patrones de codificación de procedimiento Y OO). Usted, como desarrollador, convierte la aplicación en una solución orientada a objetos creando instancias de sus objetos y dependiendo del código compilado dentro.

Orientado a objetos es excelente por millones de razones obvias. Sin embargo, ya pasaron los días en que la mayoría de los desarrolladores de VB usaban regularmente palabras clave como & Quot; goto & Quot; en su código " goto " es un comando de procedimiento en VB que se reemplaza por su contraparte OO: invocación de método.

También podría ver el punto de entrada estático (principal) como pura libertad. Si Java hubiera sido lo suficientemente diferente como para crear una instancia de un objeto y presentarle solo esa instancia durante la ejecución, no tendría otra opción PERO escribir una aplicación de procedimiento. Por inimaginable que pueda parecer para Java, es posible que haya muchos escenarios que requieren enfoques de procedimiento.

Esta es probablemente una respuesta muy oscura. Recuerde, & Quot; clase & Quot; es solo una colección de código interrelacionado. " Instancia " es una generación autónoma aislada, viva y que respira de esa clase.

El prototipo public static void main(String[]) es una convención definida en JLS :

  

El método main debe declararse público, estático y nulo. Debe especificar un parámetro formal (& # 167; 8.4.1) cuyo tipo declarado es una matriz de String.

En la especificación JVM 5.2. Arranque de máquina virtual podemos leer:

  

La máquina virtual Java se inicia creando una clase inicial, que se especifica de manera dependiente de la implementación, utilizando el cargador de clases bootstrap (& # 167; 5.3.1). La máquina virtual Java luego vincula la clase inicial, la inicializa e invoca el método de clase pública void main (String []) . La invocación de este método impulsa todas las ejecuciones posteriores. La ejecución de las instrucciones de la máquina virtual Java que constituyen el método principal puede causar la vinculación (y, en consecuencia, la creación) de clases e interfaces adicionales, así como la invocación de métodos adicionales.

Lo curioso, en la especificación JVM no se menciona que el método principal tiene que ser estático. Pero la especificación también dice que la máquina virtual Java realiza 2 pasos antes:

  

La inicialización de una clase o interfaz consiste en ejecutar su método de inicialización de clase o interfaz.

En 2.9. Métodos especiales :

Se define un método de inicialización de clase o interfaz :

  

Una clase o interfaz tiene como máximo un método de inicialización de clase o interfaz y se inicializa (& # 167; 5.5) invocando ese método. El método de inicialización de una clase o interfaz tiene el nombre especial <clinit>, no toma argumentos y es nulo.

Y un método de inicialización de clase o interfaz es diferente de un método de inicialización de instancia definido de la siguiente manera:

  

En el nivel de la máquina virtual Java, cada constructor escrito en el lenguaje de programación Java (JLS & # 167; 8.8) aparece como un método de inicialización de instancia que tiene el nombre especial <init>.

Entonces, la JVM inicializa un método de inicialización de clase o interfaz y no un método de inicialización de instancia que en realidad es un constructor. Por lo tanto, no necesitan mencionar que el método principal debe ser estático en la especificación JVM porque está implícito en el hecho de que no se crea ninguna instancia antes de llamar al método principal.

Recientemente, se publicó una pregunta similar en Programmers.SE

TL; DR parte de la respuesta aceptada es,

  

En Java, la razón de public static void main(String[] args) es que

     
      
  1. Gosling quería
  2.   
  3. el código escrito por alguien experimentado en C (no en Java)
  4.   
  5. para ser ejecutado por alguien acostumbrado a ejecutar PostScript en NeWS
  6.   
     
    

 http://i.stack.imgur.com/qcmzP.png

  
     

& nbsp;
  Para C #, el razonamiento es transitivamente similar , por así decirlo. Los diseñadores de idiomas mantuvieron el punto de entrada al programa sintaxis familiar para programadores procedentes de Java. Como arquitecto C # Anders Hejlsberg lo pone ,

     
    

... nuestro enfoque con C # simplemente ha sido ofrecer una alternativa ... a los programadores de Java ...

  
     

...

Es solo una convención. La JVM ciertamente podría tratar con métodos principales no estáticos si esa hubiera sido la convención. Después de todo, puede definir un inicializador estático en su clase e instanciar un millón de objetos antes de llegar a su método main ().

La palabra clave public es un modificador de acceso, que permite al programador controlar La visibilidad de los miembros de la clase. Cuando un miembro de la clase está precedido por private, entonces eso Se puede acceder al miembro mediante un código fuera de la clase en la que se declara.

Lo opuesto a main() es static, que evita que un miembro sea utilizado por el código definido fuera de su clase.

En este caso, void debe declararse como <=>, ya que debe llamarse por código fuera de su clase cuando se inicia el programa.

La palabra clave <=> permite <=> para ser llamado sin tener que instanciar una instancia particular de la clase. Esto es necesario ya que el intérprete de Java llama a <=> antes de que se creen objetos.

La palabra clave <=> simplemente le dice al compilador que <=> no devuelve un valor.

El verdadero punto de entrada a cualquier aplicación es un método estático. Si el lenguaje Java admitía un método de instancia como & "; Punto de entrada &"; Entonces el tiempo de ejecución necesitaría implementarlo internamente como un método estático que construye una instancia del objeto seguido de llamar al método de instancia.

Con eso fuera del camino, examinaré los fundamentos para elegir una específica de las siguientes tres opciones:

  1. A static void main() como lo vemos hoy.
  2. Un método de instancia void main() llamado en un objeto recién construido.
  3. Usar el constructor de un tipo como punto de entrada (por ejemplo, si la clase de entrada se llamara Program, entonces la ejecución consistiría efectivamente en new Program()).

Desglose:

main()

  1. Llama al constructor estático de la clase envolvente.
  2. Llama al método estático new ClassName().

<=>

  1. Llama al constructor estático de la clase envolvente.
  2. Construye una instancia de la clase adjunta llamando efectivamente a <=>.
  3. Llama al método de instancia <=>.

<=>

  1. Llama al constructor estático de la clase envolvente.
  2. Construye una instancia de la clase (luego no hace nada con ella y simplemente regresa).

Justificación:

Iré en orden inverso para este.

Tenga en cuenta que uno de los objetivos de diseño de Java era enfatizar (exigir cuando sea posible) buenas prácticas de programación orientada a objetos. En este contexto, el constructor de un objeto inicializa el objeto, pero no debe ser responsable del comportamiento del objeto. Por lo tanto, una especificación que proporcionó un punto de entrada de <=> confundiría la situación para los nuevos desarrolladores de Java al forzar una excepción al diseño de un & Quot; ideal & Quot; constructor en cada aplicación.

Al hacer que <=> sea un método de instancia, el problema anterior ciertamente se resuelve. Sin embargo, crea complejidad al requerir que la especificación enumere la firma del constructor de la clase de entrada, así como la firma del método <=>.

En resumen, especificar un <=> crea una especificación con la menor complejidad mientras se adhiere al principio de colocar el comportamiento en los métodos . Considerando lo sencillo que es implementar un método <=> que en sí mismo construye una instancia de una clase y llama a un método de instancia, no hay una ventaja real al especificar <=> como método de instancia.

static: cuando la JVM realiza una llamada al método principal, no existe ningún objeto para la clase que se llama, por lo tanto, debe tener un método estático para permitir la invocación desde la clase.

No sé si la JVM llama al método principal antes de que los objetos sean instanciados ... Pero hay una razón mucho más poderosa por la cual el método main () es estático ... Cuando JVM llama al método principal del clase (por ejemplo, persona). lo invoca con " Person.main () " ;. Verá, la JVM lo invoca por el nombre de la clase. Es por eso que se supone que el método main () es estático y público para que JVM pueda acceder a él.

Espero que haya ayudado. Si lo hizo, avíseme comentando.

Los métodos estáticos no requieren ningún objeto. Se ejecuta directamente, de modo que el principal se ejecuta directamente.

La palabra clave estática en el método principal se usa porque no hay ninguna instanciación que tenga lugar en el método principal. Pero el objeto se construye en lugar de la invocación, como resultado utilizamos la palabra clave estática en el método principal. En el contexto jvm, la memoria se crea cuando la clase se carga y todos los miembros estáticos están presentes en esa memoria. si hacemos la estática principal ahora, estará en la memoria y podrá acceder a jvm (class.main (..)) para que podamos llamar al método principal sin necesidad de crear un montón.

Es solo una convención como podemos ver aquí:

  

El método debe declararse público y estático , no debe devolver ningún   valor, y debe aceptar una matriz de cadena como parámetro. Por defecto,   El primer argumento sin opción es el nombre de la clase a invocar.   Se debe usar un nombre de clase completamente calificado. Si la opción -jar es   especificado, el primer argumento sin opción es el nombre de un archivo JAR   que contiene archivos de clase y recursos para la aplicación, con el   clase de inicio indicada por el encabezado del manifiesto de clase principal.

http://docs.oracle. com / javase / 1.4.2 / docs / tooldocs / windows / java.html # descripción

  

Las palabras clave públicas de vacío estático significan que el intérprete de la máquina virtual Java (JVM) puede llamar al método principal del programa para iniciar el programa (público) sin crear una instancia de la clase (estática), y el programa no regresa datos al intérprete de Java VM (nulo) cuando finaliza.

Fuente: Essentials, Parte 1, Lección 2: Creación de aplicaciones

Básicamente, hacemos que los DATOS MIEMBROS y FUNCIONES DE LOS MIEMBROS como ESTÁTICOS que no realizan ninguna tarea relacionada con un objeto. Y en el caso del método principal, lo estamos haciendo como ESTÁTICO porque no tiene nada que ver con el objeto, ya que el método principal siempre se ejecuta si estamos creando un objeto o no.

Cualquier método declarado como estático en Java pertenece a la clase misma. Nuevamente, solo se puede acceder al método estático de una clase en particular haciendo referencia a la clase como Class_name.method_name();

Entonces, una clase no necesita ser instanciada antes de acceder a un método estático.

Entonces, el método main () se declara como static para que se pueda acceder sin crear un objeto de esa clase.

Dado que guardamos el programa con el nombre de la clase donde está presente el método principal (o desde donde el programa debe comenzar su ejecución, aplicable para clases sin un método main() () (Nivel avanzado)). Entonces, de la manera mencionada anteriormente:

Class_name.method_name();

se puede acceder al método principal.

En resumen, cuando el programa se compila, busca el método String que tiene main(String args[]) argumentos como: <=> en la clase mencionada (es decir, por el nombre del programa), y desde el principio tiene no hay margen para instanciar esa clase, por lo que el método main () se declara como estático.

De java.sun.com (hay más información en el sitio):

  

El método principal es estático para dar al intérprete de Java VM una forma de iniciar la clase sin crear primero una instancia de la clase de control. Las instancias de la clase de control se crean en el método principal después de que se inicia el programa.

Siempre he entendido que el método principal, como cualquier método estático, se puede invocar sin crear una instancia de la clase asociada, lo que le permite ejecutarse antes que cualquier otra cosa en el programa. Si no fuera estático, tendría que crear una instancia de un objeto antes de llamarlo, lo que crea un problema de 'huevo y gallina', ya que el método principal es generalmente el que se usa para instanciar objetos al comienzo del programa.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top