探索Java的DNA-JVM字節碼深度解析


引言

在Java的世界里,JVM(Java虛擬機)是我們程序運行的心臟。而字節碼,作為JVM的血液,攜帶著程序的執行指令。今天,我們將深入探索Java字節碼的奧秘,一窺JVM如何將人類可讀的代碼轉化為機器可執行的指令。


一、JVM 知識回顧


JVM是一個可以執行Java字節碼的虛擬計算機,它包括類加載器、運行時數據區、執行引擎等核心組件。JVM架構保證了Java程序的平臺獨立性,實現了“一次編寫,到處運行”的理念。

關于Java虛擬機的工作原理、作用和應用場景, 感興趣的朋友請前往查看:Java虛擬機揭秘-底層驅動力,性能保障!


二、Class文件結構


Class文件是JVM執行字節碼的載體,它以8位字節為基礎單位的二進制流形式存在。Class文件的結構包括魔數、版本號、常量池、字段表集合、方法表集合等。

在這里插入圖片描述


下面以一個例子逐步講解字節碼。

//Test.java
public class Test {private int a;public int num() {return a + 1;}
}

通過執行以下命令, 可以在當前所在路徑下生成一個Test.class文件。

javac Test.java

以文本形式打開Test.class文件,內容如下:

cafe babe 0000 003d 0013 0a00 0200 0307
0004 0c00 0500 0601 0010 6a61 7661 2f6c
616e 672f 4f62 6a65 6374 0100 063c 696e
6974 3e01 0003 2829 5609 0008 0009 0700
0a0c 000b 000c 0100 0454 6573 7401 0001
6101 0001 4901 0004 436f 6465 0100 0f4c
696e 654e 756d 6265 7254 6162 6c65 0100
036e 756d 0100 0328 2949 0100 0a53 6f75
7263 6546 696c 6501 0009 5465 7374 2e6a
6176 6100 2100 0800 0200 0000 0100 0200
0b00 0c00 0000 0200 0100 0500 0600 0100
0d00 0000 1d00 0100 0100 0000 052a b700
01b1 0000 0001 000e 0000 0006 0001 0000
0002 0001 000f 0010 0001 000d 0000 001f
0002 0001 0000 0007 2ab4 0007 0460 ac00
0000 0100 0e00 0000 0600 0100 0000 0700
0100 1100 0000 0200 12

  • 文件開頭的4個字節(“cafe babe”)稱之為 魔數,唯有以"cafe babe"開頭的class文件方可被虛擬機所接受,這4個字節就是字節碼文件的身份識別。

  • 0000是編譯器jdk版本的次版本號0


三、反編譯字節碼文件


使用 javap 命令反編譯 Java 字節碼文件是一個查看 .class 文件內部結構和字節碼指令的簡單方法。

用法: javap <options> <classes>

其中<options>選項包括:

-help  --help  -?        輸出此用法消息-version                 版本信息-v  -verbose             輸出附加信息-l                       輸出行號和本地變量表-public                  僅顯示公共類和成員-protected               顯示受保護的/公共類和成員-package                 顯示程序包/受保護的/公共類和成員 (默認)-p  -private             顯示所有類和成員-c                       對代碼進行反匯編-s                       輸出內部類型簽名-sysinfo                 顯示正在處理的類的系統信息 (路徑, 大小, 日期, MD5 散列)-constants               顯示最終常量-classpath <path>        指定查找用戶類文件的位置-cp <path>               指定查找用戶類文件的位置-bootclasspath <path>    覆蓋引導類文件的位置

以下是如何使用 javap 命令的基本步驟:

  • 第一步,編譯 Java 源文件: 首先,你需要有一個 .class 文件。如果你有一個 .java 源文件,可以使用 javac 命令將其編譯成 .class 文件。例如:
javac Test.java

這將在當前目錄下生成一個名為 Test.class 的字節碼文件。

在這里插入圖片描述


  • 第二步,使用 javap 命令: 打開命令行工具(在 Windows 上是 CMD 或 PowerShell,在 macOS 或 Linux 上是 Terminal),然后使用 javap 命令查看 .class 文件的內容。

    可以使用:

    javap -c Test
    

  • 第三步,查看輸出: 執行 javap 命令后,你將看到 .class 文件的詳細信息,包括類定義、字段、方法以及它們的字節碼指令。

