国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【JVM學(xué)習(xí)】Class文件解析

這篇具有很好參考價(jià)值的文章主要介紹了【JVM學(xué)習(xí)】Class文件解析。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

簡介

最近為了加深對(duì)于JAVA的理解,在復(fù)習(xí)JVM,這里面的內(nèi)容大部分都是比較確定的、文檔性質(zhì)的內(nèi)容,目前并沒有特別的總結(jié)。但是看到類文件結(jié)構(gòu),手癢,想寫了個(gè)解析文件的解析器,那就簡單記錄下吧。

JAVA類文件結(jié)構(gòu)

詳細(xì)內(nèi)容不記了,太多了,有興趣的同學(xué)看虛擬機(jī)相關(guān)書籍了解,這里只簡單介紹下。
1 類文件使用類似結(jié)構(gòu)體的偽結(jié)構(gòu),基本數(shù)據(jù)類型有兩種:無符號(hào)數(shù)和表。無符號(hào)數(shù)有1、2、4、8四種長度;表可以由無符號(hào)數(shù)或其它復(fù)合類型作為元素,組成數(shù)據(jù)列表。
2 復(fù)合類型也只由上述兩種基本類型組成。
3 類文件按固定結(jié)構(gòu)存儲(chǔ),表類型例外,因?yàn)槔锩娴脑乜梢允遣煌膹?fù)合類型,因此排列順序不一定是固定順序。
4 常量池。類名、函數(shù)名、字符串等信息,類文件的解析最終都要在常量池中找到對(duì)應(yīng)的索引。不同的常量結(jié)構(gòu)體用tag(數(shù)字)區(qū)分。
5 屬性表。不管是field、method還是類本身,都有屬性表,不同的屬性結(jié)構(gòu)體用屬性名稱(字符串)區(qū)分。

設(shè)計(jì)思路

做過協(xié)議解析的同學(xué)肯定了解,類似這種情況,一般都會(huì)使用TLV(type、length、value)結(jié)構(gòu)解析,知道類型,才知道長度,知道長度才能完整讀出該類型對(duì)應(yīng)的數(shù)據(jù)。無論是協(xié)議,還是class、elf文件,這種方式都是常規(guī)操作。使用這種方式,除了定義完整的類型外,還要在解析中處理不同的類型。
那這次用的是JAVA,想換一個(gè)不一樣的思路,即使用泛型和反射,類型的定義不可避免,那么是否可以減少解析過程中對(duì)于類型的處理?
基于這個(gè)想法,簡單的按照類文件結(jié)構(gòu)進(jìn)行了相關(guān)結(jié)構(gòu)體的定義,并實(shí)現(xiàn)了一版,直接上代碼吧,我個(gè)人覺得基本達(dá)到了目的, 不算打印方法,250行左右,解析邏輯比較簡單。

public class Parser {
    public Parser() {
        initConstantPoolMap();
        initAttributeMap();
    }

