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

为什么要通过 mask 的位运算才能判断 flag

  •  1
     
  •   fhj · 2022-12-04 18:29:33 +08:00 · 4045 次点击
    这是一个创建于 480 天前的主题,其中的信息可能已经有所发展或是发生改变。

    public static final int VISIBLE = 0x00000000;

    public static final int INVISIBLE = 0x00000004;
    
    public static final int GONE = 0x00000008;
    
    static final int VISIBILITY_MASK = 0x0000000C;
    
    判断 flags 时是这么判断的:if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE)
    
    为什么不这样判断:if ((child.mViewFlags & VISIBLE) == VISIBLE)
    
    15 条回复    2022-12-05 11:53:11 +08:00
    yongfrank
        1
    yongfrank  
       2022-12-04 18:34:21 +08:00   ❤️ 1
    刚刚用 ChatGPT 出了一个答案

    在计算机程序中,通过 mask 的位运算来判断 flag 通常是为了将 flag 的多个属性(例如是否启用、是否可读、是否可写等)用一个整数来表示。

    在位运算中,通过与掩码( mask )进行与(&)运算可以判断 flag 的某一位是否被设置为 1 。例如,如果要判断 flag 的第 3 位是否被设置为 1 ,可以将 flag 与掩码 0b100 进行与运算,如果结果为 0 则表示 flag 的第 3 位被设置为 0 ,否则表示 flag 的第 3 位被设置为 1 。

    使用 mask 的位运算来判断 flag 的好处在于它可以节省存储空间,将多个属性用一个整数来表示,而不需要单独开辟多个变量来存储每个属性。例如,如果使用多个变量来表示 flag 的多个属性,则需要开辟多个 8 位的存储空间,而如果使用 mask 的位运算,则只需要开辟一个 8 位的存储空间就可以表示多个属性。
    hello2090
        2
    hello2090  
       2022-12-04 18:34:47 +08:00
    你这个 if ((child.mViewFlags & VISIBLE) == VISIBLE) 不是 永远 true 吗?
    fhj
        3
    fhj  
    OP
       2022-12-04 18:37:40 +08:00
    @hello2090 mViewFlags 没有设置不就是 false 了吗
    Cat7373
        4
    Cat7373  
       2022-12-04 18:39:19 +08:00
    @hello2090 #2 并不是的,MASK 说明了 0x0C 这一位表示是否可视,VISIBLE 的值说明了这一位是 0 时是可视,是 1 时是不可视,即 MASK 表示哪一位代表这个开关,VISIBLE 表示值是什么的时候代表什么结果
    fhj
        5
    fhj  
    OP
       2022-12-04 18:40:06 +08:00
    @yongfrank 谢谢,刚才看到一段这样的代码,这或许就是 mask 的作用把
    switch (mViewFlags&VISIBILITY_MASK) {
    case VISIBLE: out.append('V'); break;
    case INVISIBLE: out.append('I'); break;
    case GONE: out.append('G'); break;
    default: out.append('.'); break;
    }
    cxtrinityy
        6
    cxtrinityy  
       2022-12-04 18:40:40 +08:00
    VISIBILITY_MASK 是 0x0000000C -- 二进制是 1100
    invisible 是 0x00000004 -- 二进制是 0100
    gone 是 0x00000008 -- 二进制是 1000
    也就是 gone 和 invisible 是用不同位来表示, visible 要保证 gone 和 invisible 都未设置, 一次位运算就能验证两个设置
    Cat7373
        7
    Cat7373  
       2022-12-04 18:41:29 +08:00
    @Cat7373 #4 修正一下,0x0C 有两个 bit 位为 1 ,因此这两个 bit 位任意一个为 1 ,此判断结果都为不可视,均为 0 ,才为可视,具体代码设计中,这两个 bit 位各代表什么意思这里看不出,但设计上可以实现,有两个各代表某个意思的开关,任意一个打开,都代表不可视
    Cat7373
        8
    Cat7373  
       2022-12-04 18:42:03 +08:00
    @cxtrinityy #6 啊这,没注意到上面两个常量,丢人了丢人了
    viggoc
        9
    viggoc  
       2022-12-04 18:43:27 +08:00   ❤️ 1
    @fhj #3 任何数 & 0x00000000 不都是 0x00000000 吗
    fhj
        10
    fhj  
    OP
       2022-12-04 18:47:06 +08:00
    @viggoc 那应该是默认是 0,有其他需要再设置就好了
    DeweyReed
        11
    DeweyReed  
       2022-12-04 18:48:15 +08:00
    public static final int VISIBLE = 0x00000000;
    jeesk
        12
    jeesk  
       2022-12-04 21:58:02 +08:00
    最近自己优化内存用到的代码直接贴出来给你了。
    ```
    object BitStatesUtils {
    const val isFavorite = (1L shl 0).toByte()
    const val isDownload = (1L shl 1).toByte()
    const val isTrashed = (1L shl 2).toByte()

    public const val SIZE_BITS: Byte = 0

    /**
    * @param states 所有状态值
    * @param value 需要判断状态值
    * @return 是否存在
    */
    fun hasState(states: Byte, value: Byte): Boolean {
    val byte = (states and value) as Byte
    return byte != SIZE_BITS
    }

    fun Byte.HasState(value: Byte): Boolean {
    return BitStatesUtils.hasState(this, value)
    }

    /**
    * @param states 已有状态值
    * @param value 需要添加状态值
    * @return 新的状态值
    */
    fun addState(states: Byte, value: Byte): Byte {
    return if (hasState(states, value)) {
    states
    } else (states or value)
    }

    fun Byte.AddState(value: Byte): Byte {
    return addState(this, value)
    }

    /**
    * @param states 已有状态值
    * @param value 需要删除状态值
    * @return 新的状态值
    */
    fun removeState(states: Byte, value: Byte): Byte {
    return if (!hasState(states, value)) {
    states
    } else (states xor value)
    }


    }
    ```
    FranzKafka95
        13
    FranzKafka95  
       2022-12-04 23:04:47 +08:00 via Android
    嵌入式里很常见的操作,尤其是当你需要用一个 bit 表示一个状态,同时又想节省空间时,位操作就非常有必要了。
    Building
        14
    Building  
       2022-12-04 23:11:22 +08:00 via iPhone
    Mask 和 Optional Value 就像锁和钥匙,你可以把运算过程想像成把钥匙插入锁里面,全部凹槽都配平才能打开
    lysS
        15
    lysS  
       2022-12-05 11:53:11 +08:00
    用位表示 flag ,是为了正交隔离
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2998 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 14:57 · PVG 22:57 · LAX 07:57 · JFK 10:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.