在這里插入圖片描述

  • 第四步,輸出到文件: 如果你想要將 javap 的輸出保存到文件中,可以使用重定向操作符 >
javap -c Test > output.txt

這將把 Test.class 文件的字節碼指令輸出到 output.txt 文件中。

在這里插入圖片描述


請注意,javap 主要用于查看字節碼指令和類的結構,而不是將 .class 文件完全反編譯回 Java 源代碼。

如果你需要將 .class 文件反編譯為更接近原始源代碼的形式,可能需要使用其他專門的反編譯工具。


四、字節碼文件.class詳細解讀


執行以下命令,可查看子節碼文件內容:

javap -verbose -p Test.class
  Last modified 2024年5月26日; size 265 bytesSHA-256 checksum aeba5b65f486bc4f6ee16ec2073e4fec2053987d53cdaed540343c6230966095Compiled from "Test.java"
public class Testminor version: 0major version: 61flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #8                          // Testsuper_class: #2                         // java/lang/Objectinterfaces: 0, fields: 1, methods: 2, attributes: 1
Constant pool:#1 = Methodref          #2.#3          // java/lang/Object."<init>":()V#2 = Class              #4             // java/lang/Object#3 = NameAndType        #5:#6          // "<init>":()V#4 = Utf8               java/lang/Object#5 = Utf8               <init>#6 = Utf8               ()V#7 = Fieldref           #8.#9          // Test.a:I#8 = Class              #10            // Test#9 = NameAndType        #11:#12        // a:I#10 = Utf8               Test#11 = Utf8               a#12 = Utf8               I#13 = Utf8               Code#14 = Utf8               LineNumberTable#15 = Utf8               num#16 = Utf8               ()I#17 = Utf8               SourceFile#18 = Utf8               Test.java
{private int a;descriptor: Iflags: (0x0002) ACC_PRIVATEpublic Test();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 2: 0public int num();descriptor: ()Iflags: (0x0001) ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: getfield      #7                  // Field a:I4: iconst_15: iadd6: ireturnLineNumberTable:line 7: 0
}
SourceFile: "Test.java"

以上信息是使用 javap 命令反編譯 Test.class 文件后得到的輸出結果。它展示了 .class 文件的內部結構和相關信息。


下面是對輸出結果的詳細解析:

(1)、文件元信息

  • Last modified:文件最后修改時間。

  • size:文件大小。

  • SHA-256 checksum:文件的 SHA-256 校驗和。


(2)、編譯信息

  • Compiled from "Test.java":表明 Test.class 文件是由 Test.java 源文件編譯而來。


(3)、類定義

  • public class Test:定義了一個名為 Test 的公共類。


(4)、版本信息

  • minor version: 0major version: 61:表示這個 .class 文件的 Java 版本信息,主版本號是 61,這對應于 Java 17。


(5)、訪問標志

  • flags: (0x0021) ACC_PUBLIC, ACC_SUPER:類的標志,ACC_PUBLIC 表示這個類是公開的,ACC_SUPER 是一個默認標志,表示這個類不是 final 的。


    訪問標志的含義如下:

    標志名稱標志值含義
    ACC_PUBLIC0x0001是否為Public類型
    ACC_FINAL0x0010是否被聲明為final,只有類可以設置
    ACC_SUPER0x0020是否允許使用invokespecial字節碼指令的新語義.
    ACC_INTERFACE0x0200標志這是一個接口
    ACC_ABSTRACT0x0400是否為abstract類型,對于接口或者抽象類來說,次標志值為真,其他類型為假
    ACC_SYNTHETIC0x1000標志這個類并非由用戶代碼產生
    ACC_ANNOTATION0x2000標志這是一個注解
    ACC_ENUM0x4000標志這是一個枚舉

(6)、常量池

Constant pool
  • 常量池可以理解成Class文件中的資源倉庫,包含了類文件中的各種常量引用,例如方法引用、類名、字段名等。

  • 常量池主要存放的是兩大類常量:字面量(Literal)和符號引用(Symbolic References)。

  • 字面量類似于java中的常量概念,如文本字符串,final常量等。

  • 符號引用則屬于編譯原理方面的概念,包括以下三種:

    • 類和接口的全限定名(Fully Qualified Name)

    • 字段的名稱和描述符號(Descriptor)

    • 方法的名稱和描述符

