serialization-protobuf

本文通过实验对比了Java序列化与Protobuf序列化在内存占用方面的表现,结果显示Protobuf序列化后的数据体积明显更小。

java : http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html

 

protobuf 简介:是一种序列化与结构化数据的一种机制,具有跨平台、解析速度快、序列化数据体积小、扩展性高、使用简单的特点

目标:验证protobuf序列化的内存占用量低于Java的直接序列化

 

java的实现:

 public static void serialize(Serializable obj, OutputStream outputStream) {
        if (outputStream == null) {
            throw new IllegalArgumentException("The OutputStream must not be null");
        }
        ObjectOutputStream out = null;
        try {
            // stream closed in the finally
            out = new ObjectOutputStream(outputStream);
            out.writeObject(obj);
            
        } catch (IOException ex) {
            throw new SerializationException(ex);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                // ignore close exception
            }
        }
    }

    public static byte[] serialize(Serializable obj) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
        serialize(obj, baos);
        return baos.toByteArray();
    }

 

protoBuf的实现:

需要先定义 User.proto 文件,然后通过protoc.exe 进行代码生成

D:\master\tts_search\serializer\src\proto>protoc.exe --java_out=. User.proto

 User.proto的定义如下:

option java_package = "com.ddd.fff.tts.search.serializer.proto";
option java_outer_classname = "UserProto";

message User {
    required string username = 1;
    optional string password = 2;
    repeated User friendList = 3;
}

 

 

测试代码:

package test.ddd.serializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.SerializationUtils;

import com.google.common.io.Files;
import com.ddd.fff.tts.search.serializer.proto.UserProto;

public class TestSerialization2 {
	public static void main(String[] args) throws Exception {
		testJava();
		testProto();
	}  
	
	private static void testProto()  throws Exception {
		UserProto.User.Builder me = UserProto.User.newBuilder();
		me.setUsername("xinchun.wang");
		me.setPassword("123456");

		for(int i =0;i<100000;i++){
			UserProto.User.Builder she = UserProto.User.newBuilder();
			she.setPassword("pass"+i);
			she.setUsername("name"+i);
			me.addFriendList(she);
		}

		UserProto.User user = me.build();

		ByteArrayOutputStream output = new ByteArrayOutputStream();
		user.writeTo(output);

		// -------------- 分割线:上面是发送方,将数据序列化后发送 ---------------

		byte[] byteArray = output.toByteArray();
		System.out.println(byteArray.length);

		ByteArrayInputStream input = new ByteArrayInputStream(byteArray);

		// 反序列化
		UserProto.User xxg2 = UserProto.User.parseFrom(input);
		System.out.println(xxg2);
	
	}
	
	private static void testJava() throws Exception {
		User me = new User();
		me.setPassword("123456");
		me.setUsername("xinchun.wang");

		for (int i = 0; i < 100000; i++) {
			User she = new User();
			she.setPassword("pass"+i);
			she.setUsername("name"+i);
			me.getFriendList().add(she);
		}

		System.out.println(SerializationUtils.serialize(me).length);
		Files.write(SerializationUtils.serialize(me), new File("data"));
	}
	
	
	public static class User implements Serializable{
		private static final long serialVersionUID = 1L;
		private String username;
		private String password;
		
		private List<User> friendList = new ArrayList<User>();
		
		public String getUsername() {
			return username;
		}
		public void setUsername(String username) {
			this.username = username;
		}
		public String getPassword() {
			return password;
		}
		public void setPassword(String password) {
			this.password = password;
		}
		public List<User> getFriendList() {
			return friendList;
		}
		public void setFriendList(List<User> friendList) {
			this.friendList = friendList;
		}
	}
}

 

输出:

java:4678004,约4M

proto:2377802,约2M

 

可见在有缓存的地方,还是用protoBuf可以节约不少内存空间的。

 

 

 

