Know Your Stack - Scala to Java to Bytecode to Assembly

TPM2-Startup-学习手册.docx 内容概要:本文深入解析了TPM 2.0中首个必要命令TPM2_Startup的工作机制,涵盖其在芯片初始化中的核心作用、启动类型决策逻辑、内部九个初始化阶段的详细流程,以及DRTM/H-CRTM安全机制的实现原理。文档结合源码(ibmswtpm2-tpm2)与实测报文,系统阐述了Startup如何通过状态校验、locality控制、PCR管理、密码学初始化、DA防护、ACT定时器、NV索引处理等环节,确保TPM在安全可信的状态下启动,并重点剖析了commitNonce重置、DA计时器跨重启续接、ACT减半防攻击等关键安全设计。; 适合人群:对TPM安全芯片感兴趣的零基础或初级开发者,以及从事可信计算、固件安全、系统启动安全相关工作的研发人员。; 使用场景及目标:①理解TPM为何必须以Startup作为第一条命令及其安全意义;②掌握SU_CLEAR、SU_STATE、SU_RESUME、SU_RESTART、SU_RESET等启动类型的决策逻辑与状态迁移;③深入学习DRTM与H-CRTM机制,理解动态信任根的建立过程;④分析DA防护、ACT定时器、有序NV索引等子系统的初始化行为与安全考量;⑤通过实验复现各类启动场景,提升对TPM底层机制的实战理解。; 阅读建议:建议结合文档提供的源码注释、实测报文和动手实验逐步验证,重点关注Startup与Shutdown的配对关系、状态持久化机制(NV)以及各类标志位(如g_DrtmPreStartup、g_StartupLocality3)的作用,注意区分规范定义与具体实现间的差异,并利用附录常量与术语表辅助理解。 立即下载
Many times in my career so far I could have made better decisions, solved problems much faster or even prevented problems if I had a deeper understanding of the technology stack I was using.

To begin getting a deeper understanding of the Scala stack, we will trace a simple program through it's lifetime of becoming Java, then JVM bytecode and then the final step before it's fed to the CPU monsters - assembly.

Starting with a high-level overview like this is a good foundation on which to explore each step in more detail. Because I'm nice I'll give you lots of links at the bottom of this post so you can do just that.

All code relevant to this post is  up on my github .

Scala

Our initial block of code is a scala object with a main method. When the application is started this main method will be run and, as you can see below, it's going to print something stupid to the console and finish executing.
package kns

object KnowYourStack {
 
 def main(args: Array[String]) {
  val message = "Fat stacks, yo!"
  println(message)
 }
}

    

Compiled to Java

When Scala code is compiled with  sbt it's already output as bytecode. However, we can use one of the java decompilers to show us what the java code would have looked like.

First I'll run sbt to compile the Scala. This turns our KnowYourStack.scala into two .class files as shown below:



I'll now use  jd-gui to disassemble them back into java. Here are the results:
package kns;

import scala.Predef.;

public final class KnowYourStack$
{
  public static final  MODULE$;

  static
  {
    new ();
  }

  public void main(String[] args)
  {
    String message = "Fat stacks, yo!";
    Predef..MODULE$.println(message);
  }

  private KnowYourStack$()
  {
    MODULE$ = this;
  }
}
    

package kns;

import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="\006\001\025:Q!\001\002\t\002\025\tQb\0238pof{WO]*uC\016\\'\"A\002\002\007-t7o\001\001\021\005\0319Q\"\001\002\007\013!\021\001\022A\005\003\033-swn^-pkJ\034F/Y2l'\t9!\002\005\002\f\0355\tABC\001\016\003\025\0318-\0317b\023\tyAB\001\004B]f\024VM\032\005\006#\035!\tAE\001\007y%t\027\016\036 \025\003\025AQ\001F\004\005\002U\tA!\\1j]R\021a#\007\t\003\027]I!\001\007\007\003\tUs\027\016\036\005\0065M\001\raG\001\005CJ<7\017E\002\f9yI!!\b\007\003\013\005\023(/Y=\021\005}\021cBA\006!\023\t\tC\"\001\004Qe\026$WMZ\005\003G\021\022aa\025;sS:<'BA\021\r\001")
public final class KnowYourStack
{
  public static void main(String[] paramArrayOfString)
  {
    KnowYourStack..MODULE$.main(paramArrayOfString);
  }
}
It looks like Scala creates both an instance and static class as a way to enforce the singleton pattern, which objects are. This is also the entry point to the application, which is maybe what the Scala signature is doing here?

