ykma
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    1
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Annotation(註解與反射) ###### tags: `Master of JAVA` ## 1.註解入門 ### 概念 註解與註釋是不太一樣的東西,註釋主要是給人看的,而註解除了給人看以外,主要是給程式看的,這也是包括mybatis、spring等許多框架的底層實現。 ### 什麼是註解 ![](https://i.imgur.com/iGXnDUh.png) 這裡要注意的是,註解可被其他程序讀取,可以實現動態性,依靠反射來實現。 ```java= package com.ykma.annotation; //什麼是註解 public class Test01 extends Object{ //Override 重寫的註解 @Override public String toString() { return super.toString(); } } ``` ### 內置註解 ![](https://i.imgur.com/zi0oyas.png) ```java= package com.ykma.annotation; import java.util.ArrayList; import java.util.List; //什麼是註解 public class Test01 extends Object{ //Override 重寫的註解 @Override public String toString() { return super.toString(); } //Deprecated 不推薦工程師使用,但還是可以使用,或著存在更好的方式 @Deprecated public static void test(){ System.out.println("Deprecated"); } //鎮壓警告,有參數,把沒使用到的灰色警告強制鎮壓下去 @SuppressWarnings("all") public void test02(){ List list = new ArrayList(); } public static void main(String[] args) { test(); } } ``` ### 元註解 用來註解註解的註解,JAVA定義了4個meta-annotation: ![](https://i.imgur.com/FLnMXeX.png) ```java= package com.ykma.annotation; import java.lang.annotation.*; //測試元註解 @MyAnnotation public class Test02 { @MyAnnotation public void test(){ } } //定義一個註解 //Target 表示我們的註解可以用在哪些地方 @Target(value = {ElementType.METHOD,ElementType.TYPE}) //Retention 表示我們的註解在什麼地方還有效 //runtime>class>sources @Retention(value = RetentionPolicy.RUNTIME) //Documented 表示是否將我們的註解生成在JAVAdoc中 @Documented //Inherited 子類可以繼承父類的註解 @Inherited @interface MyAnnotation{ } ``` ### 自訂義註解 ![](https://i.imgur.com/Q7LN4zs.png) ```java= package com.ykma.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //自訂義註解 public class Test03 { //註解可已顯示賦值,如果沒有默認值,我們就必須給註解賦值 @MyAnnotation2(name = "ykma",schools = {"台大"}) public void test(){} //如果只有一個參數,可設定為value,這樣寫的時候不需血參數名 @MyAnnotation3("ykma") public void test2(){ } } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ //註解的參數 : 參數類型 + 參數名(); String name() default ""; int age() default 0; int id() default -1; // 如果默認值為-1,代表不存在,indexof,如果找不到就返回-1 String[] schools() default {"興大"}; } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{ String value(); } ``` ## 2.反射(Reflaction) JAVA透過反射將靜態語言變成動態語言,在程序執行的時候依然可以注入程式,改變其結構。 ### 靜態語言&動態語言 ![](https://i.imgur.com/jGpxbkF.png) JS就是一個動態語言,沒有固定的資料型別,可以在執行的時候改變某些結構: ```javascript= function f(){ var x = "var a=3;var b=5;alert(a+b)"; eval(x) } ``` ### Reflaction 反射是讓JAVA變成動態語言的關鍵所在,透過reflaction API可以在程序執行時獲得任何類的內部訊息,其原理跟一般創建物件相反,故有反射之義,一般是透過類來new物件,反射則是透過reflaction建立物件,透過該物件可以反向獲得類的訊息: ![](https://i.imgur.com/5TVldfB.png) 反射的機制與應用,動態代理在AOP相當重要,框架也使用了大量AOP: ![](https://i.imgur.com/6jCePM4.png) 反射的優點與缺點: ![](https://i.imgur.com/lE4psQ4.png) 反射相關的主要API,都是根據Class這個類來操作: ![](https://i.imgur.com/kMIv2gZ.png) ```java= package com.ykma.reflaction; //甚麼叫反射 public class Test02 { public static void main(String[] args) throws ClassNotFoundException { //透過反射獲取類的class物件 Class c1 = Class.forName("com.ykma.reflaction.User"); System.out.println(c1); Class c2 = Class.forName("com.ykma.reflaction.User"); Class c3 = Class.forName("com.ykma.reflaction.User"); Class c4 = Class.forName("com.ykma.reflaction.User"); //一個類在記憶體中只有一個class物件 //一個類被加載之後,類的整個結構都會被封裝在class物件中 System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); System.out.println(c4.hashCode()); } } //實體類:pojo , entitiy class User{ private String name; private int id; private int age; public User() { } public User(String name, int id, int age) { this.name = name; this.id = id; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}'; } } ``` Class類: ![](https://i.imgur.com/FpEpc8s.png) 正常是透過由上往下,由Class往下new出物件,反射則是由下往上,由物件去get Class資訊,即為反射之義。 ### Class的特性與常用方法 Class的特性: ![](https://i.imgur.com/P55ana8.png) Class類的常用方法: ![](https://i.imgur.com/zxW9BDs.png) 如何獲取Class類的實體: ![](https://i.imgur.com/vVYgT8F.png) ```java= package com.ykma.reflaction; //測試Class類的創建方式有哪些 public class Test03 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("這個人是:"+person.name); //方式一:透過物件獲得 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式二:透過forname獲得 Class c2 = Class.forName("com.ykma.reflaction.Student"); System.out.println(c2.hashCode()); //方式三:透過類名.class獲得 Class c3 = Student.class; System.out.println(c3.hashCode()); //方式四:基本內置類型的包裝類都有一個Type屬性 Class<Integer> c4 = Integer.TYPE; System.out.println(c4); //獲得父類類型 Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person{ public String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name = "學生"; } } class Teacher extends Person{ public Teacher(){ this.name = "老師"; } } ``` ### 哪些類型可以有Class物件 ![](https://i.imgur.com/secOtdb.png) ```java= package com.ykma.reflaction; import java.lang.annotation.ElementType; //所有類型的class public class Test04 { public static void main(String[] args) { Class c1 = Object.class; //類 Class c2 = Comparable.class; //介面(接口) Class c3 = String[].class; //一維陣列 Class c4 = int[][].class; //二維陣列 Class c5 = Override.class; //註解 Class c6 = ElementType.class; //枚舉 Class c7 = Integer.class; //基本數據類型 Class c8 = void.class; //void Class c9 = Class.class; //Class System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); //只要元素類型與維度一樣,就是同一個Class int[] a = new int[10]; int[] b = new int[100]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } } ``` ### 從JAVA記憶體分析 ![](https://i.imgur.com/x1ioTeB.png) 了解類的加載過程: ![](https://i.imgur.com/gfH7sVF.png) ![](https://i.imgur.com/bVZnSQD.png) ```java= package com.ykma.reflaction; public class Test05 { public static void main(String[] args) { A a = new A(); System.out.println(a.m); /* 1.加載到記憶體,會產生一個類對應Class物件 2.鏈結,鏈結結束後 m = 0 3.初始化 <clinit>(){ System.out.println("A類靜態程式碼區塊初始化"); m = 300; m = 100; } m = 100; */ } } class A{ static { System.out.println("A類靜態程式碼區塊初始化"); m = 300; } static int m = 100; public A(){ System.out.println("A類的無參建構初始化"); } } ``` ![](https://i.imgur.com/Ou4sJho.png) ### 分析類初始化 甚麼時候會發生類的初始化?: ![](https://i.imgur.com/QBaXMbE.png) ```java= package com.ykma.reflaction; //測試類甚麼時候會初始化 public class Test06 { static { System.out.println("main類被加載"); } public static void main(String[] args) throws ClassNotFoundException { //1.主動引用 Son son = new Son(); //反射也會產生主動引用 Class.forName("com.ykma.reflaction.Son"); //不會產生類的引用的方法 System.out.println(Son.b); Son[] array = new Son[5]; System.out.println(Son.M); } } class Father{ static int b = 2; static { System.out.println("父類被加載"); } } class Son extends Father{ static { System.out.println("子類被加載"); m = 300; } static int m = 100; static final int M = 1; } ``` ### 類加載器 ![](https://i.imgur.com/OS9Uk3y.png) ![](https://i.imgur.com/VuVmnpC.png) ```java= package com.ykma.reflaction; public class Test07 { public static void main(String[] args) throws ClassNotFoundException { //獲取系統類的加載器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //獲取系統類加載器的父類加載器-->擴展類加載器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); //獲取擴展類加載器的父類加載器-->根加載器(c/c++) ClassLoader parent1 = parent.getParent(); System.out.println(parent1); //測試當前類是哪個加載器加載的 ClassLoader classLoader = Class.forName("com.ykma.reflaction.Test07").getClassLoader(); System.out.println(classLoader); //測試JDK內置的類是誰加載的 classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader); //如何獲得系統類加載器可以加載的路徑 System.out.println(System.getProperty("java.class.path")); //雙親委派機制 } } ``` ### 建構運行時類的物件 經過以上的內容,接下來我們要創建運行時類的物件,首先創建必須要先獲取: ![](https://i.imgur.com/FMjHEqD.png) ```java= package com.ykma.reflaction; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //獲得類的訊息 public class Test08 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.ykma.reflaction.User"); User user = new User(); c1 = user.getClass(); //獲得類的名字 System.out.println(c1.getName()); //獲得包名 + 類名 System.out.println(c1.getSimpleName()); //獲得類名 //獲得類的屬性 System.out.println("============================="); Field[] fields = c1.getFields(); //只能找到public屬性 fields = c1.getDeclaredFields(); //可以找到全部的屬性 for (Field field : fields) { System.out.println(field); } //獲得指定屬性的值 Field name = c1.getDeclaredField("name"); System.out.println(name); //獲得類的方法 System.out.println("============================="); Method[] methods = c1.getMethods(); //獲得本類及其父類的全部public方法 for (Method method : methods) { System.out.println("正常的:"+method); } methods = c1.getDeclaredMethods(); //獲得本類的所有方法 for (Method method : methods) { System.out.println("getDeclaredMethods:"+method); } //獲得指定方法 //為何要參數? --> 重載overload Method getName = c1.getMethod("getName", null); Method setName = c1.getMethod("setName", String.class); System.out.println(getName); System.out.println(setName); //獲得構造器(建構子) System.out.println("============================="); Constructor[] constructors = c1.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } constructors = c1.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.println("#"+constructor); } //獲得指定的構造器(建構子) Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class); System.out.println("指定:"+declaredConstructor); } } ``` 小結: ![](https://i.imgur.com/cuA5toF.png) ### 有了Class物件後,如何使用 ![](https://i.imgur.com/w79npHZ.png) 如何調用指定的方法: ![](https://i.imgur.com/PtskO01.png) Invoke: ![](https://i.imgur.com/nASSOTd.png) setAccessible: ![](https://i.imgur.com/BWQ3uVW.png) ```java= package com.ykma.reflaction; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //透過反射動態的建構物件 public class Test09 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //獲得Class物件 Class c1 = Class.forName("com.ykma.reflaction.User"); //建構一個物件 // User user = (User)c1.newInstance(); //本質是調用了類的無參構造器(建構子) // System.out.println(user); //透過構造器(建構子)創建物件 // Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); // User user2 = (User)constructor.newInstance("ykma", 001, 18); // System.out.println(user2); //透過反射調用普通方法 User user3 = (User)c1.newInstance(); //透過反射獲取一個方法 Method setName = c1.getDeclaredMethod("setName", String.class); //invoke:激活的意思 //(物件,"方法的值") setName.invoke(user3,"馬凱"); System.out.println(user3.getName()); //透過反射操作屬性 System.out.println("=========================================================="); User user4 = (User)c1.newInstance(); Field name = c1.getDeclaredField("name"); //不能直接操作私有屬性,我們需要關閉程序的安全檢測,屬性或方法的setAccessible(true) name.setAccessible(true); name.set(user4,"馬凱2"); System.out.println(user4.getName()); } } ``` ### 性能對比分析 ```java= package com.ykma.reflaction; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //分析性能問題 public class Test10 { //普通方式調用 public static void test01(){ User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方式執行10億次:"+(endTime-startTime)+"ms"); } //反射方式調用 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式執行10億次:"+(endTime-startTime)+"ms"); } //反射方式調用,關閉檢測 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("關閉檢測執行10億次:"+(endTime-startTime)+"ms"); } public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { test01(); test02(); test03(); } } ``` ### 使用反射來操作泛型 ![](https://i.imgur.com/MRrU13Y.png) 透過反射來讀取泛型: ```java= package com.ykma.reflaction; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; //透過反射獲取泛型 public class Test11 { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = Test11.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for (Type genericParameterType : genericParameterTypes) { System.out.println("#"+genericParameterType); if (genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } method = Test11.class.getMethod("test02", null); Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } } ``` ### ==**(重要)透過反射來操作註解**== 1. getAnnotations 2. getAnnotation 甚麼是**ORM(Object Relationship Mapping)**: ORM其實就是透過類跟資料庫中的表做映射: ![](https://i.imgur.com/0Fp0Zdz.png) ```java= package com.ykma.reflaction; import java.lang.annotation.*; import java.lang.reflect.Field; //練習反射操作註解 public class Test12 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.ykma.reflaction.Student2"); //透過反射獲得註解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //獲得註解的value的值 Tableykma tableykma = (Tableykma)c1.getAnnotation(Tableykma.class); String value = tableykma.value(); System.out.println(value); //獲得類指定的註解 Field f = c1.getDeclaredField("id"); Fieldykma annotation = f.getAnnotation(Fieldykma.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); } } @Tableykma("db_student") class Student2{ @Fieldykma(columnName = "db_id",type = "int",length = 10) private int id; @Fieldykma(columnName = "db_age",type = "int",length = 10) private int age; @Fieldykma(columnName = "db_name",type = "varchar",length = 3) private String name; public Student2() { } public Student2(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student2{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } //類名的註解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Tableykma{ String value(); } //屬性的註解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Fieldykma{ String columnName(); String type(); int length(); } ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully