精华内容
下载资源
问答
  • main方法

    千次阅读 2018-07-12 16:15:21
    阅读数:3530[java] view plain copypublic static void main(String[] args) {} 或者[java] view plain copypublic static void main(String args[]) {} main方法是我们学习Java语言学习的第一个...
    
    
    [java]  view plain  copy
    1. public static void main(String[] args) {}  

    或者

    [java]  view plain  copy
    1. public static void main(String args[]) {}  
    main方法是我们学习Java语言学习的第一个方法,也是每个java使用者最熟悉的方法,每个Java应用程序都必须有且仅有一个main方法。在eclipse里可以使用输入main,在按住Alt+/的方式快速创建main方法。可以说main方法是最简单的方法,因为main方法几乎是固定不变得,除了String[] args可以写成String args[],以及args的名称可以改变外,其它所有均不改变。main方法也是特殊的,因为它的类型必须是public static void,甚至名字都必须是main,还有括号内的参数String[] args,很多初学者都不知道它的作用。正是这种简单而特殊的性质,往往容易让人对它产生忽视以及疑惑。下面就详细谈谈java main方法:

    根据Java语言规范,main方法必须声明为public。但是在JavaSE1.4以前的版本中,当main方法不是public时,有些版本的Java解释器也可以执行Java应用程序。详见http://bugs.sun.com/bugdatabase/index.jsp,bug号码4252539。当时SUN公司的工程师解释说,Java虚拟机规范并没有要求main方法一定是public。以上只是写出来,丰富一下兴趣。如果有人说Java main方法从来只能用public,那样说实际上还是错的,因为以前出过这么个BUG。但是在1.4版本之后main方法已经被强制成了public,所以现在我们看到的main方法只能是public。

    public是一种访问权限修饰符,public中文翻译共有,正如它的实际意思一样,在Java里面所有被public修饰的方法,类等都可以在任意其他地方调用。main方法之所以是public,是因为一个Java程序在运行时首先创建一个JVM实例,程序要运行需要调用main方法,JVM从外部调用main方法这就需要访问权限修饰符必须给出外部访问的权限,所以只能用public。

    static的定义是为了JVM在调用main方法时不用实例化对象,只需要在初始时加载main方法所在类,然后直接通过类名.main来调用main方法。

    void表示main方法没有返回值,没有返回值的原因是因为Java不需要main方法向操作系统返回退出信息。如果main方法正常退出,那么Java应用层序的退出代码为0,表示成功的运行了程序。

    main的名称不能变是为了JVM能够识别程序运行的起点,main方法可以被重载,重载的main方法不会被执行。main方法作为程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程,非守护线程和守护线程,main方法属于非守护线程,守护线程通常由JVM自己使用,Java程序也可以表明自己的线程是守护线程。当程序中所有的非守护线程终止时,JVM退出。也可以用Runtime类或者System.exit()来退出。

    String[] args,是main方法中唯一可以改变的地方!args是arguments的缩写,只是一个变量默认名,习惯性写作它,但是也可以改变的,只要符合命名规则随便你写成什么。在使用集成开发工具的今天,String[] args更像是一种摆设了,很多初学者都不知道它的作用,其实它是程序运行传入的一个参数组。一个简单的例子:

    用文本工具如下代码并将其保存为Test.java

    [java]  view plain  copy
    1. public class    Test{  
    2.     public static void main(String[] args){  
    3.         System.out.println("获取数组args[]的数据");  
    4.         for(int i=0;i<args.length;i++){  
    5.                      System.out.println(args[i]);  
    6.               }  
    7.     }  
    8. }  
    以管理员身份运行CMD,因为我的Test.java是直接保存在F盘中的,输入f:跳转到目录,输入Javac Test.java将其编译为Test.class文件


    然后输入Java Test 5 4 3 2 f xx,获取输出数据


    Java中所有方法的代码都是从“{”开始,以“}”结束。



    main方法还可以这样些

    public class TestSimple

    {

         public static void main(String... args)

        {

             System.out.println("你好啊");

        }

    }

    但有限制:这种写法也行,估计基本上没人知道吧。哈哈。顺便说下那个三个点是可变参数的意思,但是我没看到过有人写到main方法中的。只能这种情况的才行,其他变型的可变参数都不行。

    展开全文
  • idea如何运行main方法

    千次阅读 2021-03-08 01:18:37
    使用IntelliJ Idea 打包可执行 JAR 1、Model 结构如下: ...IDEA 发布 1.8.1 配置编译 class 的环境 1.8.2 配置 web 环境 1.8.3 发布到 tomcat 运行...Class: Main 这边 Main 既是运行类,含有 main()方法的一个类文...

    使用IntelliJ Idea 打包可执行 JAR 1、Model 结构如下: ...

    IDEA 发布 1.8.1 配置编译 class 的环境 1.8.2 配置 web 环境 1.8.3 发布到 tomcat 运行环境中 1.8.4 启动运行 1.8.5 发布到 war 文件操作完成后进入下一......

    Main-Class: Main 这边 Main 既是运行类,含有 main()方法的一个类文件,名字为 Main.class。 您的评论 发布评论 用户评价 力荐,jar可执行程序如何运行 2018-......

    值得注意的是, 该方法已执行完毕。 3.5 Drop frame 点击该按钮后,你将返回到当前方法的调用处(如上图,程序会回到 main()中) 重新执行, 并且所有上下文变量的......

    通过 cat 命令可以查看,我只截了一些关键的: 根据提示, 我们直接进入到文件夹 bin 目录下执行./idea.sh 即可启动: 之后便可以根据 UI 提示界面创建快捷方式,方......

    将 java 项目打包成可执行 jar 文件, 首先看一下我的 java project 结构, Main.java 是程序入口类,里面有 main 函数,config 目录是些配置文件,lib 是用到的......

    A.程序的执行总是从main函数开始,在main函数结束B.程序的执行总是从程序的第一个函数开始,在main函数结束C.程序的执行总是从main函数开始,在程序的最后一个函数......

    Read_Main_Idea2 段落支撑_生产/经营管理_经管营销_专业资料。段落支撑 paragraph support Main Ideas and Supporting Details ? ? ? ? ? ? ? ? ? Distinguish......

    正确答案及相关解析 正确答案 A 解析 [解析] 一个C语言源程序无论包括了多少函数,总是从main函数开始执行,从main函数结束。最新上传套卷......

    雅思阅读主旨题:怎么找main idea?_电子/电路_工程科技_专业资料。智课网雅思备考资料 雅思阅读主旨题:怎么找main idea? 雅思阅读主旨题尤其是段落标题配对题是雅思......

    android:textColor="@color/string_color" 上边是怎么使用颜色字符串 运行你的应用在 project 的创建过程中,IntelliJ IDEA 自动的生成了运行配置 android_hello_......

    实现方法 Ctrl+Shift+U,大小写转化 Ctrl+Y,删除当前行 Shift+Enter,向下插入新行 psvm/sout,main/System.out.println(); Ctrl+J,查看更多 Ctrl+Shift+F,......

    的方法名上使用会跳到具体的实现处,可 以跳过接口 Ctrl + Alt + V 快速引进变量 Ctrl + Alt + Y 同步、刷新 Ctrl + Alt + S 打开 IntelliJ IDEA 系统......

    main idea_英语学习_外语学习_教育专区。阅读 How to grasp main idea of a the passage in reading Ding-Dong! “Jason, honey? Can you answer the door?...

    比如 main 方法,我直接 Ctrl + J,然后输入 main 回车 就会自...

    这两个技巧实在太常 用了,几乎每天都要生成一堆 main、System.out 和 getter/setter。 另外,Intellij IDEA 13 中加入了后缀自动补全功能 (Postfix Completion),......

    阅读main-idea 中考英语阅读理解题(22分)可分为: 1.细节题(事实题...

    如何做主旨大意题? 高三英语科组 廖瑞燕 Teaching Aims: Help the students master how to get the main idea of a passage Important Points: 1.How to get......

    ___ In a unified paragraph, we expect all the sentences to be about the main idea of the paragraph. The main idea in this paragraph is "the descri......

    main idea主旨概括题讲课教案_英语_初中教育_教育专区。主旨概括题的阅读...

    展开全文
  • Java程序main方法执行流程

    千次阅读 2019-12-06 18:42:40
    Java程序main方法执行流程 当我们编写完java源代码程序后,经过javac编译后,执行java命令执行这个程序时,是怎么一步步的调用到我们程序中的main方法的呢?今天通过查看OpenJdk的源码来揭开它的神秘面纱。 java命令...

    Java程序main方法执行流程

    当我们编写完java源代码程序后,经过javac编译后,执行java命令执行这个程序时,是怎么一步步的调用到我们程序中的main方法的呢?今天通过查看OpenJdk的源码来揭开它的神秘面纱。

    java命令是在安装jre/jdk时配置到系统环境路径中去的,执行java命令时会找到bin目录下的java可执行程序,并将我们编译后的java程序类名传递进去就可以执行了。

    java可执行程序是由C++编写的,它的内部会启动一个Java虚拟机实例。
    虚拟机启动入口函数位于src/java.base/share/native/launcher/main.c。

    // src/java.base/share/native/launcher/main.c
    
    // java程序启动入口主函数
    JNIEXPORT int main(int argc, char **argv) {
        
        ...
        
        return JLI_Laucher(margc, margv,
                            jargc, (const char**) jargv,
                             0, NULL,
                       VERSION_STRING,
                       DOT_VERSION,
                       (const_progname != NULL) ? const_progname : *margv,
                       (const_launcher != NULL) ? const_launcher : *margv,
                       jargc > 0,
                       const_cpwildcard, const_javaw, 0)
            
    }
    
    
    // src/java.base/share/native/libjli/java.c
    
    JNIEXPORT int JNICALL JLI_Launch(int argc,
                                    char** argv,
                                    int jargc,
                                    const char** jargv,
                                    int appclassc,
                                    const char** appclassv,
                                    const char* fullversion,
                                    const char* dotversion,
                                    const char* pname,
                                    const char* lname,
                                    jboolean javaargs,
                                    jboolean cpwildcard,
                                    jboolean javaw,
                                    jint ergo) {
                                    
                                    
        ...               
        
        return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
    }
    
    
    int ContinueInNewThread(InvocationFunction* ifn, 
                            jlong threadStackSize, 
                            int argc, 
                            char **argv, 
                            int mode, 
                            char *what, 
                            int ret) {
        int rslt;
        
        ...
        
        rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);
        return (ret != 0) ? ret : rslt;
    }
    
    //真正调用Java类的main函数入口
    int JavaMain(void* _args) {
        JNIEnv *env = 0;
     
        jclass mainClass = NULL;
        //找到main函数所在的类
        mainClass = LoadMainClass(env, mode, what);   
        //获取main函数的参数
        mainArgs = CreateApplicationArgs(env, argv, argc);
        //从类中找到main方法标识
        mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                           "([Ljava/lang/String;)V");
        
        //调用main方法                                   
        (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
    }
    
    
    // src/java.base/macosx/native/libjli/java_md_macosx.m
    // src/java.base/unix/native/libjli/java_md_solinux.c
    
    int JVMInit(InvocationFunctions* ifn, jlkong threadStackSize, int argc,
                char **argv, int mode, char **what, int ret) {
                
        ...
        
        return continueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
    }
    
    CallJavaMainInNewThread(jlong stack_size, void* args) {
        
        int rslt;
        
        ...
        
        
        rslt = JavaMain(args);
        
        return rslt;
    }
    
    
    //hotspot/share/prims/jni.cpp
    
    //调用一个main这个静态方法
    static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) {
        
        JavaCalls::call(result, method, &java_args, CHECK);
    }
    
    // hotspot/share/runtime/javaCalls.cpp
    
    void JavaCalls::call(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) {
    
        os::os_exception_wrapper(call_helper, result, method, args, THREAD);
    }
    
    void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) {
    
        //字节码解释器入口函数地址
        address entry_point = method->from_interpreted_entry();
        if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
            entry_point = method->interpreter_entry();
        }
        
        ...
        
        通过call_stub->entry_point->method的调用链,完成Java方法的调用
        StubRoutines::call_stub()(
            (address)&link,//call_stub调用完后,返回值通过link指针带回来
            // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
            result_val_address,          // see NOTE above (compiler problem)
            result_type,
            method(),
            entry_point,
            parameter_address,
            args->size_of_parameters(),
            CHECK
          );
          
          result = link.result();//获取返回值
    }
    
    //  hotspot/share/runtime/stubRoutines.hpp
    
    // 将_call_stub_entry指针转换为CallStub类型,并执行该指针对应的函数
    // 这个_call_stub_entry指针是通过stubGenerator类在初始化生成的,
    // 这个stubGernerator负责为将要执行的方法创建栈帧,其实现区分不同CPU平台
    static CallStub call_stub() {
        return CAST_TO_FN_PTR(CallStub, _call_stub_entry);
    }
    
    // Calls to Java
    typedef void (*CallStub)(
        address   link,
        intptr_t* result,
        BasicType result_type,
        Method* method,
        address   entry_point,
        intptr_t* parameters,
        int       size_of_parameters,
        TRAPS
    );
    

    这里以x86_32平台为例进行说明_call_stub_entry的创建:

    // hotspot/cpu/x86/stubGenerator_x86_32.cpp
    
    class StubGenerator: public StubCodeGenerator {
        public:
        //构造函数
      StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
        if (all) {
          generate_all();
        } else {
          generate_initial();
        }
      }
      
      //初始化
      void generate_initial() {
        
        ...
        
        //创见CallStub实例,并赋值给StubRoutines::_call_stub_entry
        StubRoutines::_call_stub_entry =
          generate_call_stub(StubRoutines::_call_stub_return_address);
        
        ...
      }
      
    }
    
    
    //创建方法调用的栈帧
    address generate_call_stub(address& return_address) {
        
        //创建栈帧、参数入栈等
        
        ...
        
        __ movptr(rbx, method);           // 保存方法指针到rbx中
        __ movptr(rax, entry_point);      // get entry_point
        __ mov(rsi, rsp);                 // set sender sp
        
        //调用rax寄存器存储的解释器入口函数,这里解释器入口函数就是entry_point指针指向的函数
        //解释器就会开始从method指针指向的位置开始执行字节码
        __ call(rax);   
        
        ...
    }
    

    下面看一下解释器的入口函数的实现,从前面可以知道解释器入口函数是从method中获取到的。

    // hotspot/share/oops/method.hpp
    
    //该方法被内联了,即获取成员变量_from_interpreted_entry的值。
    address from_interpreted_entry() const;
    
    inline address Method::from_interpreted_entry() const {
      return Atomic::load_acquire(&_from_interpreted_entry);
    }
    
    // _from_interpreted_entry是在link_mehtod函数被赋值的。
    void Mehthd
    
    

    那么_from_interpreted_entry是在什么时候被赋值的呢?在链接方法时。

    // hotspot/share/oops/method.cpp
    
    void Method::link_method(const methodHandle& h_method, TRAPS) {
        
        ...
        
        if (!is_shared()) {
            //终于和字节码解释器勾搭上了
            //根据h_method的类型取出对应的解释器入口函数
            address entry = Interpreter::entry_for_method(h_method);
            set_interpreter_entry(entry);
        }
        
        ...
    }
    
    // hotspot/share/interpreter/abstractInterpreter.hpp
    
    //解释器入口函数数组
    static address  _entry_table[number_of_method_entries];
    
    static MethodKind method_kind(const methodHandle& m);
    static address entry_for_kind(MethodKind k){ 
         return _entry_table[k];
    }
    
    //从methodHandle中取出方法类型MethodKind,并根据方法类型从_entry_table取出对应的解释器入口函数地址
    static address entry_for_method(const methodHandle& m){
        return entry_for_kind(method_kind(m));
    }
    
    //虚拟机启动时通过该函数填充_entry_table数组
    static void set_entry_for_kind(MethodKind k, address e);
    

    那么到底是什么时候调用的set_entry_for_kind函数来初始化的呢?

    在文章开头说过,launcher/main.c中的main函数是java程序的启动函数,在main函数中调用了JLI_Launcher函数,在JLI_Launcher会调用LoadJavaVM函数加载虚拟机的动态链接库,并找到创建虚拟机的入口函数JNI_CreateJavaVM存储到结构体InvocationFunctions中。
    这个结构体InvocationFunctions会一直当做参数传递到JavaMain函数中。
    之后再JavaMain函数中,会根据JNI_CreateJavaVM虚拟机创建函数来初始化虚拟机,此时已经是在一个新的线程中运行了。

    下面看一下具体的调用流程:

    // src/java.base/share/native/libjli/java.c
    
    JNIEXPORT int JNICALL JLI_Launch(int argc,
                                    char** argv,
                                    int jargc,
                                    const char** jargv,
                                    int appclassc,
                                    const char** appclassv,
                                    const char* fullversion,
                                    const char* dotversion,
                                    const char* pname,
                                    const char* lname,
                                    jboolean javaargs,
                                    jboolean cpwildcard,
                                    jboolean javaw,
                                    jint ergo) {
                                    
                                    
        ...               
        
        //Java虚拟机动态链接库的路径
        char jvmpath[MAXPATHLEN];
        //
        InvocationFunctions ifn;
        
        //从参数中读取虚拟机运行环境所需的配置
        CreateExecutionEnvironment(&argc, &argv,
                                   jrepath, sizeof(jrepath),
                                   jvmpath, sizeof(jvmpath),
                                   jvmcfg,  sizeof(jvmcfg));
        
        ifn.CreateJavaVM = 0;
        ifn.GetDefaultJavaVMInitArgs = 0;
        
        //加载Java虚拟机动态链接库,并找到创建虚拟的函数JNI_CreateJavaVM
        //这里会区分不同平台和CPU位数,但大体上就是使用dlopen和dlsym这个两个系统调用来实现
        if (!LoadJavaVM(jvmpath, &ifn)) {
            return(6);
        }
        ...
        
        return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
    }
    

    下面以macos平台为例看一下LoadJavaVM的实现:

    // src/java/base/macosx/native/libjli/java_md_macosx.m
    
    jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
    {
        //动态链接库文件句柄
        void *libjvm;
        
        //判断是否是静态编译,使用dlopen函数打开动态链接库
    #ifndef STATIC_BUILD
        libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
    #else
        libjvm = dlopen(NULL, RTLD_FIRST);
    #endif
    
        //使用dlsym函数根据函数符号找到对应函数地址
        //这里一共获取了三个函数JNI_CreateJavaVM、JNI_GetDefaultJavaVMInitArgs、JNI_GetCreatedJavaVMs
        //如果有任何一下缺失都会返回错误,如果成功则将三个函数存储到InvocationFunctions结构体中。
        ifn->CreateJavaVM = (CreateJavaVM_t)
            dlsym(libjvm, "JNI_CreateJavaVM");
            
        ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
            dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
            
        ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
        dlsym(libjvm, "JNI_GetCreatedJavaVMs");
        
        return JNI_TRUE;
    }
    

    从动态链接库中找到创建虚拟机的入口函数后,会把InvocationFunctions结构体作为参数一路传递到JavaMain函数中,并在其中发起调用。

    // src/java.base/share/native/libjli/java.c
    
    int JavaMain(void* _args) {
        //将参数强制转换为JavaMainArgs类型
        JavaMainArgs *args = (JavaMainArgs *)_args;
        //从参数取出InvocationFunctions结构体
        InvocationFunctions ifn = args->ifn;
        
        JavaVM *vm = 0;
        JNIEnv *env = 0;
        
        ...
        
        //初始化Java虚拟机
        if (!InitializeJVM(&vm, &env, &ifn)) {
            JLI_ReportErrorMessage(JVM_ERROR1);
            exit(1);
        }
        
        ...
    }
    
    static jboolean InitializaJVM(JavaVM **pwm, JNIENV **penv, InvocationFunctions *ifn) {
        JavaVMInitArgs args;
        jint r;
    
        memset(&args, 0, sizeof(args));
        args.version  = JNI_VERSION_1_2;
        args.nOptions = numOptions;
        args.options  = options;
        args.ignoreUnrecognized = JNI_FALSE;
        
        //调用JNI_CreateJavaVM函数创建虚拟机,该函数内部会转调JNI_CreateJavaVM_inner函数
        r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
        JLI_MemFree(options);
        return r == JNI_OK;
    }
    
    // hotspot/share/prims/jni.cpp
    
    static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) {
        jint result = JNI_ERR;
        
        //通过Threads的create_vm函数创建虚拟机
        result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);
        
        if (result == JNI_OK) {
           JavaThread *thread = JavaThread::current();
            *vm = (JavaVM *)(&main_vm);
            *(JNIEnv**)penv = thread->jni_environment(); 
            post_thread_start_event(thread);
            ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native);
        }
        ...
        
        return result;
    }
    

    Threads::create_vm函数非常长,里面执行了很多初始化工作。例如

    • 预初始化信息,可以在初始化虚拟机之前预先初始化一些可能用到的信息,如虚拟机版本。不同的CPU平台可以在这里初始化自己定义的信息。
    • 初始化ThreadLocalStorage
    • 初始化输出流模块
    • 初始化os操作系统模块,主要是一些固定配置
    • 初始化系统属性
    • 初始化JDK版本
    • 根据JDK版本初始化特定参数
    • 解析命令行参数
    • 初始化和应用ergonomics,主要是初始化大内存页,根据CPU核心数、内存容量设置虚拟内存页大小、JVM内存参数、GC策略、java8取消永久代新增Metaspace区。
    • 解析完参数后,二次初始化os模块。例如快速线程时钟、Linux信号处理器、最小栈长度、最大文件描述符数量、线程优先级策略等
    • 初始化安全点机制,安全点机制是很重要的概念。安全点是指一些特定的位置,当线程运行到这些位置时,线程的一些状态可以被确定。
    • 初始化输出流日志
    • 加载系统库
    • 初始化全局数据结构。如java基础类型、事件队列、全局锁、JVM性能统计区、大块内存池chunkpool等
    • 创建JavaThread
    • 初始化对象监视器ObjectMonitor,它是Java语言级别的同步子系统
    • 初始化全局模块,这些模块是Hotspot的整体基础,如字节码初始化、类加载器初始化、编译策略初始化、解释器初始化等等。我们前面追踪的_entry_table数组就是在这里面初始化的。
    • 创建VMThread,并开始执行。VMThread用于执行VMOptions
    • 初始化主要JDK类,如String类、System类,Class类、线程/线程组类、Module类,还有其他反射、异常相关的类
    • 初始化jni方法的快速调用
    • 标记虚拟机的基本初始化完成
    • 日志系统的后续配置
    • 元数据区Metaspace的后续配置
    • 初始化jdk信号支持
    • 初始化Attach监听机制,它是JVM提供进程间通信机制,负责接收处理其他进程发送过来的命令
    • 初始化JSR292标准核心类,JSR292标准引入invokedynamic指令以支持调用动态类型语言中的方法,使得在把源码编译成字节码时不需要确定方法的签名。当运行invokedynamic指令时,JVM会通过新的动态链接机制Method Handles,寻找到真实的方法。
    • 第二阶段,初始化模块化系统
    • 第三阶段,初始化安全管理器、设置系统类加载器作为线程上下文的类加载器
    • 启动监听线程WatcherThread,用来模拟时钟中断。

    Threads::create_vm函数中做了上面那么多工作,这里为了简单就不讲所有源码都贴出来了。
    因为_entry_table数组的填充是在init_globals()函数中调用的,所以只说明一下init_globals()函数的调用路径。

    // hotspot/share/runtime/thread.cpp
    jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
        
        ...
        
        //初始化全局模块
        jint status = init_globals();
        
        ...
        
        return JNI_OK;
    }
    
    
    // hotspot/share/runtime/init.cpp
    jinit init_globals() {
        ...
        
        //初始化方法处理适配器
        MethodHandles::generate_adapters();
        ...
    }
    
    // hotspot/share/prims/methodHandles.cpp
    MethodHandlesAdapterBlob* MethodHandles::_adapter_code = NULL;
    void MethodHeandles::generate_adapters() {
        _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size);
        CodeBuffer code(_adapter_code);
        MethodHandlesAdapterGenerator g(&code);
        g.generate();
    }
    
    void MethodHandlesAdapterGenerator::generate() {
        //1.生成通用方法处理适配器
        //2.生成解释器入口点
        
        //这里的MethodKinds是一个枚举类型,声明了虚拟机固有的方法类型
        for (Interpreter::MethodKind mk = Interpreter::method_handle_invoke_FIRST;
        mk <= Interpreter::method_handle_invoke_LAST;
        mk = Interpreter::MethodKind(1 + (int)mk)) {
        vmIntrinsics::ID iid = Interpreter::method_handle_intrinsic(mk);
        StubCodeMark mark(this, "MethodHandle::interpreter_entry", vmIntrinsics::name_at(iid));
        
        //根据方法类型ID生成对应的方法处理解释器入口点,并通过set_entry_for_kind设置到abstractInterpreter.cpp中的_entry_table数组中。
        address entry = MethodHandles::generate_method_handle_interpreter_entry(_masm, iid);
        if (entry != NULL) {
          Interpreter::set_entry_for_kind(mk, entry);
        }
      }
    }
    
    // hotspot/share/interpreter/abstractInterpreter.cpp
    
    void AbstractInterpreter::set_entry_for_kind(AbstractInterpreter::MethodKind kind, address entry) {
    
        //将解释器入口点填充到_entry_table数组中
         _entry_table[kind] = entry;
    
         update_cds_entry_table(kind);
    }
    

    到此就可以总结一下了,当我们通过java命令执行一个应用程序时,首先会先启动虚拟机实例,启动过程中包含了很多初始化工作,这些工作是为java程序提供运行环境的必要条件。在初始化工作中会根据不同的方法类型构建对应解释器入口点,并存储到一个数组_entry_table中。
    当初始化工作完成后,会调用java应用程序的入口方法(static void main(String[] args)),然后根据main方法的类型从_entry_table数组中找出对应的解释器入口点,然后就开始解释执行main方法的字节码了。

    最后介绍一下JVM中都预定义了哪些方法类型。

    // hotspot/share/interpreter/abstractInterpreter.hpp
    
    enum MethodKind {
        //大多数没有声明为native和synchronized方法都属于这种类型
        //在执行之前要将局部变量初始化为0
        zerolocals,                                                 // method needs locals initialization
        zerolocals_synchronized,                                    // method needs locals initialization & is synchronized
        native,                                                     // native method
        native_synchronized,                                        // native method & is synchronized
        //空方法,也单独由特定解释器处理,避免创建无效的栈帧
        empty,                                                      // empty method (code: _return)
        //成员变量的get方法
        accessor,                                                   // accessor method (code: _aload_0, _getfield, _(a|i)return)
        abstract,                                                   // abstract method (throws an AbstractMethodException)
        method_handle_invoke_FIRST,                                 // java.lang.invoke.MethodHandles::invokeExact, etc.
        method_handle_invoke_LAST                                   = (method_handle_invoke_FIRST
                                                                       + (vmIntrinsics::LAST_MH_SIG_POLY
                                                                          - vmIntrinsics::FIRST_MH_SIG_POLY)),
        
        //一些固定作用的方法,直接指定特定的解释器入口,提高效率
        java_lang_math_sin,                                         // implementation of java.lang.Math.sin   (x)
        java_lang_math_cos,                                         // implementation of java.lang.Math.cos   (x)
        java_lang_math_tan,                                         // implementation of java.lang.Math.tan   (x)
        java_lang_math_abs,                                         // implementation of java.lang.Math.abs   (x)
        java_lang_math_sqrt,                                        // implementation of java.lang.Math.sqrt  (x)
        java_lang_math_log,                                         // implementation of java.lang.Math.log   (x)
        java_lang_math_log10,                                       // implementation of java.lang.Math.log10 (x)
        java_lang_math_pow,                                         // implementation of java.lang.Math.pow   (x,y)
        java_lang_math_exp,                                         // implementation of java.lang.Math.exp   (x)
        java_lang_math_fmaF,                                        // implementation of java.lang.Math.fma   (x, y, z)
        java_lang_math_fmaD,                                        // implementation of java.lang.Math.fma   (x, y, z)
        java_lang_ref_reference_get,                                // implementation of java.lang.ref.Reference.get()
        java_util_zip_CRC32_update,                                 // implementation of java.util.zip.CRC32.update()
        java_util_zip_CRC32_updateBytes,                            // implementation of java.util.zip.CRC32.updateBytes()
        java_util_zip_CRC32_updateByteBuffer,                       // implementation of java.util.zip.CRC32.updateByteBuffer()
        java_util_zip_CRC32C_updateBytes,                           // implementation of java.util.zip.CRC32C.updateBytes(crc, b[], off, end)
        java_util_zip_CRC32C_updateDirectByteBuffer,                // implementation of java.util.zip.CRC32C.updateDirectByteBuffer(crc, address, off, end)
        java_lang_Float_intBitsToFloat,                             // implementation of java.lang.Float.intBitsToFloat()
        java_lang_Float_floatToRawIntBits,                          // implementation of java.lang.Float.floatToRawIntBits()
        java_lang_Double_longBitsToDouble,                          // implementation of java.lang.Double.longBitsToDouble()
        java_lang_Double_doubleToRawLongBits,                       // implementation of java.lang.Double.doubleToRawLongBits()
        number_of_method_entries,
        invalid = -1
      };
    
    展开全文
  • java中main方法发送httpPost请求

    热门讨论 2013-10-29 13:44:03
    java语言后台请求网站操作 java中main方法发送httpPost请求
  • Java application 中的主类需包含 main 方法,以下哪项是 main 方法的正确形参?( )答:String ar[]美国对德国的文化清洗活动持强烈的批评态度。()答:√根据课程内容,京东认为的“金子”型员工指的是( )答:个人...

    Java application 中的主类需包含 main 方法,以下哪项是 main 方法的正确形参?( )

    答:String ar[]

    美国对德国的文化清洗活动持强烈的批评态度。()

    答:√

    根据课程内容,京东认为的“金子”型员工指的是( )

    答:个人能力很强,价值观及个人目标与组织高度一致

    下列关于空驶的说法,错误的是

    答:空车行驶无论从哪个角度看都是不合理运输的表现。

    金融发展与经济发展的关系是相互促进而不是独立

    答:正确

    高速铁路应急管理的内涵包括;预防,预备,()和恢复4个阶段

    答:响应

    当代资本主义发生的变化从根本上说是人类社会发展一般规律和资本主义经济规律作用的结果

    答:√

    在场景营销视角下,消费是物品消费。

    答:错误

    智慧职教: 明代的果园厂作为官方漆器工场,专门生产( )漆器。

    答:雕漆

    黑钻级冰酒是有冰葡萄压榨出来的第一道原汁发酵而成的,占整个冰酒产量小于( ?)。

    答:0.05

    文化是指人类社会历史实践过程中所创造的()和()的总和

    答:物质财富;精神财富

    在目前条件下人的生殖性克隆势必会导致妇女的工具化和客体化(物化),这属于反对生殖性克隆的()论证

    答:尊重人类尊严的论证

    不以实际成本为主要依据,而是以市场需求为定价出发点,力求使价格为消费者接受的定价方法是

    答:反向定价法

    成为建设领导的新型人民军队的重要开端是()

    答:三湾改编

    钢结构实腹式压弯构件在弯矩作用平面内整体稳定性验算公式中γ主要是考虑( )。

    答:截面塑性发展对承载力的影响

    蝴蝶的口器是

    答:虹吸式口器

    我国目前已经形成一套完善的新闻法,专门规定新闻传播中的一系列报道活动。

    答:错

    为什么要实现全体人民共同富裕,因为共同富裕是( ? )。

    答:马克思主义的基本目标 中国的奋斗目标 体现社会主义本质

    语气是“思想感情( ? ?)状态支配下语句的声音形式”。

    答:运动

    Excel的工作表中,每一行和列的交叉处为()。

    答:单元格

    In reply, we have the pleasure of informing you that an L/C has been opened amounting ____$2,000

    答:to

    Java application 中的主类需包含 main 方法,以下哪项是 main 方法的正确形参?( )

    展开全文
  • Java main方法快捷键

    千次阅读 2021-03-01 22:31:28
    快捷键:psvm,就会出现main方法的提示: 然后回车: public static void main(String[] args) { }
  • 先说结论:main方法启动后,jvm会开启多个守护线程,但main方法中的代码是被单线程执行的。 上代码: 下面这段代码通过java提供的线程管理类ThreadMXBean中的dumpAllThreads方法返回所有活动线程的线程信息,并打印...
  • java中main方法的运行

    千次阅读 2019-10-27 14:28:18
    (最近要把一个main方法启动的项目集入web项目里,参考了main方法的运行机制才解决。) 学过java的都知道main方法是学习java的开始,也是程序的入口,不过你有多少个类或程序,线程,他们的入口方法都是main()...
  • 为什么 main 方法是 public static void ?

    千次阅读 多人点赞 2020-02-18 14:52:05
    文章目录 1、为什么main方法是静态的(static) 2、为什么main方法是公有的(public) 3、为什么main方法没有返回值(Void) 4、总结 main 方法是我们学习Java编程语言时知道的第一个方法,你是否曾经想过为什么 ...
  • springboot在main方法中调用service

    千次阅读 2021-04-19 16:49:08
    一般我们测试自己的mybatis是否能正常读取数据库,需要在main方法中调用service,解决方案如下: 遇到报错,加上@ComponentScan("com.aiccms.system.*")注解问题解决。读者可根据自身环境去加注解。 package ...
  • 一定要在main方法中创建对象吗

    千次阅读 2021-03-09 04:58:09
    一般我们看见的对象一般都是在main方法里面创建的,然后这个对象也是在main方法里面使用,出去就不可以用了,可以理解为局部对象也可以在普通方法中创建.但是main作为一个程序的入口, 你只有在main中创建对象, ...
  • java中main方法的返回类型是?

    千次阅读 2021-02-12 20:20:21
    man方法是void类型,void没有返回值类型在java语言程序编写时都会涉及到一个main方法,它的格式为:public static void main(String[] args)(一般必须这么定义,这是java规范)在这里修饰符public和static的顺序是...
  • scala的MAIN方法

    千次阅读 2020-02-13 20:53:25
    MAIN方法 scala和Java一样,如果要运行一个程序,必须有一个main方法。而在Java中main方法是静态的,而在scala中没有静态方法。在scala中,这个main方法必须放在一个单例对象中。 定义Main方法 main方法 scala def ...
  • jar包中有多个main方法,执行指定.java文件的main方法: java -cp jar包名 包名.类名 参数 举例: 执行test.jar包中cn.com.test.send包下Send.java中的main方法 参数有四个 java -cp test.jar ...
  • 执行jar包中指定main方法

    千次阅读 2019-11-26 19:01:31
    通过maven将应用打成jar包之后,可以通过java -jar ***.jar来执行,会运行指定的main方法,主要是 MANIFEST.MF 中指定的 main 方法;那么如果有多个main方法的时候如何运行指定的main方法哪,可以通过下面命令去执行...
  • Idea运行main方法没反应

    千次阅读 2020-11-05 14:36:16
    Idea中右键点击执行main方法没反应的解决办法 点击设置找到Plugins选项搜索Groovy选项,将后面方框中的对号删除,会提示重启Idea,重启后就OK了。
  • Main方法执行完之后,JVM不退出,解决方案: 因为Main方法执行完之后,有线程未关闭,所以JVM肯定不会退出, 解决方法1(治本):使用debug方式运行main,看Eclipse的debug界面或者看jstack,找出main方法结束后还...
  • main方法中调用持久层service或dao

    万次阅读 2017-10-15 22:42:41
    后台经常需要单独写个test类来测试业务方法或进行其他涉及到持久层的操作,有时更简单就直接在main方法中测,这时候是无法直接调用已经写好的持久层(例如service或dao层),controller中如下写@Autowired ...
  • Eclipse运行项目找不到main方法

    千次阅读 2021-03-04 23:53:02
    eclipse中代码写好了,却找不到main方法无法运行的解决措施 ​ 在类中找不到main()方法,请将main定义为:public static void main(String[ ] args)否则JavaFX应用程序类必须扩展为javafx.application.Application ...
  • java中main方法的作用

    万次阅读 2018-06-16 15:51:56
    main方法是我们学习Java语言学习的第一个方法,也是每个java使用者最熟悉的方法,每个Java应用程序都必须有且仅有一个main方法。在eclipse里可以使用输入main,在按住Alt+/的方式快速创建main方法。可以说main方法是...
  • 如何在Linux环境中执行main方法

    千次阅读 2019-01-29 17:01:17
    对于程序员来说,很闹心的一个问题就是在生产上找bug,太太太难了,所以写测试类是一个用到很普遍的方法,那么测试类的main方法是如何被调用的呢,其实很简单啦。Linux命令:java -cp jar包 类的全限定名 参数 ...
  • intellij idea快速生成main方法、for循环、out输出

    万次阅读 多人点赞 2018-03-17 12:21:08
    输入sout,按下enter键,生成System.out.println()方法. sout---&gt;soutv=System.out.println("变量名 = " + 变量) soutp---&gt;System.out.println("") 2、public...
  • C#中Main方法参数的设置方式

    千次阅读 2019-05-16 14:48:23
    控制台应用程序,Main函数是应用程序的入口,Main函数可以有四种签名,分别如下: static void Main() static void Main(string[] args) static int Main() static int Main(string[] args) 对于参数string[] args的...
  • 错误: 在类 cn.lizixiang.dbcp.Example01 中找不到 main 方法, 请将 main 方法定义为: public static void main(String[] args) 否则 JavaFX 应用程序类必须扩展javafx.application.Application 解决方法:保存一下 ...
  • main方法中查询数据库和插入数据库

    万次阅读 2020-08-14 17:37:01
    public static void main(String[] args) { try { Connection con = null; Class.forName("com.mysql.jdbc.Driver").newInstance(); // mysql驱动 con = (Connection) DriverManager.getConnection("jdbc:mysql...
  • main方法详解

    千次阅读 2017-05-20 23:50:52
    学习Java有一段时间了,一直没用过博客来写写自己在学习过程中遇到的问题和学习心得,看到别人在诸如...话不多说,就以main方法详解开始今天的主题吧。  为了表述方便,我先把mian方法写出来: public class Demo
  • SpringBoot如何在main方法调用Controller 前言 根据功能需求,一般Controller层是用来处理外部请求的,最常见的就是@RequestMapping("../..")这样的书写,但是有时会遇到不通过外部,而由自己手动发起去调用这个...
  • 新手 找不到 main 方法

    2017-05-09 13:15:50
    我跟着视频教程一样的编辑...报错:错误: 在类 com.imooc1.Demo 中找不到 main 方法, 请将 main 方法定义为: public static void main(String[] args) 否则 JavaFX 应用程序类必须扩展javafx.application.Application
  • Java中main方法的理解和执行过程

    千次阅读 2020-04-27 17:19:08
    main方法的格式讲解: public static void main(String[] args) {...} public:公共的,访问权限是最大的。由于main方法是被jvm调用,所以权限要够大。 static:静态的,不需要创建对象,通过类名就可以。方便jvm的...
  • python 程序入口 main-Python中的main方法

    千次阅读 2020-11-11 14:12:04
    估计很多人跟我一样初学python看代码的时候先找一下main()方法,从main往下看。但事实上python中是没有你理解中的“main()”方法的。言归正传if name == "main":可以看成是python程序的入口,就像java中的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,989,965
精华内容 1,595,986
关键字:

main方法