    /**
     * 復(fù)合類型解析
     * @param obj 待解析填充的對(duì)象
     * @param inputStream 文件流
     */
    public void parse(Object obj, DataInputStream inputStream) throws ClassNotFoundException, IllegalAccessException, IOException, InstantiationException {
        Field[] fields = obj.getClass().getDeclaredFields();

        for (Field field : fields) {
            System.out.println(field.getName() + " : " + field.getGenericType());

            field.setAccessible(true);
            Type type = field.getGenericType();
            Class fieldClass = null;
            Class[] actualClassArguments = new Class[2];
            if (type instanceof Class) {
                fieldClass = (Class) type;
            } else if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                fieldClass = (Class) parameterizedType.getRawType();
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                actualClassArguments = new Class[actualTypeArguments.length];
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    actualClassArguments[i] = (Class) actualTypeArguments[i];
                }
            } else {
                throw new InstantiationException("illegal field type: " + field.getGenericType());
            }
            if (fieldClass.getSuperclass().equals(AtomicType.class)) {
                AtomicType o = parseAtomic(fieldClass, inputStream);
                field.set(obj, o);
            } else if (fieldClass.equals(Table.class)) {
                Table table = (Table) field.get(obj);
                table.setCountClass(actualClassArguments[0]);
                table.setElementClass(actualClassArguments[1]);
                parseTable(table, inputStream);
            } else {
                field.set(obj, parseMeta(fieldClass, inputStream));
            }
        }
    }

    /**
     * 原子數(shù)據(jù)類型解析(類文件定義的四種無符號(hào)數(shù)據(jù)類型)
     * @param cl 帶解析的類信息
     * @param inputStream 文件流
     * @return 解析后實(shí)例的的對(duì)象
     */
    private AtomicType parseAtomic(Class<?> cl, DataInputStream inputStream) throws IllegalAccessException, InstantiationException, IOException {
        AtomicType obj = (AtomicType) cl.newInstance();
        inputStream.read(obj.getBytes());
        System.out.println(cl.getTypeName() + " parsed: " + obj.getValue());
        return obj;
    }

    /**
     * 通用表結(jié)構(gòu)解析
     * @param table 表對(duì)象
     * @param inputStream 文件流
     */
    private void parseTable(Table table, DataInputStream inputStream) throws IllegalAccessException, InstantiationException, ClassNotFoundException, IOException {
        AtomicType count = parseAtomic(table.getCountClass(), inputStream);
        table.setCount(count);
        System.out.println("table count: " + count.getValue());
        if (count.getIntValue() == 0) {
            return;
        } else if (table.getElementClass().getSuperclass().equals(Number.class)) {
            parseNumber(table, inputStream);
        }  else if (table.getElementClass().getTypeName().equals(cp_info.class.getTypeName())) {
            parseConstantPool(table, inputStream);
        } else if (table.getElementClass().getTypeName().equals(attribute_info.class.getTypeName())) {
            parseAttribute(table, inputStream);
        } else {
            parseMetas(table, inputStream);
        }
    }

    /**
     * 其它復(fù)合類型的表結(jié)構(gòu)解析
     * @param table 表對(duì)象
     * @param inputStream 文件流
     */
    private void parseMetas(Table table, DataInputStream inputStream) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException {
        for (int i = 0; i < table.getCount().getIntValue(); i++) {
            table.getData().add(parseMeta(table.getElementClass(), inputStream));
        }
    }

    /**
     * 復(fù)合類型解析(根據(jù)類型實(shí)例化后填充)
     * @param cl 待解析類信息
     * @param inputStream 文件流
     * @return 解析后的實(shí)例
     */
    private Object parseMeta(Class cl, DataInputStream inputStream) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
        Object o = cl.newInstance();
        parse(o, inputStream);
        return o;
    }

    /**
     * 解析原子數(shù)據(jù)類型(非class文件定義的無符號(hào)數(shù))
     * @param table 表對(duì)象
     * @param inputStream 文件流
     */
    private void parseNumber(Table table, DataInputStream inputStream) throws IOException, InstantiationException {
        for (int i = 0; i < table.getCount().getIntValue(); i++) {
            if (table.getElementClass().equals(Byte.class)) {
                table.getData().add(inputStream.readByte());
            } else if (table.getElementClass().equals(Short.class)) {
                table.getData().add(inputStream.readShort());
            } else {
                throw new InstantiationException("illegal number class : " + table.getElementClass());
            }
        }
    }

    /**
     * 解析常量池
     * @param table 表對(duì)象
     * @param inputStream 文件流
     */
    private void parseConstantPool(Table table, DataInputStream inputStream) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
        for (int i = 0; i < table.getCount().getIntValue() - 1; i++) {
            table.getData().add(parseConstantPool(inputStream));
        }
    }

    /**
     * 解析單個(gè)常量對(duì)象
     * @param inputStream 表對(duì)象
     * @return 常量對(duì)象
     */
    private Object parseConstantPool(DataInputStream inputStream) throws IllegalAccessException, IOException, InstantiationException, ClassNotFoundException {
        AtomicType tag = parseAtomic(u1.class, inputStream);

        Class cl = constPoolMap.get(tag.getIntValue());
        if (cl == null) {
            throw new InstantiationException("not found const pool class: " + tag.getValue());
        }
        Object obj = cl.newInstance();
        parse(obj, inputStream);
        System.out.println("parse constant pool: tag = " + tag.getValue());
        return obj;
    }

    /**
     * 解析屬性表
     * @param table 表對(duì)象
     * @param inputStream 文件流
     */
    private void parseAttribute(Table table, DataInputStream inputStream) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        for (int i = 0; i < table.getCount().getIntValue(); i++) {
            table.getData().add(parseAttribute(inputStream));
        }
    }

    /**
     * 解析單個(gè)屬性
     * @param inputStream 文件流
     * @return 單個(gè)屬性對(duì)象
     */
    private Object parseAttribute(DataInputStream inputStream) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
        attribute_info attr = new attribute_info();
        parse(attr, inputStream);
        String name = getUtf8((int) attr.getAttribute_name_index().getValue());
        if (name == null) {
            throw new InstantiationException("not found attribute name: " + attr.getAttribute_name_index().getValue());
        }
        System.out.println("parse attribute: " + name);

        Class cl = attributeMap.get(name);
        if (cl == null) {
            throw new InstantiationException("not found attribute: " + name);
        }

        return parseMeta(cl, inputStream);
    }

    /**
     * 獲取常量池中的對(duì)象
     * @param index 常量池索引
     * @return 常量對(duì)象
     */
    private cp_info getConstant(int index) {
        if (index == 0 || index >= classInfo.getConstant_pool().getData().size()) {
            return null;
        }
        return classInfo.getConstant_pool().getData().get(index - 1);
    }

    /**
     * 獲取字符串對(duì)象
     * @param index 索引
     * @return 字符串
     */
    private String getUtf8(int index) {
        cp_info c = getConstant(index);
        if (c == null) {
            return null;
        }
        if (!(c instanceof utf8_info)) {
            System.out.println("not utf8 constant");
            return null;
        }
        utf8_info utf8 = (utf8_info) c;
        return utf8.toString();
    }

    // 類文件對(duì)象
    private static class_info classInfo = new class_info();
    // 常量池類型映射表
    private static Map<Integer, Class> constPoolMap = new HashMap<>();
    // 屬性映射表
    private static Map<String, Class> attributeMap = new HashMap<>();

    private static void initConstantPoolMap() {
        constPoolMap.put(1, utf8_info.class);
        constPoolMap.put(3, integer_info.class);
        constPoolMap.put(4, float_info.class);
        constPoolMap.put(5, long_info.class);
        constPoolMap.put(6, double_info.class);
        constPoolMap.put(7, constant_class_info.class);
        constPoolMap.put(8, string_info.class);
        constPoolMap.put(9, fieldref_info.class);
        constPoolMap.put(10, methodref_info.class);
        constPoolMap.put(11, interfacemethodref_info.class);
        constPoolMap.put(12, nametype_info.class);
    }

    private static void initAttributeMap() {
        attributeMap.put("Code", code_info.class);
        attributeMap.put("Exceptions", throws_info.class);
        attributeMap.put("LineNumberTable", LineNumberTable.class);
        attributeMap.put("LocalVariableTable", LocalVariableTable.class);
        attributeMap.put("SourceFile", SourceFile.class);
        attributeMap.put("ConstantValue", ConstantValue.class);
        attributeMap.put("InnerClasses", InnerClasses.class);
    }

    private static void print(Class cl, Object obj, String prefix, StringBuilder sb) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
        Field[] fields = cl.getDeclaredFields();

        sb.append(prefix).append(cl.getSimpleName()).append(":{\n");
        for (Field field : fields) {
            field.setAccessible(true);
            Type type = field.getGenericType();
            Class fieldClass = null;
            Class[] actualClassArguments = new Class[2];
            if (type instanceof Class) {
                fieldClass = (Class) type;
            } else if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                fieldClass = (Class) parameterizedType.getRawType();
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                actualClassArguments = new Class[actualTypeArguments.length];
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    actualClassArguments[i] = (Class) actualTypeArguments[i];
                }
            } else {
                throw new InstantiationException("illegal field type: " + field.getGenericType());
            }

            Object o = field.get(obj);
            if (fieldClass.getSuperclass().equals(AtomicType.class) && field.getName().endsWith("_index")) {
                AtomicType v = (AtomicType) o;
                sb.append(prefix).append(field.getName() + ": #" + v.getValue() + " : ");
                printConstant(v.getIntValue(), sb);
                sb.append("\n");
            } else if (fieldClass.getSuperclass().equals(AtomicType.class)) {
                AtomicType v = (AtomicType) o;
                sb.append(prefix + field.getName() + " : " + v.getValue()).append("\n");
            } else if (fieldClass.equals(Table.class)) {
                Table table = (Table) o;

                sb.append(prefix).append(field.getName() + ": ").append("[\n");
                for (int i = 0; i < table.getData().size(); i++) {
                    Class fcl = table.getData().get(i).getClass();
                    if (table.getElementClass().equals(cp_info.class)) {
                        sb.append(prefix).append("    ").append("#" + (i + 1) + " = " + table.getData().get(i).toString()).append("\n");
                    } else if (fcl.equals(Byte.class) || fcl.equals(Short.class)) {
                        sb.append(table.getData().get(i));
                    } else {
                        print(fcl, table.getData().get(i), prefix + "   ", sb);
                    }
                }
                if (table.getCount().getIntValue() > 0 &&
                        (table.getElementClass().equals(Byte.class) || table.getElementClass().equals(Short.class))) {
                    sb.append("\n");
                }
                sb.append(prefix).append("]\n");
            } else {
                sb.append(prefix).append(field.getName() + ": ").append("\n");
                Class fcl = Class.forName(field.getGenericType().getTypeName());
                print(fcl, o, prefix + "    ", sb);
            }
        }
        sb.append(prefix).append("}\n");
    }

    private static void printConstant(int index, StringBuilder sb) throws IllegalAccessException {
        if (index == 0) {
            return;
        }
        cp_info info = classInfo.getConstant_pool().getData().get(index - 1);
        if (info instanceof utf8_info) {
            sb.append(info.toString());
            return;
        }
        sb.append(" -> " + info.getClass().getSimpleName() + " :");
        Field[] fields = info.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (!field.getName().endsWith("_index")) {
                continue;
            }
            field.setAccessible(true);
            AtomicType o = (AtomicType) field.get(info);
            sb.append(field.getName() + " :#");
            sb.append(o.getValue() + " -> ");
            printConstant(o.getIntValue(), sb);
            sb.append("; ");
        }
    }

    public static void main(String[] args) throws IOException {
        Parser parser = new Parser();
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream("Bean.class");

            // Create a new DataInputStream object with the FileInputStream object
            DataInputStream dataInputStream = new DataInputStream(fileInputStream);
            parser.parse(classInfo, dataInputStream);
            StringBuilder sb = new StringBuilder();
            print(class_info.class, classInfo, "", sb);
            System.out.println(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            fileInputStream.close();
        }
    }

}