JVM是在加載Class文件的時候才進行的動態鏈接,也就是說這些字段和方法符號引用只有在運行期轉換后才能獲得真正的內存入口地址。當虛擬機運行時,需要從常量池獲得對應的符號引用,再在類創建或運行時解析并翻譯到具體的內存地址中。

例如:

  • #1 = Methodref #2.#3:引用了 java/lang/Object 類的無參構造方法 <init>()V

  • #7 = Fieldref #8.#9:引用了 Test 類中的字段 a


(7)、字段

  • private int a;:定義了一個名為 a 的私有整型字段。

(8)、構造方法

  • public Test();:定義了一個公共的無參構造方法,用于實例化 Test 類的對象。

  • Code:構造方法的字節碼指令,這里調用了父類 Object 的構造方法。


    Code:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 2: 0
    

    code內的主要屬性為:

    • stack: 最大操作數棧,JVM運行時會根據這個值來分配棧幀(Frame)中的操作棧深度,此處為1。

    • locals: 局部變量所需的存儲空間,單位為Slot, Slot是虛擬機為局部變量分配內存時所使用的最小單位,為4個字節大小。方法參數(包括實例方法中的隱藏參數this),顯示異常處理器的參數(try catch中的catch塊所定義的異常),方法體中定義的局部變量都需要使用局部變量表來存放。值得一提的是,locals的大小并不一定等于所有局部變量所占的Slot之和,因為局部變量中的Slot是可以重用的。

    • args_size: 方法參數的個數,這里是1,因為每個實例方法都會有一個隱藏參數this.

    • LineNumberTable: 該屬性的作用是描述源碼行號與字節碼行號(字節碼偏移量)之間的對應關系。可以使用 -g:none 或-g:lines選項來取消或要求生成這項信息,如果選擇不生成LineNumberTable,當程序運行異常時將無法獲取到發生異常的源碼行號,也無法按照源碼的行數來調試程序。


(9)、方法

  • public int num();:定義了一個名為 num 的公共方法,返回類型為 int

  • Codenum 方法的字節碼指令,它讀取字段 a 的值,加 1,然后返回結果。


  • descriptor: I

類型為I, I即是int類型,關于字節碼的類型對應如下:

標識字符含義
B基本類型byte
C基本類型char
D基本類型double
F基本類型float
I基本類型int
J基本類型long
S基本類型short
Z基本類型boolean
V特殊類型void
L對象類型,以分號結尾,如Ljava/lang/Object;

(10)、行號表

  • LineNumberTable:提供了源代碼行號和字節碼指令之間的映射。


(11)、源文件

  • SourceFile: "Test.java":指示這個 .class 文件是由 Test.java 源文件編譯而來的。

這個輸出結果提供了 Test.class 文件的詳細內部結構,包括字段、方法、訪問控制、版本信息等。通過這些信息,可以更好地理解 Java 類的編譯過程和字節碼的細節。


五、分析try-catch-finally


public class TestCode {public int foo() {int x;try {x = 1;return x;} catch (Exception e) {x = 2;return x;} finally {x = 3;}}
}

執行命令:

javac TestCode.java
javap -verbose -p TestCode.class

內容如下:

  Last modified 2024年5月26日; size 418 bytesSHA-256 checksum 0d58e986cce436cf5dd634bcfabb39b75afaddaa863d596c1e874f3571832952Compiled from "TestCode.java"