Next Stop: Bytecode

A JVM takes bytecode and  JITs it to machine code at runtime. It will even compile hot code that is being JITd frequently. The bytecode of our two generated .class files is below using  javap.

➜ javap -c -p KnowYourStack\$ 

Compiled from "KnowYourStack.scala"

public final class kns.KnowYourStack$ {
  public static final kns.KnowYourStack$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class kns/KnowYourStack$
       3: invokespecial #12                 // Method "":()V
       6: return        

  public void main(java.lang.String[]);
    Code:
       0: ldc           #16                 // String Fat stacks, yo!
       2: astore_2      
       3: getstatic     #21                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       6: aload_2       
       7: invokevirtual #25                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
      10: return        

  private kns.KnowYourStack$();
    Code:
       0: aload_0       
       1: invokespecial #31                 // Method java/lang/Object."":()V
       4: aload_0       
       5: putstatic     #33                 // Field MODULE$:Lkns/KnowYourStack$;
       8: return        
}


➜ javap -c -p KnowYourStack  

Compiled from "KnowYourStack.scala"

public final class kns.KnowYourStack {
  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Field kns/KnowYourStack$.MODULE$:Lkns/KnowYourStack$;
       3: aload_0       
       4: invokevirtual #18                 // Method kns/KnowYourStack$.main:([Ljava/lang/String;)V
       7: return        
}


