JVM(一)一文读懂Java编译全过程

article/2025/8/24 18:44:35

一文读懂Java编译全过程

java代码首先要通过前端编译器编译成.class字节码文件,然后再按一定的规则加载到JVM(java 虚拟机)内运行,有三种运行方式,解释模式(javac)、编译模式(C1 JIT、C2 JIT)、混合模式(javac+(C1 OR C2))。解释模式下,一边执行字节码一边解释执行;编译模式下,字节码编译为机器码后执行;混合模式下,正常情况下使用解释执行,但是针对经常执行的代码,会采用JIT技术进行编译执行。无论是server运行模式下还是client运行模式下,都有可能采用解释+(C1 OR C2 )执行。但本文的重点不在执行,而是编译,包括前端编译器、C1 JIT、C2 JIT。

如:一个是client 虚拟机模式,一个是server虚拟机模式,都是混合模式执行。
在这里插入图片描述
在这里插入图片描述

语言处理器种类

  1. 编译器,如gcc、javac。
  2. 解释器,如Ruby、Python、JAVA.EXE等一些一些语言使用解析器来实现的。
  3. IDE,如Eclipse、NetBeans等。
  4. 代码分析器,如FindBugs等。
  5. 反编译器,如JD、Jad、Reflector.NET等。

Java编译过程

Java文件编译过程包括两个阶段,第一阶段是在编译阶段编译成Java字节码的过程,有些书籍中叫前端编译器,如Oracle的javac编译器;第二阶段是在运行时,通过JVM的编译优化组件,对代码中的部分代码编译成本地代码,即JIT编译,如HotSpot中的C1、C2编译器( Thus the threads used by client JIT compiler are called c1 compiler threads. Threads used by the server JIT compiler are called c2 compiler threads.)。JVM整个编译过如下图所示。

在这里插入图片描述

其中,编译状态有如下9种。

//编译状态 
public enum CompileState {INIT(0),//初始化PARSE(1),//解析ENTER(2),//处理符号表PROCESS(3),//核心处理ATTR(4),//符号解析FLOW(5),//流分析TRANSTYPES(6),//解泛型为非泛型等类型转换UNLAMBDA(7),//解LAMBDA表达式LOWER(8),//解语法糖GENERATE(9);//生成字节码}

下面是JIT编译器和C1(C2)编译器编译流程。
在这里插入图片描述

Javac前端编译器

当我们在控制台执行javac命令时,找到javac对应的环境变量的可执行文件,通过JNI方式调用com.sun.tools.javac.Main.java中的main方法进入。也就是说Javac编译工作是由Java代码完成的。像javap,javah等命令也都是通过Java代码完成的。

   /*** launcher的入口.* Note: 该方法调用了System.exit.* @param args 命令行参数*/public static void main(String[] args) throws Exception {System.exit(compile(args));}//此代码段在Main#compile方法中,用于读取Java文件对象用于编译。if (!files.isEmpty()) {// add filenames to fileObjectscomp = JavaCompiler.instance(context);List<JavaFileObject> otherFiles = List.nil();JavacFileManager dfm = (JavacFileManager)fileManager;for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files))otherFiles = otherFiles.prepend(fo);for (JavaFileObject fo : otherFiles)fileObjects = fileObjects.prepend(fo);}//调用JavaCompiler#compile方法comp.compile(fileObjects,//要编译的文件对象classnames.toList(),//注解处理的类名processors);//用户提供的注解处理器

最终调用JavaCompiler.compile()方法进行编译处理。如果自行编译,可以调用java中提供的工具类ToolProvider.getSystemJavaCompiler() 自行进行编译。如下是JavaCompiler.compiler()方法。