public class TestCodeminor version: 0major version: 61flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #9                          // TestCodesuper_class: #2                         // java/lang/Objectinterfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:#1 = Methodref          #2.#3          // java/lang/Object."<init>":()V#2 = Class              #4             // java/lang/Object#3 = NameAndType        #5:#6          // "<init>":()V#4 = Utf8               java/lang/Object#5 = Utf8               <init>#6 = Utf8               ()V#7 = Class              #8             // java/lang/Exception#8 = Utf8               java/lang/Exception#9 = Class              #10            // TestCode#10 = Utf8               TestCode#11 = Utf8               Code#12 = Utf8               LineNumberTable#13 = Utf8               foo#14 = Utf8               ()I#15 = Utf8               StackMapTable#16 = Class              #17            // java/lang/Throwable#17 = Utf8               java/lang/Throwable#18 = Utf8               SourceFile#19 = Utf8               TestCode.java
{public TestCode();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0public int foo();descriptor: ()Iflags: (0x0001) ACC_PUBLICCode:stack=1, locals=5, args_size=10: iconst_11: istore_12: iload_13: istore_24: iconst_35: istore_16: iload_27: ireturn8: astore_29: iconst_210: istore_111: iload_112: istore_313: iconst_314: istore_115: iload_316: ireturn17: astore        419: iconst_320: istore_121: aload         423: athrowException table:from    to  target type0     4     8   Class java/lang/Exception0     4    17   any8    13    17   any17    19    17   anyLineNumberTable:line 5: 0line 6: 2line 11: 4line 6: 6line 7: 8line 8: 9line 9: 11line 11: 13line 9: 15line 11: 17line 12: 21StackMapTable: number_of_entries = 2frame_type = 72 /* same_locals_1_stack_item */stack = [ class java/lang/Exception ]frame_type = 72 /* same_locals_1_stack_item */stack = [ class java/lang/Throwable ]
}
SourceFile: "TestCode.java"

我們重點解讀名為 foo 的 Java 方法的字節碼信息。

下面是對這個輸出的詳細解析:

  1. 方法簽名
    • public int foo();:定義了一個名為 foo 的公共方法,它返回一個整數值。
  2. 方法描述符
    • descriptor: ()I:表示這個方法沒有參數,并返回一個 int 類型的值。
  3. 訪問標志
    • flags: (0x0001) ACC_PUBLIC:表示這個方法是公開的。
  4. 字節碼指令
    • Code:包含了實際執行的方法體的字節碼指令。
    • stack=1, locals=5, args_size=1:表示這個方法在執行時,操作數棧的最大深度是 1,局部變量表的大小是 5(包括 this 指針和方法參數),參數大小是 1(對于實例方法,this 指針算作第一個參數)。
  5. 字節碼指令詳解
    • iconst_1:將整數 1 推送到棧上。
    • istore_1:將棧頂的整數值存儲到局部變量 1 中。
    • iload_1:從局部變量 1 中加載整數值到棧上。
    • istore_2:將棧頂的整數值存儲到局部變量 2 中。
    • iconst_3:將整數 3 推送到棧上。
    • istore_1:將棧頂的整數值存儲到局部變量 1 中。
    • iload_2:從局部變量 2 中加載整數值到棧上。
    • ireturn:將棧頂的整數值作為返回值結束方法。
    • astore_2:將棧頂的引用類型值存儲到局部變量 2 中。
    • iconst_2istore_1istore_3aloadathrow:這些指令涉及到異常處理,athrow 指令會拋出異常。
  6. 異常表
    • Exception table:列出了方法中可能拋出的異常及其處理程序的位置。
    • fromtotargettype:分別表示異常發生的起始指令、結束指令、跳轉目標指令和異常類型。
  7. 行號表
    • LineNumberTable:提供了源代碼行號和字節碼指令之間的映射,方便調試。
  8. StackMapTable
    • StackMapTable:在 JDK 7 及以后版本中,用于替代之前的 Exceptions 屬性和 LineNumberTable,提供了更詳細的棧映射信息,用于支持新的異常表和行號信息。
  9. 源文件
    • SourceFile:指示這個 .class 文件是由哪個 .java 源文件編譯而來的。

這個輸出結果提供了 foo 方法的字節碼指令和相關元信息,包括方法的訪問權限、返回類型、局部變量和操作數棧的使用情況、異常處理以及源代碼行號映射等。通過這些信息,可以深入理解 Java 方法的執行細節和異常處理機制。


六、結語

字節碼不僅支持Java語言,還支持所有編譯到字節碼的JVM語言,如Groovy、Scala、Kotlin等。此外,字節碼層面的優化可以顯著提高程序性能。

字節碼是Java程序的靈魂,掌握了字節碼,就掌握了程序性能的鑰匙。本文深入探討了Java字節碼的內部結構和工作原理,然而,字節碼的世界遠比我們所見的要深邃。

在下一篇文章中,我們將揭開JVM調優的神秘面紗,探索如何通過字節碼優化讓Java程序運行如飛。敬請期待!


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/21790.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/21790.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/21790.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

