主頁 > 區塊鏈 > String物件的存盤、拼接和比較

String物件的存盤、拼接和比較

2020-09-24 15:27:02 區塊鏈

String物件的存盤、拼接和比較

  • 一、String型別介紹
  • 二、String型別的存盤
    • 虛擬機運行時記憶體(JDK1.8以后)
    • 常量池
    • String物件的創建
  • 三、String型別的拼接
    • 通過concat方法拼接
    • 通過+號拼接
  • 四、字串的比較
    • equals方法
    • "=="運算子

( 以下原始碼都基于jdk11)

一、String型別介紹

String型別是參考資料型別,表示字串型別,String底層使用byte[]陣列來存盤char[]陣列,(JDK1.9及以后的版本,JDK1.9之前是使用char陣列保存,1.9為了節省空間,開始使用byte陣列保存)

@Stable
private final byte[] value;//定義byte陣列用于存盤建構式傳進的char陣列,最下方的代碼中有用到,

從上方的代碼中可以看出,String用于保存資料的陣列是private、final的,因此String型別是不可變的,

//String的建構式
public String(char value[]) {  this(value, 0, value.length, null);//呼叫另一個建構式,代碼在下方     }
String(char[] value, int off, int len, Void sig) {
    if (len == 0) {
        this.value = "".value;
        this.coder = "".coder;
        return;
    }
    if (COMPACT_STRINGS) {
        byte[] val = StringUTF16.compress(value, off, len);
        if (val != null) {
            this.value = val;
            this.coder = LATIN1;
            return;
        }
    }
    this.coder = UTF16;
    this.value = StringUTF16.toBytes(value, off, len);
}

二、String型別的存盤

虛擬機運行時記憶體(JDK1.8以后)

在這里插入圖片描述
JVM記憶體中與String型別存盤相關的結構主要有堆和虛擬機堆疊,

常量池

常量池在java用于保存在編譯期已確定的,已編譯的class檔案中的一份資料,它包括了關于類,方法,介面等中的常量,也包括字串常量,如String s = "java"這種申明方式;當然也可擴充,執行器產生的常量也會放入常量池,故認為常量池是JVM的一塊特殊的記憶體空間,

通過常量池的使用String實作了多個參考指向同一個常量池中的物件,大大的節省了記憶體空間的開銷,
JDK1.8之后,常量池存放于JVM運行時記憶體中的堆記憶體中,

String物件的創建

主要有以下兩種創建String物件的方式
1、String a="abcd";
使用這種創建方式時,若常量池中不存在"abcd"這個String物件,則會創建2個物件:在常量池中創建String型別的物件"abcd",常量池位于上圖所示的堆記憶體中、在堆疊中創建參考a保存"abcd"的記憶體地址,從而指向常量池中的"abcd"物件,堆疊既上圖所示的虛擬機堆疊,

若常量池中已存在"abcd"物件,則會直接回傳這個物件,只在堆疊中創建一個參考a指向該物件,
在這里插入圖片描述

2、String a=new String("abcd");
使用這種創建方式時,若常量池中不存在值為"abcd"的String物件,則會先在常量池中創建一個值為“abcd”的String物件,然后將其復制一份到堆記憶體中(常量池外,堆記憶體中,地址不同),然后在堆疊中創建一個參考a保存"abcd"在堆中的地址,從而指向堆記憶體中的該物件,共創建了三個物件
若常量池重已存在物件“abcd”,則省去在常量池中創建物件的這一步,共創建兩個物件
在這里插入圖片描述

三、String型別的拼接

通過concat方法拼接

String a="a";
String b="b";
System.out.println(a.concat(b));//通過a物件concat方法連接b物件,結果為"ab"

下面來看看concat方法的原始碼

   public String concat(String str) {
        int olen = str.length();
        if (olen == 0) {
            return this;
        }
        if (coder() == str.coder()) {//coder來標識字串的編碼格式是LATIN1還是UTF16,若兩個字串的編碼格式相等,則不用進行編碼格式轉換
            byte[] val = this.value;
            byte[] oval = str.value;
            int len = val.length + oval.length;//拼接后字串的長度
            byte[] buf = Arrays.copyOf(val, len);//創建一個新陣列存放拼接后的字串
            System.arraycopy(oval, 0, buf, val.length, oval.length);
            return new String(buf, coder);
        }
        int len = length();
        byte[] buf = StringUTF16.newBytesFor(len + olen);
        getBytes(buf, 0, UTF16);
        str.getBytes(buf, len, UTF16);
        return new String(buf, UTF16);
    }

從concat原始碼中容易得出,concat方法通過創建一個長度為兩字串長度之和的byte陣列來存放兩字串,然后將兩個字串依次放入陣列中,實作了字串的拼接,
至于為什么使用byte陣列,上面講過,String型別底層使用byte陣列存盤char陣列,因此concat使用byte陣列來存盤字串,如果用其他型別的陣列就要進行型別轉換,
注意:concat方法并不會對原物件進行改變,而是會回傳一個新的String物件,

通過+號拼接

通過+號的拼接主要分為兩種情況:有字串變數(既在堆疊中創建的參考)參與的拼接無字串變數參與,只有字串常量(常量池中的String物件)參與的拼接

有字串變數(既在堆疊中創建的參考)參與的拼接:

在網上找了下有字串變數參與+號拼接的實作原理,大部分說的都是:

運行時, 兩個字串str1, str2的拼接首先會呼叫String.valueOf(obj),這個Obj為str1,而String.valueOf(Obj)中的實作是return obj ==null ? “null” : obj.toString(),
然后產生StringBuilder, 呼叫的StringBuilder(str1)構造方法, 把StringBuilder初始化,長度為str1.length()+16,并且呼叫append(str1)!接下來呼叫StringBuilder.append(str2), 把第二個字串拼接進去, 然后呼叫StringBuilder.toString回傳結果,

下面我就得從底層中看看它們是如何實作拼接的,
打以下代碼:

public class Test{
   public static void main(String[] args){
        String str1 = "111111";
	String str2 = "222222";
	String str = str1 + str2;
	System.out.println(str);
   }
}

然后進入dos界面,在dos界面中進入檔案所在檔案夾,使用javac Test.java命令生成位元組碼,再使用javap -verbose Test命令進行反編譯,可以看到以下結果,(JDK1.9及以后的版本才能看到如下結果,JDK1.8及以前的可參考這篇博文:Java String + 拼接字串原理)
在這里插入圖片描述
容易看出以下兩行代碼 ,對應的是String str = str1 + str2;陳述句

8: invokedynamic #4,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
13: astore_3

動態指令invokedynamic指令會呼叫makeConcatWithConstants方法進行字串的連接,
該方法位于java.lang.invoke.StringConcatFactory類中,
下面是原始碼,容易看出這個方法里如果沒出問題,是直接呼叫doStringConcat方法

public static CallSite makeConcatWithConstants(MethodHandles.Lookup lookup,
                                               String name,
                                               MethodType concatType,
                                               String recipe,
                                               Object... constants) throws StringConcatException {
    if (DEBUG) {
        System.out.println("StringConcatFactory " + STRATEGY + " is here for " + concatType + ", {" + recipe + "}, " + Arrays.toString(constants));
    }

    return doStringConcat(lookup, name, concatType, false, recipe, constants);
}

下面是doStringConcat方法的部分原始碼,多的就省略了,可以看到回傳值中,mh呼叫asType方法適配得到MethodHandle物件,回傳值的邏輯就是單純的回傳一個結果,字串拼接是在mh物件生成的時候進行的,也就是在generate方法中進行,

 private static CallSite doStringConcat(MethodHandles.Lookup lookup,
                                           String name,
                                           MethodType concatType,
                                           boolean generateRecipe,
                                           String recipe,
                                           Object... constants) throws StringConcatException {
......
MethodHandle mh;
if (CACHE_ENABLE) {
    Key key = new Key(className, mt, rec);
    mh = CACHE.get(key);
    if (mh == null) {
        mh = generate(lookup, className, mt, rec);
        CACHE.put(key, mh);
    }
} else {
    mh = generate(lookup, className, mt, rec);
}
return new ConstantCallSite(mh.asType(concatType));

下面是generate方法的原始碼

private static MethodHandle generate(Lookup lookup, String className, MethodType mt, Recipe recipe) throws StringConcatException {
    try {
        switch (STRATEGY) {
            case BC_SB:
                return BytecodeStringBuilderStrategy.generate(lookup, className, mt, recipe, Mode.DEFAULT);
            case BC_SB_SIZED:
                return BytecodeStringBuilderStrategy.generate(lookup, className, mt, recipe, Mode.SIZED);
            case BC_SB_SIZED_EXACT:
                return BytecodeStringBuilderStrategy.generate(lookup, className, mt, recipe, Mode.SIZED_EXACT);
            case MH_SB_SIZED:
                return MethodHandleStringBuilderStrategy.generate(mt, recipe, Mode.SIZED);
            case MH_SB_SIZED_EXACT:
                return MethodHandleStringBuilderStrategy.generate(mt, recipe, Mode.SIZED_EXACT);
            case MH_INLINE_SIZED_EXACT:
                return MethodHandleInlineCopyStrategy.generate(mt, recipe);
            default:
                throw new StringConcatException("Concatenation strategy " + STRATEGY + " is not implemented");
        }
    } catch (Error | StringConcatException e) {
        // Pass through any error or existing StringConcatException
        throw e;
    } catch (Throwable t) {
        throw new StringConcatException("Generator failed", t);
    }
}

generate方法通過不同的STRATEGY(策略)值來呼叫不同物件的generate方法,那么,接下來看看Strategy型別,對檔案中的英文進行了一些簡單的翻譯,

 private enum Strategy {
        /**
         * 位元組碼生成器,呼叫{@link java.lang.StringBuilder}.
         */
        BC_SB,

        /**
         * 位元組碼生成器,呼叫 {@link java.lang.StringBuilder};
         * 但要估計所需的存盤空間,
         */
        BC_SB_SIZED,

        /**
         * 位元組碼生成器,呼叫 {@link java.lang.StringBuilder};
         * 但需要精確地計算所需的存盤空間,
         */
        BC_SB_SIZED_EXACT,

        /**
         *基于MethodHandle的生成器,最終呼叫 {@link java.lang.StringBuilder}.
         * 此策略還嘗試估計所需的存盤空間,
         */
        MH_SB_SIZED,

        /**
         * 基于MethodHandle的生成器,最終呼叫 {@link java.lang.StringBuilder}.
         * 此策略也需要準確地計算所需的存盤空間,
         */
        MH_SB_SIZED_EXACT,

        /**
         * 基于MethodHandle的生成器, 基于MethodHandle的生成器,從引數構造自己的byte[]陣列,它精確地計算所需的存盤空間,
         */
        MH_INLINE_SIZED_EXACT
    }

主要就是針對不同的情況,使用不同的策略值,共六種策略,從而能呼叫適用于當前情況的generate方法,上面五種策略的實作都是基于StringBuilder,
接下來以上面的BytecodeStringBuilderStrategy中的generate方法為例,來具體看一看是怎么實作字串拼接的(套了一堆娃,終于到正題了)
首先,是呼叫String的ValueOf()方法

             if (mode.isExact()) {
/*在精確模式下,我們需要將所有引數轉換為字串表示,因為這允許精確計算它們的字串大小,我們不能在這里使用私有的原語方法,因此我們也需要轉換它們,

我們還記錄了轉換結果中保證為非null的引數,字串.valueOf是否為我們檢查空,唯一極端的情況是字串.valueOf(物件)回傳null本身,

此外,如果發生任何轉換,則傳入引數中的插槽索引不等于最終的本地映射,唯一可能會中斷的情況是將2-slot long/double轉換為1-slot時,因此,我們可以跟蹤修改過的偏移,因為沒有轉換可以覆寫即將到來的引數,
*/
                int off = 0;
                int modOff = 0;
                for (int c = 0; c < arr.length; c++) {
                    Class<?> cl = arr[c];
                    if (cl == String.class) {
                        if (off != modOff) {
                            mv.visitIntInsn(getLoadOpcode(cl), off);
                            mv.visitIntInsn(ASTORE, modOff);
                        }
                    } else {
                        mv.visitIntInsn(getLoadOpcode(cl), off);
                        mv.visitMethodInsn(
                                INVOKESTATIC,
                                "java/lang/String",
                                "valueOf",
                                getStringValueOfDesc(cl),
                                false
                        );
                        mv.visitIntInsn(ASTORE, modOff);
                        arr[c] = String.class;
                        guaranteedNonNull[c] = cl.isPrimitive();
                    }
                    off += getParameterSize(cl);
                    modOff += getParameterSize(String.class);
                }
            }

            if (mode.isSized()) {
            /*在調整大小模式(包括精確模式)下操作時,讓StringBuilder附加鏈看起來熟悉優化StringConcat是有意義的,為此,我們需要盡早進行空檢查,而不是使附加鏈形狀更簡單,*/

                int off = 0;
                for (RecipeElement el : recipe.getElements()) {
                    switch (el.getTag()) {
                        case TAG_CONST:
                            // Guaranteed non-null, no null check required.
                            break;
                        case TAG_ARG:
                            // Null-checks are needed only for String arguments, and when a previous stage
                            // did not do implicit null-checks. If a String is null, we eagerly replace it
                            // with "null" constant. Note, we omit Objects here, because we don't call
                            // .length() on them down below.
                            int ac = el.getArgPos();
                            Class<?> cl = arr[ac];
                            if (cl == String.class && !guaranteedNonNull[ac]) {
                                Label l0 = new Label();
                                mv.visitIntInsn(ALOAD, off);
                                mv.visitJumpInsn(IFNONNULL, l0);
                                mv.visitLdcInsn("null");
                                mv.visitIntInsn(ASTORE, off);
                                mv.visitLabel(l0);
                            }
                            off += getParameterSize(cl);
                            break;
                        default:
                            throw new StringConcatException("Unhandled tag: " + el.getTag());
                    }
                }
            }

然后是生成StringBuilder物件并使用append方法依次將字串加入

// 準備StringBuilder實體
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);

if (mode.isSized()) {
 /*大小模式要求我們遍歷引數,并估計最終長度,
   在精確模式下,這將僅在字串上操作,此代碼將在堆疊上累積最終長度,*/
    int len = 0;
    int off = 0;

    mv.visitInsn(ICONST_0);

    for (RecipeElement el : recipe.getElements()) {
        switch (el.getTag()) {
            case TAG_CONST:
                len += el.getValue().length();
                break;
            case TAG_ARG:
                /*
                   如果一個引數是String,那么我們可以對它呼叫.length(),大小/精確模式為我們轉換了引數,
                   如果一個引數是原始的,我們可以猜測它的字串表示大小,
                */
                Class<?> cl = arr[el.getArgPos()];
                if (cl == String.class) {
                    mv.visitIntInsn(ALOAD, off);
                    mv.visitMethodInsn(
                            INVOKEVIRTUAL,
                            "java/lang/String",
                            "length",
                            "()",
                            false
                    );
                    mv.visitInsn(IADD);
                } else if (cl.isPrimitive()) {
                    len += estimateSize(cl);
                }
                off += getParameterSize(cl);
                break;
            default:
                throw new StringConcatException("Unhandled tag: " + el.getTag());
        }
    }

    // 常數具有非零長度,混合
    if (len > 0) {
        iconst(mv, len);
        mv.visitInsn(IADD);
    }

    mv.visitMethodInsn(
            INVOKESPECIAL,
            "java/lang/StringBuilder",
            "<init>",
            "(I)V",
            false
    );
} else {
    mv.visitMethodInsn(
            INVOKESPECIAL,
            "java/lang/StringBuilder",
            "<init>",
            "()V",
            false
    );
}

// 此時,堆疊上有一個空的StringBuilder,用.append呼叫填充它,
{
    int off = 0;
    for (RecipeElement el : recipe.getElements()) {
        String desc;
        switch (el.getTag()) {
            case TAG_CONST:
                mv.visitLdcInsn(el.getValue());
                desc = getSBAppendDesc(String.class);
                break;
            case TAG_ARG:
                Class<?> cl = arr[el.getArgPos()];
                mv.visitVarInsn(getLoadOpcode(cl), off);
                off += getParameterSize(cl);
                desc = getSBAppendDesc(cl);
                break;
            default:
                throw new StringConcatException("Unhandled tag: " + el.getTag());
        }

        mv.visitMethodInsn(//呼叫append方法
                INVOKEVIRTUAL,
                "java/lang/StringBuilder",
                "append",
                desc,
                false
        );
    }
}
            if (DEBUG && mode.isExact()) {
                /*
                    Exactness checks compare the final StringBuilder.capacity() with a resulting
                    String.length(). If these values disagree, that means StringBuilder had to perform
                    storage trimming, which defeats the purpose of exact strategies.
                 */

                /*
                   The logic for this check is as follows:

                     Stack before:     Op:
                      (SB)              dup, dup
                      (SB, SB, SB)      capacity()
                      (int, SB, SB)     swap
                      (SB, int, SB)     toString()
                      (S, int, SB)      length()
                      (int, int, SB)    if_icmpeq
                      (SB)              <end>

                   Note that it leaves the same StringBuilder on exit, like the one on enter.
                 */

                mv.visitInsn(DUP);
                mv.visitInsn(DUP);

                mv.visitMethodInsn(
                        INVOKEVIRTUAL,
                        "java/lang/StringBuilder",
                        "capacity",
                        "()I",
                        false
                );

                mv.visitInsn(SWAP);

                mv.visitMethodInsn(
                        INVOKEVIRTUAL,
                        "java/lang/StringBuilder",
                        "toString",
                        "()Ljava/lang/String;",
                        false
                );

                mv.visitMethodInsn(
                        INVOKEVIRTUAL,
                        "java/lang/String",
                        "length",
                        "()I",
                        false
                );

                Label l0 = new Label();
                mv.visitJumpInsn(IF_ICMPEQ, l0);

                mv.visitTypeInsn(NEW, "java/lang/AssertionError");
                mv.visitInsn(DUP);
                mv.visitLdcInsn("Failed exactness check");
                mv.visitMethodInsn(INVOKESPECIAL,
                        "java/lang/AssertionError",
                        "<init>",
                        "(Ljava/lang/Object;)V",
                        false);
                mv.visitInsn(ATHROW);

                mv.visitLabel(l0);
            }

下面是該方法中末尾的幾行代碼,主要就是呼叫StringBuilder的toString()方法并回傳該方法得到的物件,

mv.visitMethodInsn(//呼叫StringBuilder的toString()方法
        INVOKEVIRTUAL,
        "java/lang/StringBuilder",
        "toString",
        "()Ljava/lang/String;",
        false
);

mv.visitInsn(ARETURN);

mv.visitMaxs(-1, -1);
mv.visitEnd();
cw.visitEnd();

byte[] classBytes = cw.toByteArray();
try {
    Class<?> hostClass = lookup.lookupClass();
    Class<?> innerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, null);
    UNSAFE.ensureClassInitialized(innerClass);
    dumpIfEnabled(innerClass.getName(), classBytes);
    return Lookup.IMPL_LOOKUP.findStatic(innerClass, METHOD_NAME, args);
} catch (Exception e) {
    dumpIfEnabled(className + "$$FAILED", classBytes);
    throw new StringConcatException("Exception while spinning the class", e);
}