   /*** 主方法:要编译的文件列表,返回所有编译的类* @param sourceFileObjects 要编译的文件对象* @param classnames 为类中注解处理的类名* @param processors 用户提供的注解处理器,null意味着没有处理器提供。*/public void compile(List<JavaFileObject> sourceFileObjects,List<String> classnames,Iterable<? extends Processor> processors){if (processors != null && processors.iterator().hasNext())explicitAnnotationProcessingRequested = true;// 由于JavaCompiler只能使用一次,如果以前使用过,则抛出异常if (hasBeenUsed)throw new AssertionError("attempt to reuse JavaCompiler");hasBeenUsed = true;// forcibly set the equivalent of -Xlint:-options, so that no further// warnings about command line options are generated from this point onoptions.put(XLINT_CUSTOM.text + "-" + LintCategory.OPTIONS.option, "true");options.remove(XLINT_CUSTOM.text + LintCategory.OPTIONS.option);start_msec = now();try {//检查是否要处理注解initProcessAnnotations(processors);// (1)这些方法必须是链式调用以避免内存泄漏delegateCompiler =processAnnotations(enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))),classnames);// (2)分析和生成字节码delegateCompiler.compile2();delegateCompiler.close();elapsed_msec = delegateCompiler.elapsed_msec;} catch (Abort ex) {if (devVerbose)ex.printStackTrace(System.err);} finally {if (procEnvImpl != null)procEnvImpl.close();}}

从上面的代码可知,编译真正处理的代码在(1)和(2)处。对代码分析,编译处理包括以下三个部分。分别为解析与填充符号表、注解处理、分析和生成字节码三个大阶段。

在这里插入图片描述

解析与填充符号表

解析与填充符号表,对应图一的词法分析、语法分析、抽象语法树、填充符合表几个细节处理。在解释语法树之前,我们首先要说下什么是语法树,语法树在很多语言中都有采用,如java、sql源码阅读中都用到了语法树的概念。如下的英语句子的语法树。
在这里插入图片描述

根据上面源码中的(1)注解中的代码,解析与填充符号表包括以下几个步骤。

delegateCompiler =processAnnotations(enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))),classnames);
  1. parseFiles方法会执行parserFactory#newParser方法,在该方法内部封装了Scanner类并借助于JavaTokenizer类实现词法分析(手写的ad-hoc方式构造的词法分析器),词法分析可以简单理解为java文件中的每个空格之间的字符当作一个标记。源文件经过Unicode转义处理,通过Scanner类转化为令牌流。Parser类读取令牌流,使用TreeMaker创建语法树。而语法树通过com.sun.source.Tree及其子类的JCTree类或其子类实现的。语法树可理解为JCTree中每个节点表示一个包、类型等语法结构。每个树最后传递给Enter类,为遇到的所有定义的符号传入符号字面量。这必须在解析树之前做好,因为可能引用这些符号。该阶段输出的是“待办”列表,其中包含需要分析并生成文件的树。而Parser#parseCompilationUnit方法用于语法分析。
  2. enterTrees方法主要用于填充符号表。主要由Enter类实现。Enter包含很多阶段,要编译的类通过队列从一个阶段传到下一个阶段。

在这里插入图片描述

  • 在第一个阶段,所有的类符号都进入到Enter的范围之内,树中其他类的成员变量都严格降序排列。类符号被赋予一个MemberEnter对象作为"完成者"。除此之外,如果任何package-info.java文件被找到,并且包含包注解。树节点的顶层将会为该文件添加到“代办”列表。

  • 将符号输入到符号表。com.sun.tools.javac.comp.Enter,每个编译单元的抽象语法树的顶局节点都先被放到待处理列表中,逐个处理列表中的节点,所有类符号被输入到外围作用域的符号表中,若找到package-info.java,将其顶局树节点加入到待处理列表中,确定类的参数(对泛型类型而言)、超类型和接口,根据需要添加默认构造器,将类中出现的符号输入到类自身的符号表中,分析和校验代码中的注解(annotation)。
    添加的默认构造器如下。
    在这里插入图片描述

  • 在第二阶段,类使用MemberEnter.complete()来完成。类是按需完成的,但是未按照此方式完成的类最终都会通过处理未完成的队列来完成。完成需要:(1)决定类的变量、超类和接口。(2)将类中定义的所有符号输入,但是在第一阶段已经完成的符号变量除外。(2)依赖于(1)中的类及其所有超类和封闭类已经完成。这就是为什么在(1)之后,我们将类放入到一个半完成的队列中。只有当我们对一个类及其所有超类和内部类执行了(1)之后,我们才继续执行(2)。

  • 输入所有的符号后,在这些符号上遇到的所有注解将会分析和验证。

    第一阶段是组织被遍历所有编译的语法树,而第二阶段是按需的,类的成员在第一次访问类的内容时输入,这是通过在编译类的类符号中使用completer对象来实现的,编译类调用对应类的树的MemberEnter阶段。