洛谷 P1438 無聊的數列

題意 給定一個序列 A ( A 1 , A 2 , ? , A n ) A(A_1,A_2,\cdots,A_n) A(A1?,A2?,?,An?)。 現在進行 m m m次操作&#xff0c;分為以下兩種: 1 l r k d&#xff1a;給定一個長度為 r ? l 1 r-l1 r?l1的等差序列&#xff0c;首項為 k k k&#xff0c;公差為 d d d&am…

【小白向】微信小程序解密反編譯教程

# 前言 最近筆者有做到微信小程序的滲透測試&#xff0c;其中有一個環節就是對微信小程序的反編譯進行源碼分析&#xff0c;所謂微信小程序反編譯&#xff0c;就是將訪問的小程序進行反向編譯拿到部分源碼&#xff0c;然后對源碼進行安全審計&#xff0c;分析出其中可能存在的…

圖形學初識--顏色混合

文章目錄 前言正文為什么要有顏色混合&#xff1f;顏色混合常見實現方式&#xff1f;上述顏色混合注意點 結尾&#xff1a;喜歡的小伙伴點點關注贊哦! 前言 本章節補充一下顏色混合的內容&#xff0c;主要包含&#xff1a;為什么要有顏色混合&#xff1f;顏色混合常實現方式&a…

BGP——邊界網關路由協議

BGP -邊界網關路由協議 OSPF RIP EIGRP AS——自治系統 標準編號16位二進制 0-65535 1-64511公有 64512 -私有 擴展編號 32位二進制 動態路由協議: GP ——內部網關路由協議 —— AS之內 或企業網、局域網 RIP OSPF EIGRP EGP-外部網關路由協議 - …

Centos 7 安裝刻錄至硬件服務器

前言 在日常測試中&#xff0c;會遇到很多安裝的場景&#xff0c;今天給大家講一下centos 7 的安裝&#xff0c;希望對大家有所幫助。 一.下載鏡像 地址如下&#xff1a; centos官方鏡像下載地址https://www.centos.org/download/ 按照需求依次點擊下載 二.鏡像刻錄 鏡像刻…

idea springboot woff/woff2/eot/ttf/svg等小圖標不顯示的問題 - 第515篇

歷史文章&#xff08;文章累計500&#xff09; 《國內最全的Spring Boot系列之一》 《國內最全的Spring Boot系列之二》 《國內最全的Spring Boot系列之三》 《國內最全的Spring Boot系列之四》 《國內最全的Spring Boot系列之五》 《國內最全的Spring Boot系列之六》 《…

Shopify 獨立站監控觀測最佳實踐

Shopify 簡介 Shopify 是一個全球領先的電子商務平臺&#xff0c;它為商家提供了一整套在線商店解決方案。自 2006 年成立以來&#xff0c;Shopify 已經幫助數百萬商家在全球范圍內建立和發展他們的在線業務。 監控觀測 Shopify 站點對于確保業務連續性、優化用戶體驗和提高運…

python虛擬環境venv的安裝--ubuntu

venv是Python內置的虛擬環境管理工具 1.安裝python3-venv包&#xff1a; sudo apt install python3.12-venv2.創建虛擬環境&#xff08;在項目目錄下&#xff09; python3 -m venv venv3. 激活虛擬環境&#xff1a; source venv/bin/activate4.在虛擬環境中安裝所需的庫&am…

Linux shell編程學習筆記56:date命令——顯示或設置系統時間與日期

0 前言 2024年的網絡安全檢查又開始了&#xff0c;對于使用基于Linux的國產電腦&#xff0c;我們可以編寫一個腳本來收集系統的有關信息。在收集的信息中&#xff0c;應該有一條是搜索信息的時間。 1. date命令 的功能、格式和選項說明 我們可以使用命令 date --help 來查看 d…

python 虛擬環境安裝及python包庫安裝

python 虛擬環境安裝及python包庫安裝 安裝虛擬環境的方式注意事項 安裝虛擬環境的方式 切記盡量不要混用 pip 安裝 對于pip安裝&#xff0c;使用命令如下 下載virtualenv 工具 pip install virtualenv 創建虛擬環境并激活環境virtualenv venv source ./venv/bin/activate co…

Kafka之Broker原理