所以,總結一下,有字串變數參與拼接的程序:首先呼叫String的ValueOf方法,然后是生成一個StringBuilder物件并將用append方法將兩個字串依次加入,然后回傳StringBuilder的toString()方法,

只有字串常量(常量池中的String物件)參與的拼接:例如:String a=“ab”+cd;這種拼接,在編譯時,編譯器會自動將a變數編譯為"abcd"
例如以下代碼:
public class Test2{
public static void main(String[] args){
String str = “12”+“34”;
System.out.println(str);
}
}
用上述的方法同樣查看反編譯代碼
在這里插入圖片描述
可以看到編譯器直接將str字串編譯為了”1234“.

四、字串的比較

equals方法

String型別的物件有個equals方法,用于比較兩個String物件的是否相等,

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String aString = (String)anObject;
        if (coder() == aString.coder()) {//判斷編碼格式是否相等
            return isLatin1() ? StringLatin1.equals(value, aString.value)
                              : StringUTF16.equals(value, aString.value);
                              //根據編碼格式呼叫不同的equals方法
        }
    }
    return false;
}

下面是StringLatin1物件(以Latin1為編碼格式的String物件)的equals方法

@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
    if (value.length == other.length) {
        for (int i = 0; i < value.length; i++) {
            if (value[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
    return false;
}

然后是StringUTF16物件的equals方法

@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
    if (value.length == other.length) {
        int len = value.length >> 1;
        for (int i = 0; i < len; i++) {
            if (getChar(value, i) != getChar(other, i)) {
                return false;
            }
        }
        return true;
    }
    return false;
}

可以看出equals方法的實作邏輯就是通過for回圈遍歷保存字串的byte陣列,一位一位地進行判斷,

"=="運算子

“==”運算子用于比較兩個物件的地址是否相等,用在字串比較時,需要注意"abcd"與new String(“abcd”)所回傳的地址值不相同,具體看上方String物件的創建,

注意:上面我們具體分析了有字串變數參與的連接預算,最后的物件是由StringBuilder的toString()方法回傳的,而toString()方法底層是回傳的是new String()物件,存盤的地址是在堆中,而不是在常量池中,

@Override
@HotSpotIntrinsicCandidate
public String toString() {//StringBuilder物件的toString方法
    // Create a copy, don't share the array
    return isLatin1() ? StringLatin1.newString(value, 0, count)
                      : StringUTF16.newString(value, 0, count);
}
//StringLatin1物件的newString方法
public static String newString(byte[] val, int index, int len) {
    return new String(Arrays.copyOfRange(val, index, index + len),
                      LATIN1);
}
//StringUTF16的toString方法
public static String newString(byte[] val, int index, int len) {
    if (String.COMPACT_STRINGS) {
        byte[] buf = compress(val, index, len);
        if (buf != null) {
            return new String(buf, LATIN1);
        }
    }
    int last = index + len;
    return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/119771.html

標籤:區塊鏈

上一篇:spring官網筆記1

下一篇:SpringBoot-web開發(二): 首頁和圖示定制(原始碼分析)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • JAVA使用 web3j 進行token轉賬

    最近新學習了下區塊鏈這方面的知識,所學不多,給大家分享下。 # 1. 關于web3j web3j是一個高度模塊化,反應性,型別安全的Java和Android庫,用于與智能合約配合并與以太坊網路上的客戶端(節點)集成。 # 2. 準備作業 jdk版本1.8 引入maven <dependency> < ......

    uj5u.com 2020-09-10 03:03:06 more
  • 以太坊智能合約開發框架Truffle

    前言 部署智能合約有多種方式,命令列的瀏覽器的渠道都有,但往往跟我們程式員的風格不太相符,因為我們習慣了在IDE里寫了代碼然后打包運行看效果。 雖然現在IDE中已經存在了Solidity插件,可以撰寫智能合約,但是部署智能合約卻要另走他路,沒辦法進行一個快捷的部署與測驗。 如果團隊管理的區塊節點多、 ......

    uj5u.com 2020-09-10 03:03:12 more
  • 谷歌二次驗證碼成為區塊鏈專用安全碼,你怎么看?

    前言 谷歌身份驗證器,前些年大家都比較陌生,但隨著國內互聯網安全的加強,它越來越多地出現在大家的視野中。 比較廣泛接觸的人群是國際3A游戲愛好者,游戲盜號現象嚴重+國外賬號安全應用廣泛,這類游戲一般都會要求用戶系結名為“兩步驗證”、“雙重驗證”等,平臺一般都推薦用谷歌身份驗證器。 后來區塊鏈業務風靡 ......

    uj5u.com 2020-09-10 03:03:17 more
  • 密碼學DAY1

    目錄 ##1.1 密碼學基本概念 密碼在我們的生活中有著重要的作用,那么密碼究竟來自何方,為何會產生呢? 密碼學是網路安全、資訊安全、區塊鏈等產品的基礎,常見的非對稱加密、對稱加密、散列函式等,都屬于密碼學范疇。 密碼學有數千年的歷史,從最開始的替換法到如今的非對稱加密演算法,經歷了古典密碼學,近代密 ......

    uj5u.com 2020-09-10 03:03:50 more
  • 密碼學DAY1_02

    目錄 ##1.1 ASCII編碼 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際標準ISO/IE ......

    uj5u.com 2020-09-10 03:04:50 more
  • 密碼學DAY2

    ##1.1 加密模式 加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html ECB ECB : Electronic codebook, 電子密碼本. 需要加密的訊息按照塊密碼的塊大小被分為數個塊,并對每個塊進 ......

    uj5u.com 2020-09-10 03:05:42 more
  • NTP時鐘服務器的特點(京準電子)

    NTP時鐘服務器的特點(京準電子) NTP時鐘服務器的特點(京準電子) 京準電子官V——ahjzsz 首先對時間同步進行了背景介紹,然后討論了不同的時間同步網路技術,最后指出了建立全球或區域時間同步網存在的問題。 一、概 述 在通信領域,“同步”概念是指頻率的同步,即網路各個節點的時鐘頻率和相位同步 ......

    uj5u.com 2020-09-10 03:05:47 more
  • 標準化考場時鐘同步系統推進智能化校園建設

    標準化考場時鐘同步系統推進智能化校園建設 標準化考場時鐘同步系統推進智能化校園建設 安徽京準電子科技官微——ahjzsz 一、背景概述隨著教育事業的快速發展,學校建設如雨后春筍,隨之而來的學校教育、管理、安全方面的問題成了學校管理人員面臨的最大的挑戰,這些問題同時也是學生家長所擔心的。為了讓學生有更 ......

    uj5u.com 2020-09-10 03:05:51 more
  • 位元幣入門

    引言 位元幣基本結構 位元幣基礎知識 1)哈希演算法 2)非對稱加密技術 3)數字簽名 4)MerkleTree 5)哪有位元幣,有的是UTXO 6)位元幣挖礦與共識 7)區塊驗證(共識) 總結 引言 上一篇我們已經知道了什么是區塊鏈,此篇說一下區塊鏈的第一個應用——位元幣。其實先有位元幣,后有的區塊 ......

    uj5u.com 2020-09-10 03:06:15 more
  • 北斗對時服務器(北斗對時設備)電力系統應用

    北斗對時服務器(北斗對時設備)電力系統應用 北斗對時服務器(北斗對時設備)電力系統應用 京準電子科技官微(ahjzsz) 中國北斗衛星導航系統(英文名稱:BeiDou Navigation Satellite System,簡稱BDS),因為是目前世界范圍內唯一可以大面積提供免費定位服務的系統,所以 ......

    uj5u.com 2020-09-10 03:06:20 more