注解处理

注解是JDK1.5中引入的,对于注解的处理可以理解为编译器的一组插件,根据注解解析结果对抽象语法树进行修改,如lombok。方法processAnnotations是注解处理的入口,当由注解需要处理时,则由JavacProcessingEnvironment#doProcessing方法创建一个JavaCompiler对象来完成。从概念上来讲,注解处理是编译之前的一个初步步骤。这个初步动作由一系列的循环组成(如图2)。每个循环用于解析和输入源文件,然后确定和调用适当的注解处理器。在首次循环之后,如果被调用的任何注解处理器生成任何需要作为最后编译一部分的新原文件或类时,将需要执行后面的循环。最后,当所有必要的循环完成,执行实际编译。

在这里插入图片描述

在实际中,调用任何注解处理器的需要可能要等到要编译的文件被解析并且包含的声明被确定之后才能知道。因此,为了避免在不执行注解处理的情况下不必要地解析和输入源文件,JavacProcessingEnvironment对概念模型的执行有点不同,但是仍满足注解处理器作为一个整体在实际编译前执行。

在这里插入图片描述

当class文件被编译,并且已经解析和填充符号后。JavacProcessingEnvironment将会被调用。该类决定被编译的文件哪些注解需要被加载或被调用。通常,如果在整个编译过程中出现任何错误,该过程则在下一个合适的点停止编译。但是,如果在符号解析阶段出现丢失符号,则会抛出异常,因为定义这些符号可能作为注解处理器的结果。

如果要运行注释处理器,将在单独的类加载器中加载并运行它们。

当注解处理器运行时,JavacProcessingEnvironment决定是否需要另外一轮注解处理。如果需要,将会创建一个新的对象JavaCompiler。读取上步骤新生成的源文件进行解析。并且重新使用之前的语法树进行解析。所有的这些树都被输入到这个新编译器实例的符号表中,并且根据需要调用注解处理器。然后重复直到所有的注解编译完成。

最后,JavacProcessingEnvironment返回JavaCompiler对象用于编译剩下的部分。这个对象是用于解析和输入初始文件集的原始实例,或者是JavacProcessingEnvironment创建的用于开始最后一轮编译的最新实例。

下面以lombok为例说明

  1. 注解处理之前。

在这里插入图片描述
2. 注解处理后
在这里插入图片描述

分析和生成字节码