1. 日志數據的存儲 1.1 Partition 1. 為了實現橫向擴展&#xff0c;把不同的數據存放在不同的 Broker 上&#xff0c;同時降低單臺服務器的訪問壓力&#xff0c;我們把一個Topic 中的數據分隔成多個 Partition 2. 每個 Partition 中的消息是有序的&#xff0c;順序寫入&#x…

LeetCode刷題:反轉鏈表

leetCode真題 206. 反轉鏈表 屬于基礎簡單題目 常見的做法有遞歸和while循環 遞歸 // 1. 遞歸參數和返回值public static ListNode reverseList(ListNode head) {// 1. 遞歸終止條件if (head null || head.next null) {return head;}// 遞歸邏輯ListNode last reverseL…

達夢數據庫相關SQL及適配Mysql配置總結

&#x1f353; 簡介&#xff1a;java系列技術分享(&#x1f449;持續更新中…&#x1f525;) &#x1f353; 初衷:一起學習、一起進步、堅持不懈 &#x1f353; 如果文章內容有誤與您的想法不一致,歡迎大家在評論區指正&#x1f64f; &#x1f353; 希望這篇文章對你有所幫助,歡…

解決Python導入第三方模塊報錯“TypeError: the first argument must be callable”

注意以下內容只對導包時遇到同樣的報錯會有參考價值。 問題描述 當你嘗試導入第三方模塊時&#xff0c;可能會遇到如下報錯信息&#xff1a; TypeError: the first argument must be callable 猜測原因 經過仔細檢查代碼&#xff0c;我猜測這個錯誤的原因是由于變量名沖突所…

Windows 系統安裝 VisualSVN Server

一.下載 VisualSVN Server VisualSVN-Server 是 SVN 版本控制中服務器端要使用的軟件,就是我們提交代碼存在安裝這個軟件的電腦上,它將很多配置和服務直接幫你完成,簡單好用容易上手。VisualSVN Server有三個版本,社區版免費但限15個用戶,另有一般和‘企業’兩個收費版本…

如何卸載ollama

文章目錄 一 概述二 卸載2.1 Windows平臺卸載 ollama2.2 Linux 平臺卸載 ollama2.3 Docker 平臺卸載 ollama 參考鏈接 一 概述 本文檔主要講述 ollama 如何卸載&#xff0c;適用范圍包括 Windows Linux 以及 Docker 等平臺的安裝方式。 二 卸載 2.1 Windows平臺卸載 ollama …

學習C++應該做點什么項目

C作為一門底層可操作性很強的語言&#xff0c;廣泛應用于游戲開發、工業和追求性能、速度的應用。 比如騰訊&#xff0c;無論游戲&#xff0c;還是微信&#xff0c;整個鵝廠后臺幾乎都是 C 開發&#xff0c;對 C 開發者的需求非常大。 但問題是C入門和精通都比較困難&#xf…

有哪些掙錢軟件一天能賺幾十元?盤點十個能長期做下去的掙錢軟件

在這個信息爆炸的時代&#xff0c;每個人都在尋找快速賺錢的秘訣。很多人做兼職副業的目標并不是獲得很大的成功&#xff0c;大部分人一天能賺幾十就心滿意足了。 今天&#xff0c;我要帶你一探究竟&#xff0c;揭秘那些能讓你日賺幾十元的掙錢軟件。準備好了嗎&#xff1f;讓我…

單槍匹馬月入17萬美元:數字游民Pieter Levels如何成就商業傳奇

了解數字游民的應該都聽說過 Pieter Levels&#xff0c;可以說他是數字游民的先驅人物。 他在推特上擁有超過43萬的粉絲&#xff0c;僅憑一臺筆記本電腦就連續建立了多個高盈利網站&#xff0c;光是推特主頁上展示的比較新的幾個網站&#xff0c;每月收入加起來就高達 17.6 萬…

第九周:員工激勵理論

1. 關注自己到關注他人 你是激勵者&#xff0c;也會是被激勵者。 雖然每個人的價值觀不一樣&#xff0c;但要做好激勵員工這件事情&#xff0c;我覺得可以從自身角度出發&#xff0c;可以問問自己&#xff0c;你是如何被激勵的&#xff1f; 如果是我&#xff0c;就只想要錢&…