再補(bǔ)充幾個(gè)結(jié)構(gòu)體定義實(shí)例:

public class Table<N extends AtomicType, T> {
    private N count;
    private LinkedList<T> data = new LinkedList<>();
    private Class countClass;
    private Class elementClass;

    public Table() {

    }
    public N getCount() {
        return count;
    }

    public void setCount(N count) {
        this.count = count;
    }

    public LinkedList<T> getData() {
        return data;
    }

    public void setData(LinkedList<T> data) {
        this.data = data;
    }

    public Class getCountClass() {
        return countClass;
    }

    public Class getElementClass() {
        return elementClass;
    }

    public void setCountClass(Class countClass) {
        this.countClass = countClass;
    }

    public void setElementClass(Class elementClass) {
        this.elementClass = elementClass;
    }

    public String toString() {
        return "count: " + count;
    }
}


public abstract class AtomicType<T extends Number> {
    private int length;
    private byte[] bytes;
    private T value;

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public T getValue() {
        if (value != null) {
            return value;
        }
        parse();
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public byte[] getBytes() {
        return bytes;
    }

    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }

    public abstract void parse();

    public int getIntValue() {
        return getValue().intValue();
    }
}

public class u2 extends AtomicType<Short> {
    public u2() {
        setLength(2);
        setBytes(new byte[2]);
    }