[versions] agp = "8.9.1" kotlin = "2.1.10" ksp = "2.1.10-1.0.30" compose-bom = "2025.02.00" lifecycle = "2.8.7" navigation = "2.8.7" activity-compose = "1.10.0" kotlinx-coroutines = "1.10.1" coil-compose = "2.7.0" compose-destination = "2.1.0-beta16" sheets-compose-dialogs = "1.3.0" markdown = "4.6.2" webkit = "1.12.1" appiconloader-coil = "1.5.0" parcelablelist = "2.0.1" libsu = "6.0.0" apksign = "1.4" cmaker = "1.2" compose-material = "1.7.8" compose-material3 = "1.3.1" compose-ui = "1.7.8" compose-foundation = "1.7.8" documentfile = "1.0.1" protobuf = "3.22.1" protobuf-gradle-plugin = "0.9.1" material = "1.10.0" androidxLifecycle = "2.8.7" squareRetrofit = "2.11.0" squareOkhttp = "4.12.0" kotlinxSerialization = "1.7.1" navigationFragmentKtx = "2.6.0" navigationUiKtx = "2.6.0" core-ktx = "1.13.0" gson = "2.10.1" room = "2.6.1" datastore-preferences = "1.1.1" serialization-protobuf = "1.6.0" work-manager = "2.10.0" zip4j = "2.11.5" apache-commons = "3.10.0" apache-commons-codec = "1.16.1" kotlinx-coroutines-core-jvm = "1.8.0" pickyou = "3.0.4" smbj = "0.14.0" smbj-rpc = "0.12.9" sshj = "0.38.0" guava-compat = "9999.0-empty-to-avoid-conflict-with-guava" sardine-next = "1.0.2" refine = "4.4.0" appcompat = "1.7.0" hilt-android = "2.49" hilt-android-compiler = "2.48" hilt-navigation-compose = "1.2.0" hilt-work = "1.2.0" hilt = "2.48" hilt-work-compiler = "1.2.0" mlkit-text = "16.0.1" mlkit-common-version = "18.11.0" activity = "1.9.1" savedstate = "1.2.1" espresso-core = "3.6.1" ktor-version = "2.0.3" quickie-bundled = "1.10.0" [plugins] agp-app = { id = "com.android.application", version.ref = "agp" } agp-lib = { id = "com.android.library", version.ref = "agp" } kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } lsplugin-apksign = { id = "org.lsposed.lsplugin.apksign", version.ref = "apksign" } lsplugin-cmaker = { id = "org.lsposed.lsplugin.cmaker", version.ref = "cmaker" } butterknife = { id = "com.jakewharton", version = "10.2.3" } com-google-protobuf = { id = "com.google.protobuf", version.ref = "protobuf-gradle-plugin" } hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } refine = { id = "dev.rikka.tools.refine", version.ref = "refine" } serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } application-common = { id = "application.common", version = "unspecified" } application-compose = { id = "application.compose", version = "unspecified" } application-hilt = { id = "application.hilt", version = "unspecified" } application-hilt-work = { id = "application.hilt.work", version = "unspecified" } library-common = { id = "library.common", version = "unspecified" } library-hilt = { id = "library.hilt", version = "unspecified" } library-hilt-work = { id = "library.hilt.work", version = "unspecified" } library-room = { id = "library.room", version = "unspecified" } library-compose = { id = "library.compose", version = "unspecified" } library-protobuf = { id = "library.protobuf", version = "unspecified" } library-test = { id = "library.test", version = "unspecified" } library-androidTest = { id = "library.androidTest", version = "unspecified" } library-firebase = { id = "library.firebase", version = "unspecified" } [libraries] androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" } androidx-foundation = { module = "androidx.compose.foundation:foundation" } androidx-material3 = { module = "androidx.compose.material3:material3" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } androidx-compose-material = { group = "androidx.compose.material", name = "material", version.ref = "compose-material" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "compose-material3" } androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "compose-ui" } androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "compose-ui" } androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose-foundation" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } androidx-ui = { module = "androidx.compose.ui:ui" } androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" } com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" } com-github-topjohnwu-libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" } com-github-topjohnwu-libsu-io = { group = "com.github.topjohnwu.libsu", name = "io", version.ref = "libsu" } dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version.ref = "parcelablelist" } io-coil-kt-coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil-compose" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version.ref = "appiconloader-coil" } compose-destinations-core = { group = "io.github.raamcosta.compose-destinations", name = "core", version.ref = "compose-destination" } compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destination" } sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs" } sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs" } sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "input", version.ref = "sheets-compose-dialogs" } markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" } lsposed-cxx = { module = "org.lsposed.libcxx:libcxx", version = "27.0.12077973" } androidx-documentfile = { group = "androidx.documentfile", name = "documentfile", version.ref = "documentfile" } androidx-lifecycle-service = { module = "androidx.lifecycle:lifecycle-service", version.ref = "androidxLifecycle" } androidx-core = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" } # Koin Inject # https://insert-koin.io/docs/setup/koin koin-core = { group = "io.insert-koin", name = "koin-core", version = "3.4.0" } koin-android = { group = "io.insert-koin", name = "koin-android", version = "3.4.0" } koin-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version = "3.4.4" } protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } protobuf-javalite = { group = "com.google.protobuf", name = "protobuf-javalite", version.ref = "protobuf" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } kotlinx-serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf", version.ref = "kotlinxSerialization" } square-okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "squareOkhttp" } square-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "squareOkhttp" } square-okhttp-dnsoverhttps = { group = "com.squareup.okhttp3", name = "okhttp-dnsoverhttps", version.ref = "squareOkhttp" } square-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "squareRetrofit" } square-retrofit-kotlinxSerialization = { group = "com.squareup.retrofit2", name = "converter-kotlinx-serialization", version.ref = "squareRetrofit" } retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "squareRetrofit" } smbj = { module = "com.hierynomus:smbj", version.ref = "smbj" } smbj-rpc = { module = "com.rapid7.client:dcerpc", version.ref = "smbj-rpc" } sshj = { module = "com.hierynomus:sshj", version.ref = "sshj" } guava-compat = { module = "com.google.guava:listenablefuture", version.ref = "guava-compat" } sardine-next = { module = "com.github.xayahsususu:sardine-next", version.ref = "sardine-next" } # rhino mozilla-rhino = "org.mozilla:rhino:1.8.0" mozilla-rhino-xml = "org.mozilla:rhino-xml:1.8.0" mozilla-rhino-tools = "org.mozilla:rhino-tools:1.8.0" #navigation androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" } androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" } lifecycle-compiler = { group = "androidx.lifecycle", name = "lifecycle-compiler", version.ref = "lifecycle"} gson = { module = "com.google.code.gson:gson", version.ref = "gson" } serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization-protobuf" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore-preferences" } # Dependencies of the included build-logic android-build-logic = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } kotlin-build-logic = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } ksp-build-logic = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } #firebase-crashlytics-build-logic = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebase-crashlytics-gradle" } pickyou = { module = "com.github.xayahsususu:libpickyou", version.ref = "pickyou" } zip4j = { module = "net.lingala.zip4j:zip4j", version.ref = "zip4j" } androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "work-manager" } apache-commons-net = { module = "commons-net:commons-net", version.ref = "apache-commons" } apache-commons-codec = { module = "commons-codec:commons-codec", version.ref = "apache-commons-codec" } kotlinx-coroutines-core-jvm = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", version.ref = "kotlinx-coroutines-core-jvm" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } refine-annotation = { module = "dev.rikka.tools.refine:annotation", version.ref = "refine" } refine-annotation-processor = { module = "dev.rikka.tools.refine:annotation-processor", version.ref = "refine" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt-android" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt-android-compiler" } hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "hilt-work" } hilt-work-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hilt-work-compiler" } androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" } androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" } okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "squareOkhttp" } # commons commons-exec = "org.apache.commons:commons-exec:1.3" commons-io = "commons-io:commons-io:2.6" timscriptov-apksigner = "com.github.TimScriptov:apksigner:1.2.0" core-ktx = { module = "androidx.core:core-ktx", version.ref = "core-ktx" } google-gson = { module = "com.google.code.gson:gson", version.ref = "gson" } # androidx compose compose-bom = "androidx.compose:compose-bom:2025.02.00" compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4" } compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } compose-material = { module = "androidx.compose.material:material" } compose-ui = { module = "androidx.compose.ui:ui" } # mlkit mlkit-common = { group = "com.google.mlkit", name = "common", version.ref = "mlkit-common-version" } mlkit-text-recognition = { module = "com.google.mlkit:text-recognition", version.ref = "mlkit-text" } mlkit-text-recognition-chinese = { module = "com.google.mlkit:text-recognition-chinese", version.ref = "mlkit-text" } mlkit-text-recognition-devanagari = { module = "com.google.mlkit:text-recognition-devanagari", version.ref = "mlkit-text" } mlkit-text-recognition-japanese = { module = "com.google.mlkit:text-recognition-japanese", version.ref = "mlkit-text" } mlkit-text-recognition-korean = { module = "com.google.mlkit:text-recognition-korean", version.ref = "mlkit-text" } androidx-viewpager2 = "androidx.viewpager2:viewpager2:1.1.0" androidx-work = "androidx.work:work-runtime:2.9.1" androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version = "2.2.0" } androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activity" } documentfile = "androidx.documentfile:documentfile:1.0.1" androidx-savedstate = { module = "androidx.savedstate:savedstate", version.ref = "savedstate" } androidx-savedstate-ktx = { module = "androidx.savedstate:savedstate-ktx", version.ref = "savedstate" } preference-ktx = "androidx.preference:preference-ktx:1.2.1" androidx-annotation = "androidx.annotation:annotation:1.9.1" activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity" } espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } # ktor ktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor-version" } ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor-version" } ktor-server-websockets = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor-version" } ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor-version" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor-version" } ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-version" } #shizuku shizuku-api = "dev.rikka.shizuku:api:13.1.5" shizuku-provider = "dev.rikka.shizuku:provider:13.1.5" kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } compose-material3 = "androidx.compose.material3:material3:1.3.1" compose-material3-window-size = "androidx.compose.material3:material3-window-size-class:1.3.1" compose-material3-adaptive-navigation-suite = "androidx.compose.material3:material3-adaptive-navigation-suite:1.3.1" #rxjava quickie-bundled = { module = "io.github.g00fy2.quickie:quickie-bundled", version.ref = "quickie-bundled" } rxjava2 = "io.reactivex.rxjava2:rxjava:2.2.21" rxjava2-rxandroid = "io.reactivex.rxjava2:rxandroid:2.1.1" rxjava3 = "io.reactivex.rxjava3:rxjava:3.1.5" rxjava3-rxandroid = "io.reactivex.rxjava3:rxandroid:3.0.2" javet-android-node = "com.caoccao.javet:javet-android-node:3.1.4" leakcanary-android = "com.squareup.leakcanary:leakcanary-android:2.13" leakcanary-objectinfo-watcher-android = "com.squareup.leakcanary:leakcanary-object-watcher-android:2.13" retrofit2-retrofit = "com.squareup.retrofit2:retrofit:2.11.0" retrofit2-converter-gson = "com.squareup.retrofit2:converter-gson:2.11.0" #Glide glide = "com.github.bumptech.glide:glide:4.8.0" glide-ksp = "com.github.bumptech.glide:ksp:4.14.2" glide-compiler = "com.github.bumptech.glide:compiler:4.12.0" #lifecycle lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" } lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" } lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "lifecycle" } lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" } lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycle" } lifecycle-viewmodel-savedstate = { module = "androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "lifecycle" } lifecycle-service = { module = "androidx.lifecycle:lifecycle-service", version.ref = "lifecycle" } androidx-swiperefreshlayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" ktsh = "com.jaredrummler:ktsh:1.0.0" coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil-compose" } [bundles] ktor = ["ktor-server-core", "ktor-server-netty", "ktor-server-websockets", "ktor-client-websockets", "ktor-client-okhttp", "ktor-client-core"] mlkit = [ "mlkit-text-recognition", "mlkit-text-recognition-chinese", "mlkit-text-recognition-devanagari", "mlkit-text-recognition-japanese", "mlkit-text-recognition-korean" ] shizuku = ["shizuku-api", "shizuku-provider"] 这个是一个Android Studio 的 libs.versions.toml 文件的代码,请帮我重构,去掉重复的代码,类似于ktsh = "com.jaredrummler:ktsh:1.0.0"这样的代码,修改为 module 或在 group 格式,并且在[versions]中定义版本号
08-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值