Interesting.... where did our string go? We can see it being loaded as constant 16 (ldc #16) and accessed later (getstatic #16) but where is the declaration? A lot of these instructions make a lot of sense when you've read/watched the links I've posted at the bottom of this post.

Final Destination: Assembly

I've got 2 ravenous intel CPUs inside in my i5 Ivy Bridge; both of whom have an insatiable appetite for x86_64 soup. Let's see what we can knock up from our base of bytecode special ingredients.

To get assembly out of the JVM you need to pass two flags. We do that like this in sbt:

name := "know your stack"

scalaVersion := "2.10.2"

fork := true

javaOptions += "-XX:+UnlockDiagnosticVMOptions"

javaOptions += "-XX:+PrintAssembly"

Note also the fork settings is set to true. This is because sbt needs to fork a JVM with the settings applied. You'll also need to listen to  this smart guy.

We're now ready to cook.

After running  sbt run my terminal erupts with lines of text that are hard to make out. Luckily I pipe it into a file, which on later inspection happens to be full of intel instructions. Here's a couple of snippets:

Start of the application
Running kns.KnowYourStack  
OpenJDK 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output 
Loaded disassembler from /usr/lib/jvm/java-7-openjdk/jre/lib/amd64/hsdis-amd64.so 
Decoding compiled method 0x00007f3419060250: 
Code: 
[Disassembling for mach='i386:x86-64'] [0m
[Entry Point] 
[Constants] 
 [# {method} 'readLine' '([BII)I' in 'java/util/jar/Manifest$FastInputStream' 
 # this:     rsi:rsi   = 'java/util/jar/Manifest$FastInputStream' 
 # parm0:    rdx:rdx   = '[B' 
  # parm1:    rcx       = int 
  # parm2:    r8        = int
  #           [sp+0x60]  (sp of caller) 
  0x00007f34190603a0: mov    0x8(%rsi),%r10d 
  0x00007f34190603a4: shl    $0x3,%r10 
  0x00007f34190603a8: cmp    %r10,%rax 
 0x00007f34190603ab: jne    0x00007f3419037960  ;   {runtime_call} 
  0x00007f34190603b1: xchg   %ax,%ax 
  0x00007f34190603b4: nopl   0x0(%rax,%rax,1) 
  0x00007f34190603bc: xchg   %ax,%ax 
 [Verified Entry Point] 
  0x00007f34190603c0: mov    %eax,-0x14000(%rsp) 
  0x00007f34190603c7: push   %rbp 
  0x00007f34190603c8: sub    $0x50,%rsp         ;*synchronization entry 

Method Decompilation with Annotations
[Decoding compiled method 0x00007f3419062f50: 
  [Code: 
 [Entry Point] 
 [Verified Entry Point] 
 [Constants] 
  # {method} 'indexOf' '([CII[CIII)I' in 'java/lang/String' [
  # parm0:    rsi:rsi   = '[C' [
  # parm1:    rdx       = int [
  # parm2:    rcx       = int [
  # parm3:    r8:r8     = '[C' [
  # parm4:    r9        = int [
  # parm5:    rdi       = int [
  # parm6:    [sp+0x50]   = int  (sp of caller) [
  0x00007f34190630a0: mov    %eax,-0x14000(%rsp) [
  0x00007f34190630a7: push   %rbp [
  0x00007f34190630a8: sub    $0x40,%rsp         ;*synchronization entry [
                                                 ; - java.lang.String::indexOf@-1 (line 1718) [
  0x00007f34190630ac: mov    %rsi,0x18(%rsp) [
  0x00007f34190630b1: mov    %edx,0x10(%rsp) [
  0x00007f34190630b5: mov    %r9d,(%rsp) [
 0x00007f34190630b9: mov    %ecx,0x8(%rsp) [
  0x00007f34190630bd: mov    0x50(%rsp),%ebp [
  0x00007f34190630c1: cmp    %ecx,%ebp [
  0x00007f34190630c3: jge    0x00007f3419063481  ;*if_icmplt [

You can find the full output  on  my github. Just don't ask me to explain what all of those registers are used for.... yet.
国央企创新负责人如何快速识别关键技术成果并推动落地?.docx 科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。 立即下载

相关推荐

三相电压型PWM整流器PI双闭环控制Matlab仿真

内容概要:本文档系统介绍了三相电压型PWM整流器的PI双闭环控制技术及其在Matlab/Simulink环境下的仿真建模方法,重点阐述了电流内环与电压外环的协同控制机制,旨在实现高功率因数、低电流谐波畸变及稳定的直流母线电压输出。内容涵盖多种典型电力电子变换器的建模与控制策略,包括三相维也纳(Vienna)整流器、双有源桥(DAB)变换器、LLC谐振变换器等,并深入探讨SVPWM调制、滞环电流控制、中点电位平衡、软开关技术、畸变抑制等关键技术。文档提供丰富的仿真模型、Mathcad计算书及参考文献,支持从基础控制结构到高级优化算法(如基于KKT条件的协同最小应力控制)的多层次研究与复现。; 适合人群:电气工程、自动化、电力电子与电力传动等相关专业的高校本科生、研究生,以及从事新能源发电、电动汽车、轨道交通等领域电能变换系统研发的科研人员与工程技术人员;要求具备Matlab/Simulink仿真基础及电力电子、自动控制理论的相关知识背景。; 使用场景及目标:①作为高校课程设计与实验教学的辅助材料,帮助学生掌握PWM整流器双闭环控制系统的设计流程与仿真方法;②支撑科研项目中对高性能整流器控制策略的验证、优化与EI级论文复现;③为工业界在新能源并网、车载充电机、直流配电系统等应用场景中的控制器开发提供仿真依据与参数设计工具;④结合Mathcad计算书实现不同功率等级与电压等级系统的自主建模与参数匹配。; 阅读建议:建议读者按照资源目录顺序循序渐进地学习,先掌握PI双闭环控制的基本架构与仿真调试方法,再逐步拓展至中点平衡控制、电网不平衡工况下的功率调节、软开关优化等高级主题;重点关注“顶级EI复现”案例以提升学术研究深度;推荐结合提供的仿真模型、计算书与参考文献进行对照分析与代码调试,强化理论与实践的融合能力。

深入理解Scala默认参数函数:从方法重载到优雅API设计

我写这篇文章的时候,特意没罗列默认参数有多少种用法——因为用法很简单,谁都能写。默认参数为什么重要?可选参数。Java里你想要可选参数?写重载方法。想要几个?写一堆。代码臃肿,维护痛苦。Scala的默认参数把这件事简化了——一行函数签名,编译器帮你生成所有的重载方法。调用方想用默认值就用默认值,想改哪个就改哪个,不用管顺序。把重复的事情交给编译器,让程序员专注在业务逻辑上。你不用手写重载方法——编译器帮你写。你不用记参数顺序——命名参数帮你记。你不用写Builder类——默认参数就是Builder。

https://starzy1990.github.io/ 761

智能气象站:ESP32驱动的心知天气数据可视化实践

本文详细介绍了基于ESP32微控制器和心知天气API构建智能气象站的完整实践。通过Arduino开发环境,实现天气数据的获取、JSON解析与OLED屏可视化展示,涵盖硬件连接、API配置、低功耗优化及部署问题排查,为物联网开发者提供实用指南。

jump7的博客 210

深入理解Scala嵌套函数:作用域封装之道

我写这篇文章的时候,特意没罗列嵌套函数有多少种写法——因为写法很简单,谁都能写。嵌套函数为什么重要?辅助逻辑的作用域应该是多大?Java里你写辅助逻辑,只能写到类级别——因为Java的方法必须定义在类级别。但很多辅助逻辑其实只属于某一个函数,不属于整个类。你把它们写到类级别,就造成了作用域放大——本来应该是函数内部的东西,变成了类级别的东西。Scala的嵌套函数把这个问题解决了——辅助逻辑可以精确地封装在主函数内部。它直接访问外层函数的变量,不用把上下文传来传去。它不暴露到类级别,不造成API膨胀。

https://starzy1990.github.io/ 758

STM32F103多通道PWM输出避坑指南:TIM1_CH1异常输出的解决方案

本文深入解析STM32F103多通道PWM输出中的TIM1_CH1异常问题,提供从时钟配置到GPIO复用的系统化解决方案。通过黄金法则配置流程和高级调试技巧,帮助开发者快速定位并解决PWM输出不稳定、占空比异常等问题,同时拓展多定时器协同和互补PWM等高级应用场景。

weixin_29194817的博客 117

不用Root!这些隐藏代码能一键开启安卓诊断端口(小米/OPPO/魅族机型实测)

本文提供了一份无需Root权限即可开启安卓手机诊断端口的实用指南。通过拨号盘输入特定隐藏代码,小米、OPPO、魅族等机型的用户可以一键激活此工程模式,从而连接电脑进行基带数据备份(如QCN文件)或故障排查。文章详细列出了各品牌指令、操作验证步骤,并强调了备份IMEI等关键数据的重要性与操作风险,旨在帮助用户在紧急情况下修复网络问题。

weixin_29260291的博客 273

深入理解Scala可变参数函数:从Java数组语法到优雅集合传递

我写这篇文章的时候,特意没罗列可变参数有多少种用法——因为用法很简单,谁都能写。Scala的可变参数为什么比Java好用?不是因为它有:_*这个语法——而是因为它的底层是Seq,不是数组。Java的可变参数是数组的语法糖——你传List进去,它不认,因为List不是数组。你想传?自己转。Scala的可变参数是Seq的语法糖——你传任何序列进去,只要用:_*展开就行。不用转,不用强转,一行代码搞定。**这就是函数式语言的设计哲学:可变参数不是"数组的便捷写法",它是"序列的便捷写法"。

https://starzy1990.github.io/ 440

YOLOv8改进 - 注意力篇 - 引入CAA注意力机制

YOLOv8改进 - 注意力篇 - 引入CAA注意力机制

浪子L的博客 5223

深入理解Scala柯里化函数:函数链式变换

我写这篇文章的时候,特意没罗列柯里化有多少种写法——因为写法很简单。柯里化为什么是函数式编程的一个核心概念?因为函数式编程里,函数是一等公民——函数可以返回函数。柯里化就是这个特性的直接体现:一个多参数函数,可以看成一串单参数函数的链。这带来了什么?——参数可以分阶段传递。你先传配置,得到一个"记住了配置"的函数;以后再传数据。你先传条件,得到一个控制结构;再传执行体。Java里你做不到——Java的方法必须一次传完所有参数。你想"分阶段",只能用Builder模式,手动写一堆对象。

https://starzy1990.github.io/ 827

3. ChaosBlade-Box平台安装

参考自:https://chaosblade.io/docs/about-chaosblade/box-introduce/通过ChaosBlade-Box可实现chaosblade等已托管工具自动化部署,按照社区的建立的混沌实验模型统一实验场景,根据主机、Kubernetes、应用来划分目标资源,通过目标管理器来控制,在实验创建页面,可以实现白屏化的目标资源选择。

lldhsds的专栏 2485

历年CSP-J(NOIP普及组)考点分析与分类汇总(纯干货)

noip/csp-j历年真题考点分类

weixin_42358969的博客 1万+

深入理解Scala Map:从实现原理到工程实践

我写这篇文章的时候,特意没罗列Map有多少个方法——因为那些东西官方文档都有,查一下就行。Map到底解决了什么问题?它不是"带key的列表",它是一个"从key到value的映射函数"。它用哈希表的O(1)查找,换来了通过key快速找到value的能力。在大数据开发里,Map无处不在——维度关联、配置映射、计数统计、分组聚合、缓存索引。理解了Map,你就理解了大数据处理里最核心的几个操作:查找、映射、聚合。很多人用了几年Map,还停留在"new一个HashMap,然后put put put"的阶段。

https://starzy1990.github.io/ 394

数分实战(01):Global_Superstore数据集解析与商业洞察

本文以Global_Superstore零售数据集为例,手把手指导数据分析实战全流程。从数据清洗、探索性分析到深度商业洞察,详细解析了如何通过Python处理缺失值与异常值,进行销售利润分析、客户细分与地理分析,并探讨了折扣与利润的微妙关系。文章旨在帮助读者建立数据分析思维框架,从数据中挖掘可指导实际业务决策的核心洞察。

weixin_28487433的博客 342

深入理解Scala匿名函数:函数式编程基石

我写这篇文章的时候,特意没罗列匿名函数有多少种写法——因为写法很简单,谁都能写。匿名函数为什么是函数式编程的基石?把函数当参数传。你不能把函数当参数传,就没有map、filter、reduce这些集合操作。没有这些集合操作,就没有声明式编程。没有声明式编程,就没有函数式编程。Java花了很长时间才意识到这一点——Java 8才加了Lambda。但Java的Lambda是不完整的——它只能捕获final变量,不能修改变量。它是一个"阉割版"的闭包。Scala呢?

https://starzy1990.github.io/ 521

点云目标检测:open3d多窗口联动可视化

多个模型之间的对比除了指标之外,还需要可以直接直观的对比可视化结果,这次介绍一下如何使用open3d同时打开两个窗口分别加载两个模型的结果进行对比,同时实现两个窗口的联动,也就是当一个窗口拖动或者缩放时另外一个窗口也跟着做同样的变换。

zhaoguanhua的博客 4688

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深入理解Scala偏应用函数:函数工厂设计

我写这篇文章的时候,特意没罗列偏应用函数有多少种写法——因为写法很简单,谁都能写。偏应用函数为什么重要?不是因为"它可以固定一部分参数"——而是因为它让你可以把函数当工厂用。Java里你想写一个"专用函数",怎么办?——写一个新方法,重载,或者用Builder。Scala呢?——一行占位,就把通用函数变成了专用函数。函数是一等公民,你可以加工它——固定参数、组合参数、变换参数——得到新的函数。Java的方法是死的——你定义的时候几个参数,调用的时候就得传几个。

https://starzy1990.github.io/ 400

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【Spark】 04键值对 RDD:创建、常用操作与数据分区

介绍 Spark 键值对 RDD 的创建方式、聚合、分组、连接、排序与行动操作,并结合 PageRank 示例讲解数据分区、分区器复用与自定义分区方式。

qq_46126258的博客 378

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

大数据Spark(八十二):Spark 算子综合案例

本文通过四个典型Spark算子应用案例,系统讲解了单词频次过滤、PV/UV统计、二次排序及分组取TopN的实现方法。涵盖flatMap、mapToPair、reduceByKey、distinct、sortByKey、groupByKey等核心算子的组合使用,提供Java与Scala双语言实现,兼顾可读性与实用性。强调根据数据规模选择合适方案,避免内存溢出,适用于大数据处理场景的实战参考。

Lansonli(蓝深李)的博客 622

深入理解Scala递归函数:从栈溢出到尾调用优化

我写这篇文章的时候,特意没罗列递归有多少种写法——因为递归的语法很简单,谁都能写。为什么Java的递归会栈溢出,而Scala的不会?不是因为Scala更厉害——而是因为Scala是函数式语言,递归是它的核心特性之一。它从设计之初就考虑了尾调用优化的问题。Java是命令式语言,它的核心是对象和方法,递归只是一个"能用但不推荐"的特性。Java程序员写递归:栈溢出,不敢用Scala程序员写递归:尾递归,随便写递归不是洪水猛兽,栈溢出是因为你没写对。你可以用递归的优雅写法,获得循环的性能。

https://starzy1990.github.io/ 629

深入理解Scala可变Map:动态构建场景下的性能与设计权衡

我写这篇文章的时候,特意没罗列可变Map有多少个方法——因为那些东西官方文档都有,查一下就行。为什么需要可变Map?不是因为"它就是Java HashMap的Scala版",而是因为在动态构建数据的场景下,不可变Map的性能不够好。你要在循环里不断往Map里加key-value对,用不可变Map就是O(n²)的灾难,用可变Map就是O(n)的高效。但可变Map也不是万能的。它只适合"构建"场景——你在一个方法内部,动态构建一个Map,最后输出一个不可变Map。

https://starzy1990.github.io/ 361

深入理解Scala高阶函数:函数式编程核心

我写这篇文章的时候,特意没罗列高阶函数有多少种用法——因为用法很简单,谁都能写。高阶函数为什么是函数式编程的核心?把函数当一等公民,用函数来抽象和组合逻辑。没有高阶函数,函数就不能当参数传——那你就没有map、filter、reduce。没有这些,你就只能写for循环——命令式编程。有了高阶函数,你可以把逻辑封装成函数,传给其他函数——你可以组合函数、变换函数、生成函数。这就是函数式编程。Java花了很长时间才意识到这一点——Java 8加了Lambda和Stream。

https://starzy1990.github.io/ 525

深入理解Scala元组:从多返回值到模式匹配的桥梁

函数式编程里,函数的参数和元组是一一对应的。在函数式编程里,一个函数可以看成是接收一个参数、返回R的函数。这个叫"函数的元组化"(tupled)。而Scala的类型系统在处理多参数函数的时候,需要为每个参数数量生成对应的函数类型——、…、。因为函数最多到Function22,所以元组也最多到Tuple22。这是一个统一的设计——元组和函数,共享同一个N的上限。那22以上怎么办?用嵌套元组或者case class。// 超过22个元素:用嵌套。

https://starzy1990.github.io/ 704

深入理解Scala函数定义:从方法到函数的类型跨越

最常用的方式。定义一个方法,属于当前类/对象。name特点:有名字、有参数类型、有返回类型(可以省略,编译器推断)、函数体用连接。定义一个函数值,它是一个对象,可以到处传。name特点:用val定义(因为它是值),参数和返回类型写在括号里,=>后面是函数体。我写这篇文章的时候,特意没罗列函数有多少种写法——因为那些语法东西,查文档就有。Scala为什么要有函数这个概念?不是因为"函数式编程嘛,函数是一等公民"——这句话说了等于没说。当你需要对一组数据做变换的时候,你需要一个"可以传进去的操作"。

https://starzy1990.github.io/ 711

大数据Spark(八十三):Spark中的分区器Partitioner介绍

本文介绍Spark中Partitioner的作用及三种实现方式:HashPartitioner(基于哈希取模,默认分区器,高效但易倾斜)、RangePartitioner(按键范围分区,支持排序,数据均衡性好)和自定义分区器(按业务规则分配,灵活应对特殊需求)。合理选择分区器可优化shuffle性能,提升作业效率。

Lansonli(蓝深李)的博客 577

深入理解Scala伴生类:类对象合一设计

我写这篇文章的时候,特意没罗列伴生对象有多少种写法——因为写法很简单。Scala为什么要设计伴生对象,而不是直接保留static?因为static破坏了面向对象的纯粹性。Java的静态方法不属于任何对象——它不能被继承、不能被重写、不能多态。你写一个静态方法,它就钉死在那个类上了。Scala的伴生对象是一个真正的对象——它可以继承抽象类、实现特质、混入功能。它和伴生类是平等的,只不过一个管"实例",一个管"类级别"。这就是Scala的设计哲学:在Scala的世界里,一切都是对象。

https://starzy1990.github.io/ 331
上一篇: Scala: Under The Hood of Hello World
下一篇: scala:函数即对象
DViewer
博客等级 码龄16年 16粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值