    @Override
    public void parse() {
        short x =  (short) ((((short)(getBytes()[0])) << 8) + (((short)(getBytes()[1])) << 0));
        setValue(x);
    }
}
public class attribute_info {
    public u2 attribute_name_index;
    public u4 attribute_length;

    public u2 getAttribute_name_index() {
        return attribute_name_index;
    }
}
public class cp_info implements Printable {
    public u1 tag;
}
public class class_info {
    public u4 magic;
    public u2 minor_version;
    public u2 major_version;
    public Table<u2, cp_info> constant_pool = new Table<>();
    public u2 access_flags;
    public u2 this_class;
    public u2 super_class;
    public Table<u2, Short> interfaces = new Table<>();
    public Table<u2, field_info> fields = new Table<>();
    public Table<u2, method_info> methods = new Table<>();
    public Table<u2, attribute_info> attributes = new Table<>();

    public Table<u2, cp_info> getConstant_pool() {
        return constant_pool;
    }
}

總結(jié)

不算完美,階段性成果吧。關(guān)于泛型,值得單獨(dú)寫一篇記錄一下。文章來源地址http://www.zghlxwxcb.cn/news/detail-411918.html

到了這里,關(guān)于【JVM學(xué)習(xí)】Class文件解析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • class文件中,常量池之后的相關(guān)數(shù)據(jù)解析!【class二進(jìn)制文件分析】

    class文件中,常量池之后的相關(guān)數(shù)據(jù)解析!【class二進(jìn)制文件分析】

    前言:前段時(shí)間讀《深入java虛擬機(jī)》介紹到class文件的時(shí)候,由于理論知識(shí)較多,人總感覺疲憊不堪,就泛泛閱讀了一下。在工作中使用起來知識(shí)點(diǎn)知道,但是總是需要查閱各種資料。今天有時(shí)間,繼續(xù)整理常量池后面的相關(guān)知識(shí)。 class文件中,我們可以通過背或記也好,或

    2024年02月07日
    瀏覽(27)
  • 解析用GraalVm編譯的class文件

    解析用GraalVm編譯的class文件

    如果只是單純的用javap +class文件名的話,那只是單純的反編譯class文件而已。 我們都知道class文件的字節(jié)碼文件,是難以理解的。 很好理解。這里保存了最新更改時(shí)間和文件大小為414字節(jié)。 類聲明: 版本信息: 這表示 Java 編譯器的次要版本為 0,主要版本為 61。Java 版本號(hào)

    2024年01月18日
    瀏覽(20)
  • Golang實(shí)現(xiàn)JAVA虛擬機(jī)-解析class文件

    Golang實(shí)現(xiàn)JAVA虛擬機(jī)-解析class文件

    原文鏈接:https://gaoyubo.cn/blogs/de1bedad.html 所需前置知識(shí)為:JAVA語言、JVM知識(shí)、Go筆記 對(duì)應(yīng)項(xiàng)目:jvmgo 操作系統(tǒng):Windows 11 openjdk version \\\"1.8.0_382\\\" go version go1.21.0 windows/amd64 Java虛擬機(jī)的工作是運(yùn)行Java應(yīng)用程序。和其他類型的應(yīng)用程序一樣,Java應(yīng)用程序也需要一個(gè)入口點(diǎn),這個(gè)入

    2024年02月04日
    瀏覽(15)
  • Java中Excel文件解析(POI簡介及基本使用)

    在Java技術(shù)生態(tài)圈中,可以進(jìn)行Excel文件處理的主流技術(shù)包括: Apache POI 、 JXL 、 Alibaba EasyExcel 等。 其中各個(gè)技術(shù)都有最適合的場景 Apache POI 基于 DOM 方式進(jìn)行解析,將文件直接加載內(nèi)存,所以速度較快,適合 Excel 文件數(shù)據(jù)量不大的應(yīng)用場景。 JXL 只支持Excel 2003以下版本,所以

    2024年02月08日
    瀏覽(36)
  • jvm 什么是常量池,常量池定義 class常量池

    jvm 什么是常量池,常量池定義 class常量池

    首先需要理解下Java的class文件,以及class文件結(jié)構(gòu): 1. Class文件 是一組以8個(gè)字節(jié)為基礎(chǔ)單位的 二進(jìn)制流 ,各個(gè)數(shù)據(jù)項(xiàng)目嚴(yán)格按照順序緊湊地排列在文 件之中, 中間沒有任何分隔符 ,這使得整個(gè)Class文件中存儲(chǔ)的內(nèi)容幾乎全部是程序運(yùn)行的必要數(shù)據(jù), 沒有空隙存在 。當(dāng)遇到

    2024年02月11日
    瀏覽(17)
  • java中的線程不安全和實(shí)例解析(1),為了跳槽強(qiáng)刷1000道網(wǎng)絡(luò)安全真題

    java中的線程不安全和實(shí)例解析(1),為了跳槽強(qiáng)刷1000道網(wǎng)絡(luò)安全真題

    先自我介紹一下,小編浙江大學(xué)畢業(yè),去過華為、字節(jié)跳動(dòng)等大廠,目前阿里P7 深知大多數(shù)程序員,想要提升技能,往往是自己摸索成長,但自己不成體系的自學(xué)效果低效又漫長,而且極易碰到天花板技術(shù)停滯不前! 因此收集整理了一份《2024年最新網(wǎng)絡(luò)安全全套學(xué)習(xí)資料》

    2024年04月22日
    瀏覽(17)
  • ubuntu下自啟動(dòng)設(shè)置,為了開機(jī)自啟動(dòng)launch文件

    ubuntu下自啟動(dòng)設(shè)置,為了開機(jī)自啟動(dòng)launch文件

    每隔5秒鐘啟動(dòng)一個(gè)launch文件,也可以直接在一個(gè)launch文件中啟動(dòng)多個(gè),這里為了確保啟動(dòng)順利,添加了一些延時(shí) (1)、進(jìn)入主菜單界面在搜索框中輸入startup applications (2)、按照如下提示,加入后重啟啟動(dòng)即可實(shí)現(xiàn)自啟動(dòng)

    2024年02月10日
    瀏覽(19)
  • 文件系統(tǒng)內(nèi)部的inode是為了解決什么問題?有什么用途?

    文件系統(tǒng)內(nèi)部的inode(Index Node)是為了解決文件管理和數(shù)據(jù)存儲(chǔ)的問題,并提供了一些重要的用途,包括: 1. 文件索引:inode是文件系統(tǒng)中的一個(gè)數(shù)據(jù)結(jié)構(gòu),它存儲(chǔ)了文件的元數(shù)據(jù),如文件名、文件大小、文件權(quán)限、文件所有者等信息。inode相當(dāng)于一個(gè)文件的索引,通過它可

    2024年02月15日
    瀏覽(21)
  • 為了快速掌握使用 ChatGPT,我應(yīng)該著重學(xué)習(xí)什么?

    當(dāng)然!下面是更詳細(xì)的學(xué)習(xí)計(jì)劃,包含了每個(gè)章節(jié)的內(nèi)容和建議的學(xué)習(xí)時(shí)間: 章節(jié)一:ChatGPT簡介 ChatGPT是什么(10分鐘) 了解ChatGPT是一個(gè)基于深度學(xué)習(xí)的自然語言處理模型,能夠生成人類般的對(duì)話回復(fù)。 應(yīng)用領(lǐng)域和用途(10分鐘) 探索ChatGPT在客戶支持、虛擬助手、教育等領(lǐng)

    2024年02月12日
    瀏覽(22)
  • Vue3學(xué)習(xí)(僅為了記錄,參考意義不大)

    Vue3學(xué)習(xí)(僅為了記錄,參考意義不大)

    vue-cli是創(chuàng)建vue2.0的腳手架工具,create-vue是創(chuàng)建vue3的腳手架工具,create-vue構(gòu)建速度非???setup語法糖: 總結(jié): 開啟深度監(jiān)聽同樣的寫法 beforeUnmount和unmounted對(duì)應(yīng)beforeDestoryed和destoryed defineProps原理還是props,只不過在setup里面可以去接收使用 父組件里面寫v-model,子組件里defi

    2024年02月09日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包