最新发布
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:46:47 more
  • Hyperledger Fabric 使用 CouchDB 和復雜智能合約開發

    在上個實驗中,我們已經實作了簡單智能合約實作及客戶端開發,但該實驗中智能合約只有基礎的增刪改查功能,且其中的資料管理功能與傳統 MySQL 比相差甚遠。本文將在前面實驗的基礎上,將 Hyperledger Fabric 的默認資料庫支持 LevelDB 改為 CouchDB 模式,以實作更復雜的資料... ......

    uj5u.com 2023-04-16 07:28:31 more
  • .NET Core 波場鏈離線簽名、廣播交易(發送 TRX和USDT)筆記

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. PM> Install-Package Tron.Wallet.Net 配置 public reco ......

    uj5u.com 2023-04-14 08:08:00 more
  • DKP 黑客分析——不正確的代幣對比率計算

    概述: 2023 年 2 月 8 日,針對 DKP 協議的閃電貸攻擊導致該協議的用戶損失了 8 萬美元,因為 execute() 函式取決于 USDT-DKP 對中兩種代幣的余額比率。 智能合約黑客概述: 攻擊者的交易:0x0c850f,0x2d31 攻擊者地址:0xF38 利用合同:0xf34ad ......

    uj5u.com 2023-04-07 07:46:09 more
  • Defi開發簡介

    Defi開發簡介 介紹 Defi是去中心化金融的縮寫, 是一項旨在利用區塊鏈技術和智能合約創建更加開放,可訪問和透明的金融體系的運動. 這與傳統金融形成鮮明對比,傳統金融通常由少數大型銀行和金融機構控制 在Defi的世界里,用戶可以直接從他們的電腦或移動設備上訪問廣泛的金融服務,而不需要像銀行或者信 ......

    uj5u.com 2023-04-05 08:01:34 more
  • solidity簡單的ERC20代幣實作

    // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; //ERC20 同質化代幣,每個代幣的本質或性質都是相同 //ETH 是原生代幣,它不是ERC20代幣, ......

    uj5u.com 2023-03-21 07:56:29 more
  • solidity 參考型別修飾符memory、calldata與storage 常量修飾符C

    在solidity語言中 參考型別修飾符(參考型別為存盤空間不固定的數值型別) memory、calldata與storage,它們只能修飾參考型別變數,比如字串、陣列、位元組等... memory 適用于方法傳參、返參或在方法體內使用,使用完就會清除掉,釋放記憶體 calldata 僅適用于方法傳參 ......

    uj5u.com 2023-03-08 07:57:54 more
  • solidity注解標簽

    在solidity語言中 注釋符為// 注解符為/* 內容*/ 或者 是 ///內容 注解中含有這幾個標簽給予我們使用 @title 一個應該描述合約/介面的標題 contract, library, interface @author 作者的名字 contract, library, interf ......

    uj5u.com 2023-03-08 07:57:49 more
  • 評價指標:相似度、GAS消耗

    【代碼注釋自動生成方法綜述】 這些評測指標主要來自機器翻譯和文本總結等研究領域,可以評估候選文本(即基于代碼注釋自動方法而生成)和參考文本(即基于手工方式而生成)的相似度. BLEU指標^[^?88^^?^]^:其全稱是bilingual evaluation understudy.該指標是最早用于 ......

    uj5u.com 2023-02-23 07:27:39 more
  • 基于NOSTR協議的“公有制”版本的Twitter,去中心化社交軟體Damus

    最近,一個幽靈,Web3的幽靈,在網路游蕩,它叫Damus,這玩意詮釋了什么叫做病毒式營銷,滑稽的是,一個Web3產品卻在Web2的產品鏈上瘋狂傳銷,各方大佬紛紛為其背書,到底發生了什么?Damus的葫蘆里,賣的是什么藥? 注冊和簡單實用 很少有什么產品在用戶注冊環節會有什么噱頭,但Damus確實出 ......

    uj5u.com 2023-02-05 06:48:39 more