V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chur
V2EX  ›  Java

初学 Java ,请教大神们一个问题

  •  
  •   chur · 2022-02-11 14:58:14 +08:00 · 3629 次点击
    这是一个创建于 1045 天前的主题,其中的信息可能已经有所发展或是发生改变。

    rt.最近在看编码方面的文章,了解到 utf32 是定长编码,String.charAt 方法对此编码有更好的支持,于是写了段代码试了一下:

    
        long start = System.nanoTime();
        for (int i = 0; i < utf8.length(); i++) {
        	char c = utf8.charAt(i);
        }
        long end = System.nanoTime();
        System.out.println(end - start);
    
        start = System.nanoTime();
        for (int i = 0; i < utf32.length(); i++) {
        	char c = utf32.charAt(i);
        }
        end = System.nanoTime();
        System.out.println(end - start);
        System.out.println("==========");
    
    

    将这段代码放入 for 循环中输出如下

    5435600
    3786200
    ==========
    5370700
    200
    ==========
    ....
    

    手动复制代码片段执行输出如下:

    7608200
    5690900
    ==========
    5709800
    4930700
    ==========
    ...
    

    放入 for 循环中执行的代码,从第二次循环开始 utf32 耗时在 0-500 纳秒浮动 是代码哪里写的有问题吗? utf8 和 utf32 两个 String 对象是同一段一亿个字符的文本

    24 条回复    2022-02-14 13:41:52 +08:00
    Kasumi20
        1
    Kasumi20  
       2022-02-11 15:28:47 +08:00   ❤️ 1
    你的 utf8 和 utf32 怎么来的?这样 new 出来的吗?

    String(byte[] bytes, Charset charset)
    Constructs a new String by decoding the specified array of bytes using the specified charset.

    Java 中的对象使用无法修改的 UTF-16 编码,不可能有 UTF-8 和 UTF-32 编码的 Java 字符串。
    txwd
        2
    txwd  
       2022-02-11 16:10:00 +08:00
    借楼问,为什么 Java 的工程目录要那么多层级...\src\main\java\com\...
    KomiSans
        3
    KomiSans  
       2022-02-11 16:11:46 +08:00
    [![HadMz8.png]( https://s4.ax1x.com/2022/02/11/HadMz8.png)]( https://imgtu.com/i/HadMz8)
    像是这样的么? 好像对于比较大的文本 UTF32 耗时比较短相对于 UTF8
    q474818917
        4
    q474818917  
       2022-02-11 16:27:01 +08:00   ❤️ 1
    还学 java ?这都卷成什么样了
    chur
        5
    chur  
    OP
       2022-02-11 16:36:27 +08:00
    @Kasumi20 貌似是可以的?对同一个字符的 byte 数组使用 new String 指定 utf-8 或 utf-32 字符集重新编码会得到不同的结果
    chur
        6
    chur  
    OP
       2022-02-11 16:37:59 +08:00
    @KomiSans 对,现在疑惑的点在于 这段代码放到 for 循环中 输出的结果很离谱= =
    chur
        7
    chur  
    OP
       2022-02-11 16:48:04 +08:00   ❤️ 1
    @txwd src/main/java 貌似是 maven 编译项目时默认的路径,可以修改; com 和后面的就是自定义的了
    VeryZero
        8
    VeryZero  
       2022-02-11 16:49:15 +08:00
    感觉是被优化了,把各种优化关了试试
    xiangyuecn
        9
    xiangyuecn  
       2022-02-11 16:50:12 +08:00   ❤️ 2
    @txwd #2 java 没有要求你这样搞,但开发环境要求你这样搞😂 其实你源码随便放哪里都行,只要编译时找得到😂
    xiangyuecn
        10
    xiangyuecn  
       2022-02-11 16:53:21 +08:00
    欢迎观摩我手撸的 java 仓库,https://github.com/xiangyuecn/RSA-java 源码文件全丢在根目录,但包名还是那个包名🐶
    gadfly3173
        11
    gadfly3173  
       2022-02-11 17:03:34 +08:00   ❤️ 1
    @txwd #2 这玩意算是工程实践,src 下 main 放项目源码,test 放单元测试; main 下 java 放包名路径,resource 下放要打包进去的资源。你乐意的话把打包配置改了也能放别的地方
    Jooooooooo
        12
    Jooooooooo  
       2022-02-11 17:17:13 +08:00
    搜 jit
    Kasumi20
        13
    Kasumi20  
       2022-02-11 17:25:18 +08:00
    charset 不是指定 String 的编码,而是指定 bytes 的解码方法,你用 UTF-32 去解码,得到的乱码字符数量很可能只是 UTF-8 的四分之一
    Kasumi20
        14
    Kasumi20  
       2022-02-11 17:32:05 +08:00
    如果你这堆文本都是 UTF-8 编码的汉字的话,UTF-8 和 UTF-32 去解码得到的 UTF-16 代码点的比值应该是 3 : 4 ,即 0.75

    > 4930700/5709800
    0.8635503870538372

    > 5690900/7608200
    0.7479955837123105

    似乎是成立的
    thedrwu
        15
    thedrwu  
       2022-02-11 17:35:10 +08:00 via Android   ❤️ 2
    @txwd
    可能因为 Java 语言的设计初衷就不是用来写单文件的迷你 script 的。于是人们在 applet 之外发明了 javascript 。
    讽刺的是 javascript 屠了 applet 的龙。
    pxiphx891
        16
    pxiphx891  
       2022-02-11 18:10:03 +08:00
    @chur @KomiSans 你们 getBytes()的时候,得到的是默认编码的 bytes ,一般是 utf8 ,utf8 的 bytes 转换到 utf32 ,length 会变短
    pxiphx891
        17
    pxiphx891  
       2022-02-11 18:11:50 +08:00
    可以试试这段代码:
    ```java
    import java.nio.charset.StandardCharsets;

    public class Utf{
    public static void main(String[] args) throws Exception {
    for (int j = 0; j < 30; j++) {
    String b = "《新能源汽车推广应用推荐车型目录》( 2021 年第 4 批)车型主要参数";
    String utf8 = new String(b.getBytes(),StandardCharsets.UTF_8);
    String utf32 = new String(b.getBytes(), "UTF_32");
    long start = System.nanoTime();
    for (int i = 0; i < utf8.length(); i++) {
    char c = utf8.charAt(i);
    System.out.printf("%s",c);
    }
    System.out.printf("%n");
    long end = System.nanoTime();
    System.out.println(end - start);

    start = System.nanoTime();
    for (int i = 0; i < utf32.length(); i++) {
    char c = utf32.charAt(i);
    System.out.printf("%s",c);
    }
    System.out.printf("%n");
    end = System.nanoTime();
    System.out.println(end - start);
    System.out.println("==========");
    }
    }
    }
    ```
    结果是这样的:
    ```
    《新能源汽车推广应用推荐车型目录》( 2021 年第 4 批)车型主要参数
    358397
    �����������������������
    255780
    ==========
    《新能源汽车推广应用推荐车型目录》( 2021 年第 4 批)车型主要参数
    415140
    �����������������������
    226139
    ==========
    ```
    maokabc
        18
    maokabc  
       2022-02-11 21:24:06 +08:00 via Android
    你测试 utf8 不用 byte 数组,utf32 不用 int 数组,用 String 干什么? String 固定的 utf16 没其他编码。
    ohwind
        19
    ohwind  
       2022-02-11 21:41:12 +08:00
    @txwd ../src/main/java 这是一般项目层级,可以修改的。
    到了 "com" 就是 java 的 package 层级。假如有一个类的路径是这样的: /src/main/java/com/xxx/Util.java
    那么 "/src/main/java" 就是项目路径, 它的类名是 "Util" ,包名就是 "com.xxx"。而 "com.xxx.Util" 称为这个类的全限定类名
    KomiSans
        20
    KomiSans  
       2022-02-11 22:12:46 +08:00
    @pxiphx891 这... 有什么太大差别么
    bequt
        21
    bequt  
       2022-02-11 22:41:21 +08:00
    已经开始学,rust 了
    EscYezi
        22
    EscYezi  
       2022-02-13 04:26:09 +08:00 via iPhone
    @txwd #2 src/main/java 是 maven 项目约定的源码位置,后面的 com/…是因为 java 包名通常是域名倒序,如 api.baidu.com 变成 com/baidu/api
    Bingchunmoli
        23
    Bingchunmoli  
       2022-02-13 12:34:12 +08:00
    @txwd 你看一看现在前端也是 src public 什么的,都是规范的事情,你可以用,但是约定大于配置,都用规范,易懂,好用
    chur
        24
    chur  
    OP
       2022-02-14 13:41:52 +08:00
    @maokabc 没太明白你的意思。String 如果没有显示指定字符集,默认是按系统默认字符集来的? java 内部存储字符使用的是 utf-16 编码,实际调用 getBytes 等方法时会有一个转码的过程
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   887 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:39 · PVG 04:39 · LAX 12:39 · JFK 15:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.