当命令行中指定的所有文件被解析并输入到编译器的符号表中,并且注解也已经处理,JavaCompiler能处理分析的语法树,以生成相应的class文件。由delegateCompiler.compile2()方法进入。

   /*** 注释处理之后的阶段:属性、解语法糖,最后是代码生成。*/private void compile2() {try {switch (compilePolicy) {case ATTR_ONLY://只需解析数据的属性attribute(todo);break;case CHECK_ONLY://用于属性和解析树的流分析检查flow(attribute(todo));break;case SIMPLE://流分析、语法糖处理、生成字节码generate(desugar(flow(attribute(todo))));break;case BY_FILE: {Queue<Queue<Env<AttrContext>>> q = todo.groupByFile();while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) {generate(desugar(flow(attribute(q.remove()))));}}break;case BY_TODO:while (!todo.isEmpty())generate(desugar(flow(attribute(todo.remove()))));break;default:Assert.error("unknown compile policy");}} catch (Abort ex) {if (devVerbose)ex.printStackTrace(System.err);}if (verbose) {elapsed_msec = elapsed(start_msec);log.printVerbose("total", Long.toString(elapsed_msec));}reportDeferredDiagnostics();if (!log.hasDiagnosticListener()) {printCount("error", errorCount());printCount("warn", warningCount());}}

当分析树时,可以找到对成功编译所需的类的引用,但是这些类没有显示指定用于编译。根据编译选项,将在源路径和类路径中搜索此类的类定义。如果能在类文件中找到定义,将自动分析、输入源文件并将其放到待办事项列表中。这些在Attr.SourceCompleter类中实现。

分析树和生成类文件的工作由一系列的观察者来处理进入了编译器代办事项列表。这些观察者没有必要分步对所有的源文件处理。事实上,内存问题会使这极不可取。唯一的要求是,“代办”列表最终会被每一个观察者处理,除非编译因为错误而提前终止。

  1. Attr和Check

    顶层类是“Attribute",使用Attr,这意味着语法树中的名称、表达式和其他元素将被解析并与相对应的类型和符号相关联。这可以通过Attr类或Check类检查到许多语义错误。

语法分析的一个步骤,将语法树中名字、表达式等元素不变量、方法、类型等联系到一起,检查变量使用前是否已声明,推导泛型方法的类型参数,检查类型匹配性,迕行常量折叠。

下面举例说明。
(1)标注前。
在这里插入图片描述

(2)标注后。
在这里插入图片描述

  1. Flow

    如果到目前没有错误,将会使用Flow进行类的流分析。流分析用于检查变量的明确分配和不可到达语句。检查所有checked exception都被捕获或抛出;检查变量的确定性赋值(1)所有局部变量在使用前必项确定性赋值;(2)有返回值的方法必须确定性返回值;检查变量的确定性不重复赋值(1)为保证final的语义。

  2. TransTypes

    将泛型类型的类转变为TransTypes类(裸类型,普通的java类型),同时插入必要的类型转换代码。

    下面给个示例。
    (1)类型转换前。
    在这里插入图片描述
    (2)类型转化后。
    在这里插入图片描述

  3. Lower

    语法糖使用Lower类来处理,它重写语法树,通过替换等价、简单子树来消除特定类型的子树。这将会处理内部类和嵌套类,类字面量,断言,foreach循环等。对于每个被处理的类,Lower类返回已转变类及所有转变的嵌套类和内部类的树的列表。尽管Lower通常处理顶层类,但也处理package-info.java的顶层树。对于这种树,Lower类将创建合成类来包含包的任何注解。
    在这里插入图片描述

    削除if (false) { … }形式癿无用代码。满足下述所有条件的代码被认为是条件编译的无用代码◦if语句的条件表达式是Java语言规范定义的常量表达式◦并且常量表达式值为false则then块为无用代码;反之则else块为无用代码。

示例

(1)Lower前
在这里插入图片描述
(2)Lower后
在这里插入图片描述

  1. Gen

    Gen类用于方法代码的编译,它创建包含字节码的Code属性,通过JVM实例来执行方法。如果该步骤成功,则编译后的类由ClassWriter类写出。

一旦一个类作为类文件被写出来,它的许多语法树和生成的字节码就不再需要了。为了节省内存,对树的这些部分和符号的引用将为空,以允许垃圾收集器恢复内存。

  1. 将实例成员初始化器收集到构造器中成为();将静态成员初始化器收集为();
  2. 从抽象语法树生成字节码。(1)后序遍历语法树(如下);(2)进行最后的少量代码转换,如String的+被生成为StringBuilder操作;x++/x–在条件允许时被优化为++x/–x
  3. 从符号表生成Class文件◦生成Class文件的结构信息。生成元数据(包括常量池)
    在这里插入图片描述

整个前端编译过程如下图所示。
在这里插入图片描述
以上步骤已经生成了.class文件。在运行期间,编译器将会进一步优化,即JIT优化。

JIT编译

JIT是即时编译器(Just In Time Compiler)的缩写,Hotspot中有两个即时编译器,分别为Client Compiler(C1 JIT)和Server Compiler(C2 JIT),C1和C2都是将字节码编译成本地代码,区别可以理解为C1是局部优化,而C2可以理解为专门面向服务端的。JVM有三种运行模式,分别是解释(interpreted mode)、编译模式(compiled mode)和混合模式(mixed mode)三种模式。**Java1.8中默认的解释器与其中一个JIT编译器直接配合的方式执行,即采用混合模式。**用户可以通过参数"-Xint"强制虚拟机运行在解释模式,此时编译器不工作。当然也可以使用参数"-Xcomp"强制虚拟机运行于“编译模式”。这时优先采用编译方式执行,但在某些情况下,解释器不得不介入才能执行。

编译条件

编译优化的条件主要针对热点代码,而热点代码主要有两种情况:

  1. 多次被调用的方法
  2. 多次执行的循环体

无论第一种情况还是第二种情况,都是以整个方法作为编译对象。第二种情况而不是以循环体作为编译对象。只是处理方式不同,因为第二种编译方式发生在方法执行体中,而在运行时表现为方法栈,通过替换方法栈中的部分代码为编译后的本地代码,即通过栈上替换(On Stack Replacement,OSR)的方式进行JIT编译。

很显然,无论采用哪种方法,编译器都需要识别哪些代码为热点代码。目前热点代码探测的方式有两种。

  1. 基于采样的热点探测。虚拟机启动一个检测线程周期性检查各个线程的栈顶,如果发现某个方法经常在栈顶,则认为是"热点代码"。这种方式简单但是不能精确统计某个方法的热点,且容易受线程阻塞等外界因素影响,当线程阻塞时,某个方法就会一直处于栈顶,从而不能精确统计方法的执行次数。
  2. 基于计数器的热点探测。虚拟机会为每个方法建立计数器,如果该方法超过规定的次数则认为是热点代码。

在HotSpot中采用的是第二种方式,且对同一个方法采用了两个计数器。一个是记录在某段时间内方法调用次数的计数器,当某段时间内不满足编译时,则次数会衰减一半,所以是某段时间内的相对次数。另一个是记录方法中的循环体的计数器(称为回边计数器),而这个计数器会一直往上增长,是绝对计数,当溢出时,则调整计数器的值为溢出状态。当该两个计数器超过默认的阈值,则发生JIT编译。下面表格是不同编译模式下的默认值。两个计数器都可以通过虚拟机参数进行设定。

方法调用计数器回边计数器
1500次13995次
C210000次10700次

编译过程

默认情况下,当虚拟机中的编译线程编译完成后,才能替换到JIT编译请求。用户可以通过参数-XX:-BackgroundCompilation来禁止后台编译。

C1编译优化主要在AdvancedThresholdPolicy.cpp文件中。

编译优化技术

公共子表达式消除、方法内联、逃逸分析

参考

1、http://openjdk.java.net/groups/compiler/doc/compilation-overview/index.html

2、(重要文章)JVM c1, c2 compiler thread — high CPU consumption? https://medium.com/@RamLakshmanan/jvm-c1-c2-compiler-thread-high-cpu-consumption-b99acc604f1d

3、(javac编译操作)Compile All Java Classes in Directory Structure with javac,https://www.baeldung.com/javac-compile-classes-directory

4、(内容同3)Compile Java Files. https://www.baeldung.com/javac

5、https://www.oracle.com/java/technologies/whitepaper.html


http://chatgpt.dhexx.cn/article/UHjNdGm2.shtml

相关文章

无需插件修改chrome浏览器UA标识为手机版

可能在手机上我们可以很方便的操作将网页的UA设置为电脑版或者是其他的&#xff0c;但是在电脑上一般没有直接的操作修改&#xff0c;网上的经验也一般为使用User-Agent Switcher 插件,修改。其实使用开发者工具就已经能够很方便的修改UA了 首先在对应的页面按下F12&#xff0c…

使用PC端谷歌Chrome浏览器浏览手机网页 修改PC端谷歌Chrome浏览器UA

废话不多说直接上干货&#xff08;快下班了&#xff09;&#xff1a; 1.进入你想要审查元素的网站&#xff0c;比如www.baidu.com&#xff1b; 2.按F12召唤开发者窗口&#xff1b; 3.点击下图框出来的三个点&#xff1a; 4.点击下图框出来的选项&#xff1a; 5.将下面框选住…

【测试】抓包获取浏览器UA,并使用Chrome 调试工具模拟手机

抓包获取浏览器UA 首先需要先安装charles&#xff0c;在http的请求头当中可以看到User-Agent&#xff0c;复制该User-Agent的内容 如果你是前端开发&#xff0c;也可通过以下代码获取UA $(‘body’).html(navigator.userAgent);构造UA 然后打开chrome浏览器的调试工具&…

自定义浏览器UA标识

正文 手机浏览器改成下面这段&#xff0c;可以享受到百度的纯净浏览。 Mozilla/5.0 (Linux; U; Android 10; zh-CN; 2014811 Build/QQ3A.200805.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.2564.116 Quark/3.8.2.126 Mobile Safari/537.36 T7/10.…

修改浏览器UA的作用汇总

1.浏览器标识&#xff08;UA&#xff09; 可以使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件&#xff0c;从而判断用户是使用电脑浏览还是手机浏览&#xff0c;让网页作出自动的适应。    可理解为网站通过…

一篇文章带你了解清楚什么是UA

最近在做一部分的UA的统计、正好做下记录、有需要的同学也可以借鉴一下 一、首先讲一下UA是什么 UA&#xff0c;全称为“User Agent”&#xff0c;中文通常直译为“用户代理”&#xff0c;但从其产生作用的机制来看&#xff0c;或许称之为“浏览器标识”或“浏览器名片”更为妥…

小白想学大数据?

一.大数据领域的从业人员,应该牢牢把握2018年大数据这三个大的技术方向: 1、Hadoop大数据开发方向; 2、数据挖掘、数据分析和机器学习方向; 3、大数据运维和云计算方向。精通任何方向之一者,均会前(钱)途无量。 3个方向中,大数据开发是基础。以Hadoop开发工程师为例,…

Java开发者,我到底要不要学大数据开发?

一入编程深似海&#xff0c;从此女神是路人。没办法&#xff0c;这行就这样。你不学Spring&#xff0c;总不是跑去学JVM/微服务架构/分布式去了&#xff0c;不断学习根本避免不了。所以关键在于把时间投在学什么上比较划算。 明确表达我的观点&#xff0c;作为一名Javaer进阶大…

从0开始学大数据-数据仓库建模

为什么要数据仓库建模 数据模型是数据组织和存储方法&#xff0c;它强调从业务、数据存取和使用角度合理存储数据。有了适合业务和基础数据存储环境的模型&#xff0c;那么大数据就能获得以下好处&#xff1a; 性能&#xff1a;良好的数据模型能帮助我们快速查询所需要的数据&a…

【金猿案例展】某国家级研究所——组学大数据分析平台建设

荣联科技集团案例 本案例由荣联科技集团投递并参与“数据猿年度金猿策划活动——2020大数据产业创新服务企业榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 大数据时代下&#xff0c;科学大数据已经成为科技创新和社会经济发展的新动力。生物信息学经过近…

零基础学大数据分析现实吗

学习大数据分析已然成为社会的大势所趋&#xff0c;随着传统公司的被迫更新&#xff0c;新兴公司的数据人才增多&#xff0c;大数据技术显得格外的重要。当大数据的大浪凶猛袭来时&#xff0c;要么你冲上浪尖&#xff0c;做时代的弄潮儿&#xff0c;要么被打入海底&#xff0c;…

零基础可以学大数据分析吗

国家的大数据战略实施已经到了关键的落地时期&#xff0c;创新、实体经济都跟大数据分析有着深度的融合&#xff0c;在各行各业都能看到大数据分析师的身影&#xff0c;另外大数据安全管理和立法等方面也进入到了关键时刻&#xff0c;所有这些无不在向人们诉说着一个事实&#…

学大数据需要具备四种条件?你具备几种?

现在学大数据的越来越多了&#xff0c;可是你知道学大数据需要什么条件吗&#xff1f;我来说说四个必备条件。 大数据现已成为年代开展的趋势&#xff0c;很多人纷纷挑选学大数据&#xff0c;想要进入大数据职业。大数据技术体系巨大&#xff0c;包含的常识较多&#xff0c;体…

学大数据专业后悔死了?学大数据以后好就业吗?

前言 从近几年来看&#xff0c;大数据专业的就业情况和就业前景是非常不错的&#xff0c;而所谓的学大数据专业后悔死了等等言论都是不实或偏激的。小编在收集整理相关资料后发现大多数同学认为学大数据专业后悔死了有两个原因&#xff1a;一是大数据专业学习难度大&#xff0…

女生适合学大数据开发吗,女生怎样学大数据开发

红遍全球的大数据开发,不仅仅吸引了男孩子的目光,更是让不少女孩子为之兴奋。但是有些女孩子被刻板成见所击败,不敢涉足大数据开发。那么,女生适合学大数据开发吗?女生应该怎样学习大数据开发? 女生适合学大数据开发吗: 1、女生适不适合学大数据开发这个问题,就跟女生…

哪些人适合学大数据分析

哪些人适合学大数据分析&#xff0c;实际上&#xff0c;问题还有个潜台词是“什么人学习数据分析&#xff0c;会更容易取得成功(比如职业成功)”&#xff0c;这个要关乎你的兴趣、付出和机遇。但要做到出类拔萃&#xff0c;除了上面三点&#xff0c;还需要一点天赋&#xff0c;…

从0开始学大数据(十二)

30 | 当大数据遇上物联网 某位互联网大佬说过&#xff0c;未来 20 年最有发展潜力的三项技术分别是&#xff1a;区块链、人工智能、物联网。关于区块链&#xff0c;现在可能是最有争议也是最迷茫的时候&#xff1b;关于人工智能的价值&#xff0c;我们已经达成共识并稳步发展&…

零基础学大数据难吗?

零基础学大数据难吗&#xff1f;通过各大招聘平台我们可以看到&#xff0c;同样都是互联网技术岗位&#xff0c;大数据技术岗位的薪资普遍较高&#xff0c;不仅仅是因为目前布局大数据技术是各个企业的战略目标&#xff0c;同时也因为大数据技术有一定的难度&#xff0c;那对于…

《从0开始学大数据》的启示

《从0开始学大数据》学习后感 方法论与哲学学习的目的以及形成思维体系抽象能力&#xff0c;为什么是A而不是B&#xff1f;从MR-Spark看产品思维模式思维 大数据发展历史分布式计算的核心思想——移动计算而非移动数据大数据系统与大型网站系统设计思路的差异大型网站的思路大数…

大数据需要学哪些内容

大数据技术是当今互联网时代的热点之一&#xff0c;目前已经成为了各行各业中的最佳选择。随着物联网、人工智能、云计算等技术的发展&#xff0c;数据的规模不断增大&#xff0c;数据分析、数据挖掘、人工智能等应用也随之蓬勃发展&#xff0c;对大数据开发的需求越来越多。因…