WeakHashMap 和 HashMap 的区别是什么,何时使用?

news2024/11/17 20:44:48

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。

前言

大家好,我是小彭。

在之前的文章里,我们聊到了 Java 标准库中 HashMap 与 LinkedHashMap 的实现原理。HashMap 是一个标准的散列表数据结构,而 LinkedHashMap 是在 HashMap 的基础上实现的哈希链表。

今天,我们来讨论 WeakHashMap,其中的 “Weak” 是指什么,与前两者的使用场景有何不同?我们就围绕这些问题展开。

提示: 本文源码基于 JDK 1.2 WeakHashMap。


小彭的 Android 交流群 02 群已经建立啦,扫描文末二维码进入~


思维导图:


1. 回顾 HashMap 和 LinkedHashMap

其实,WeakHashMap 与 HashMap 和 LinkedHashMap 的数据结构大同小异,所以我们先回顾后者的实现原理。

1.1 说一下 HashMap 的实现结构

HashMap 是基于分离链表法解决散列冲突的动态散列表。

  • 1、HashMap 在 Java 7 中使用的是 “数组 + 链表”,发生散列冲突的键值对会用头插法添加到单链表中;
  • 2、HashMap 在 Java 8 中使用的是 “数组 + 链表 + 红黑树”,发生散列冲突的键值对会用尾插法添加到单链表中。如果链表的长度大于 8 时且散列表容量大于 64,会将链表树化为红黑树。

HashMap 实现示意图

1.2 说一下 LinkedHashMap 的实现结构

LinkedHashMap 是继承于 HashMap 实现的哈希链表。

  • 1、LinkedHashMap 同时具备双向链表和散列表的特点。当 LinkedHashMap 作为散列表时,主要体现出 O(1) 时间复杂度的查询效率。当 LinkedHashMap 作为双向链表时,主要体现出有序的特性;
  • 2、LinkedHashMap 支持 FIFO 和 LRU 两种排序模式,默认是 FIFO 排序模式,即按照插入顺序排序。Android 中的 LruCache 内存缓存和 DiskLruCache 磁盘缓存也是直接复用 LinkedHashMap 提供的缓存管理能力。

LinkedHashMap 示意图


2. 认识 WeakHashMap

2.1 WeakReference 弱引用的特点

WeakHashMap 中的 “Weak” 指键 Key 是弱引用,也叫弱键。弱引用是 Java 四大引用类型之一,一共有四种引用类型,分别是强引用、软引用、弱引用和虚引用。我将它们的区别概括为 3 个维度:

  • 维度 1 - 对象可达性状态的区别: 强引用指向的对象是强可达的,只有强可达的对象才会认为是存活的对象,才能保证在垃圾收集的过程中不会被回收;
  • 维度 2 - 垃圾回收策略的区别: 不同的引用类型的回收激进程度不同,
    • 强引用指向的对象不会被回收;
    • 软引用指向的对象在内存充足时不会被回收,在内存不足时会被回收;
    • 弱引用和虚引用指向的对象无论在内存是否充足的时候都会被回收;
  • 维度 3 - 感知垃圾回收时机: 当引用对象关联的实际对象被垃圾回收时,引用对象会进入关联的引用队列,程序可以通过观察引用队列的方式,感知对象被垃圾回收的时机。

感知垃圾回收示意图

提示: 关于 “Java 四种引用类型” 的区别,在小彭的 Java 专栏中深入讨论过 《说一下 Java 的四种引用类型》,去看看。

2.2 WeakHashMap 的特点

WeakHashMap 是使用弱键的动态散列表,用于实现 “自动清理” 的内存缓存。

  • 1、WeakHashMap 使用与 Java 7 HashMap 相同的 “数组 + 链表” 解决散列冲突,发生散列冲突的键值对会用头插法添加到单链表中;

  • 2、WeakHashMap 依赖于 Java 垃圾收集器自动清理不可达对象的特性。当 Key 对象不再被持有强引用时,垃圾收集器会按照弱引用策略自动回收 Key 对象,并在下次访问 WeakHashMap 时清理全部无效的键值对。因此,WeakHashMap 特别适合实现 “自动清理” 的内存活动缓存,当键值对有效时保留,在键值对无效时自动被垃圾收集器清理;

  • 3、需要注意,因为 WeakHashMap 会持有 Value 对象的强引用,所以在 Value 对象中一定不能持有 key 的强引用。否则,会阻止垃圾收集器回收 “本该不可达” 的 Key 对象,使得 WeakHashMap 失去作用。

  • 4、与 HashMap 相同,LinkedHashMap 也不考虑线程同步,也会存在线程安全问题。可以使用 Collections.synchronizedMap 包装类,其原理也是在所有方法上增加 synchronized 关键字。

WeakHashMap 示意图

自动清理数据

2.3 说一下 WeakHashMap 与 HashMap 和 LinkedHashMap 的区别?

WeakHashMap 与 HashMap 都是基于分离链表法解决散列冲突的动态散列表,两者的主要区别在 键 Key 的引用类型上:

  • HashMap 会持有键 Key 的强引用,除非手动移除,否则键值对会长期存在于散列表中;

  • WeakHashMap 只持有键 Key 的弱引用,当 Key 对象不再被外部持有强引用时,键值对会被自动被清理。

WeakHashMap 与 LinkedHashMap 都有自动清理的能力,两者的主要区别在于 淘汰数据的策略上:

  • LinkedHashMap 会按照 FIFO 或 LRU 的策略 “尝试” 淘汰数据,需要开发者重写 removeEldestEntry() 方法实现是否删除最早节点的判断逻辑;

  • WeakHashMap 会按照 Key 对象的可达性淘汰数据,当 Key 对象不再被持有强引用时,会自动清理无效数据。

2.4 重建 Key 对象不等价的问题

WeakHashMap 的 Key 使用弱引用,也就是以 Key 作为清理数据的判断锚点,当 Key 变得不可达时会自动清理数据。此时,如果使用多个 equals 相等的 Key 对象访问键值对,就会出现第 1 个 Key 对象不可达导致键值对被回收,而第 2 个 Key 查询键值对为 null 的问题。 这说明 equals 相等的 Key 对象在 HashMap 等散列表中是等价的,但是在 WeakHashMap 散列表中是不等价的。

因此,如果 Key 类型没有重写 equals 方法,那么 WeakHashMap 就表现良好,否则会存在歧义。例如下面这个 Demo 中,首先创建了指向 image_url1 的图片 Key1,再重建了同样指向 image_url1 的图片 Key2。在 HashMap 中,Key1 和 Key2 等价,但在 WeakHashMap 中,Key1 和 Key2 不等价。

Demo

class ImageKey {
    private String url;

    ImageKey(String url) {
        this.url = url;
    }

    public boolean equals(Object obj) {
        return (obj instanceOf ImageKey) && Objects.equals(((ImageKey)obj).url, this.url);
    }
}

WeakHashMap<ImageKey, Bitmap> map = new WeakHashMap<>();
ImageKey key1 = new ImageKey("image_url1");
ImageKey key2 = new ImageKey("image_url2");
// key1 equalsTo key3
ImageKey key3 = new ImageKey("image_url1");

map.put(key1, bitmap1);
map.put(key2, bitmap2);

System.out.println(map.get(key1)); // 输出 bitmap1
System.out.println(map.get(key2)); // 输出 bitmap2
System.out.println(map.get(key3)); // 输出 bitmap1

// 使 key1 不可达,key3 保持
key1 = null;

// 说明重建 Key 与原始 Key 不等价
System.out.println(map.get(key1)); // 输出 null
System.out.println(map.get(key2)); // 输出 bitmap2
System.out.println(map.get(key3)); // 输出 null

默认的 Object#equals 是判断两个变量是否指向同一个对象:

Object.java

public boolean equals(Object obj) {
    return (this == obj);
}

2.5 Key 弱引用和 Value 弱引用的区别

不管是 Key 还是 Value 使用弱引用都可以实现自动清理,至于使用哪一种方法各有优缺点,适用场景也不同。

  • Key 弱引用: 以 Key 作为清理数据的判断锚点,当 Key 不可达时清理数据。优点是容器外不需要持有 Value 的强引用,缺点是重建的 Key 与原始 Key 不等价,重建 Key 无法阻止数据被清理;

  • Value 弱引用: 以 Value 作为清理数据的判断锚点,当 Value 不可达时清理数据。优点是重建 Key 与与原始 Key 等价,缺点是容器外需要持有 Value 的强引用。

类型优点缺点场景
Key 弱引用外部不需要持有 Value 的强引用,使用更简单重建 Key 不等价未重写 equals
Value 弱引用重建 Key 等价外部需要持有 Value 的强引用重写 equals

举例 1: 在 Android Glide 图片框架的多级缓存中,因为图片的 EngineKey 是可重建的,存在多个 EngineKey 对象指向同一个图片 Bitmap,所以 Glide 最顶层的活动缓存采用的是 Value 弱引用。

EngineKey.java

class EngineKey implements Key {

    // 重写 equals
    @Override
    public boolean equals(Object o) {
        if (o instanceof EngineKey) {
            EngineKey other = (EngineKey) o;
            return model.equals(other.model)
                && signature.equals(other.signature)
                && height == other.height
                && width == other.width
                && transformations.equals(other.transformations)
                && resourceClass.equals(other.resourceClass)
                && transcodeClass.equals(other.transcodeClass)
                && options.equals(other.options);
        }
        return false;
    }
}

举例 2: 在 ThreadLocal 的 ThreadLocalMap 线程本地存储中,因为 ThreadLocal 没有重写 equals,不存在多个 ThreadLocal 对象指向同一个键值对的情况,所以 ThreadLocal 采用的是 Key 弱引用。

ThreadLocal.java

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
    
    // 未重写 equals
}

3. WeakHashMap 源码分析

这一节,我们来分析 WeakHashMap 中主要流程的源码。

事实上,WeakHashMap 就是照着 Java 7 版本的 HashMap 依葫芦画瓢的,没有树化的逻辑。考虑到我们已经对 HashMap 做过详细分析,所以我们没有必要重复分析 WeakHashMap 的每个细节,而是把重心放在 WeakHashMap 与 HashMap 不同的地方。

3.1 WeakHashMap 的属性

先用一个表格整理 WeakHashMap 的属性:

版本数据结构节点实现类属性
Java 7 HashMap数组 + 链表Entry(单链表)1、table(数组)
2、size(尺寸)
3、threshold(扩容阈值)
4、loadFactor(装载因子上限)
5、modCount(修改计数)
6、默认数组容量 16
7、最大数组容量 2^30
8、默认负载因子 0.75
WeakHashMap数组 + 链表Entry(单链表,弱引用的子类型)9、queue(引用队列)

WeakHashMap.java

public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {

    // 默认数组容量
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    // 数组最大容量:2^30(高位 0100,低位都是 0)
    private static final int MAXIMUM_CAPACITY = 1 << 30;

    // 默认装载因子上限:0.75
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    // 底层数组
    Entry<K,V>[] table;

    // 键值对数量
    private int size;

    // 扩容阈值(容量 * 装载因子)
    private int threshold;

    // 装载因子上限
    private final float loadFactor;

    // 引用队列
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

    // 修改计数
    int modCount;

    // 链表节点(一个 Entry 等于一个键值对)
    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        // Key:与 HashMap 和 LinkedHashMap 相比,少了 key 的强引用
        // final K key;
        // Value(强引用)
        V value;
        // 哈希值
        final int hash;
        Entry<K,V> next;

        Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next) {
            super(key /*注意:只有 Key 是弱引用*/, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }
    }
}

WeakHashMap 与 HashMap 的属性几乎相同,主要区别有 2 个:

  • 1、ReferenceQueue: WeakHashMap 的属性里多了一个 queue 引用队列;

  • 2、Entry: WeakHashMap#Entry 节点继承于 WeakReference,表面看是 WeakHashMap 持有了 Entry 的强引用,其实不是。注意看 Entry 的构造方法,WeakReference 关联的实际对象是 Key。 所以,WeakHashMap 依然持有 Entry 和 Value 的强引用,仅持有 Key 的弱引用。

引用关系示意图

不出意外的话又有小朋友出来举手提问了🙋🏻‍♀️

  • 🙋🏻‍♀️疑问 1:说一下 ReferenceQueue queue 的作用?

ReferenceQueue 与 Reference 配合能够实现感知对象被垃圾回收的能力。在创建引用对象时可以关联一个实际对象和一个引用队列,当实现对象被垃圾回收后,引用对象会被添加到这个引用队列中。在 WeakHashMap 中,就是根据这个引用队列来自动清理无效键值对。

  • 🙋🏻‍♀️疑问 2:为什么 Key 是弱引用,而不是 Entry 或 Value 是弱引用?

首先,Entry 一定要持有强引用,而不能持有弱引用。这是因为 Entry 是 WeakHashMap 内部维护数据结构的实现细节,并不会暴露到 WeakHashMap 外部,即除了 WeakHashMap 本身之外没有其它地方持有 Entry 的强引用。所以,如果持有 Entry 的弱引用,即使 WeakHashMap 外部依然在使用 Key 对象,WeakHashMap 内部依然会回收键值对,这与预期不符。

其次,不管是 Key 还是 Value 使用弱引用都可以实现自动清理。至于使用哪一种方法各有优缺点,适用场景也不同,这个在前文分析过了。

3.2 WeakHashMap 如何清理无效数据?

在通过 put / get /size 等方法访问 WeakHashMap 时,其内部会调用 expungeStaleEntries() 方法清理 Key 对象已经被回收的无效键值对。其中会遍历 ReferenceQueue 中持有的弱引用对象(即 Entry 节点),并将该结点从散列表中移除。

private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

// 添加键值对
public V put(K key, V value) {
    ...
    // 间接 expungeStaleEntries()
    Entry<K,V>[] tab = getTable();
    ...
}

// 扩容
void resize(int newCapacity) {
    // 间接 expungeStaleEntries()
    Entry<K,V>[] oldTable = getTable();
    ...
}

// 获取键值对
public V get(Object key) {
    ...
    // 间接 expungeStaleEntries()
    Entry<K,V>[] tab = getTable();
    ...
}

private Entry<K,V>[] getTable() {
    // 清理无效键值对
    expungeStaleEntries();
    return table;
}

// ->清理无效键值对
private void expungeStaleEntries() {
    // 遍历引用队列
    for (Object x; (x = queue.poll()) != null; ) {
        // 疑问 3:既然 WeakHashMap 不考虑线程同步,为什么这里要做加锁,岂不是突兀?
        synchronized (queue) {
            Entry<K,V> e = (Entry<K,V>) x;
            // 根据散列值定位数组下标
            int i = indexFor(e.hash /*散列值*/, table.length);
            // 遍历桶寻找节点 e 的前驱结点
            Entry<K,V> prev = table[i];
            Entry<K,V> p = prev;
            while (p != null) {
                Entry<K,V> next = p.next;
                if (p == e) {
                    // 删除节点 e
                    if (prev == e)					
                        // 节点 e 是根节点
                        table[i] = next;
                    else
                        // 节点 e 是中间节点
                        prev.next = next;
                    // Must not null out e.next;
                    // stale entries may be in use by a HashIterator
                    e.value = null; // Help GC
                    size--;
                    break;
                }
                prev = p;
                p = next;
            }
        }
    }
}

4. 总结

  • 1、WeakHashMap 使用与 Java 7 HashMap 相同的 “数组 + 链表” 解决散列冲突,发生散列冲突的键值对会用头插法添加到单链表中;

  • 2、WeakHashMap 能够实现 “自动清理” 的内存缓存,其中的 “Weak” 指键 Key 是弱引用。当 Key 对象不再被持有强引用时,垃圾收集器会按照弱引用策略自动回收 Key 对象,并在下次访问 WeakHashMap 时清理全部无效的键值对;

  • 3、WeakHashMap 和 LinkedHashMap 都具备 “自动清理” 的 能力,WeakHashMap 根据 Key 对象的可达性淘汰数据,而 LinkedHashMap 根据 FIFO 或 LRU 策略尝试淘汰数据;

  • 4、WeakHashMap 使用 Key 弱引用,会存在重建 Key 对象不等价问题。


小彭的 Android 交流群 02 群

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55234.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

eval()方法字符串转对象; 分别取对象属性名和属性的方法

字符串转对象 ⬇️ A是字符串 转对象&#xff1a; let B eval(‘ (‘ A ‘) ‘) B就是A转成的对象 取对象属性名(for ... in ... ) ⬇️ let C []; for(let key in B) { C.push(key); console.log(key); // 打印所有属性名 console.log(B[key]); // 打印所有属性值…

“元宇宙”虚拟世界的营销法则 “品牌元宇宙空间”算什么?

虚拟世界从来不缺吃螃蟹的品牌。 “元宇宙”依旧是当下品牌创新营销的重要形式&#xff0c;从时趣的行业观察来看&#xff0c;大量品牌方都有着元宇宙的营销意向&#xff0c;但在营销落地上存在不同的进度。一个显而易见的事实是&#xff0c;元宇宙不仅仅是一个虚拟的游戏空间…

RabbitMQ之负载均衡-HAProxy

将客户端的连接和操作的压力分散到集群中的不同节点&#xff0c;防止单个或几台服务器压力过大成为访问的瓶颈&#xff0c;甚至宕机。HAProxy是一款开源免费&#xff0c;并提供高可用性、负载均衡以及基于TCP和HTTP协议的代理软件&#xff0c;可以支持四层、七层负载均衡&#…

虚拟列表渲染-前端性能优化

目录 1 使用场景 2 小插曲 3 虚拟列表渲染实现原理 4 代码实现 1 使用场景 在做EMBP项目时&#xff0c;有个模板新建的需求&#xff0c;需要点击获取子任务时获取所有的子任务&#xff0c;当时有的数据比较大&#xff0c;会有几百条的情况&#xff0c;此时接口请求变得很慢…

高可用网站架构云化

高可用网站架构云化 一、背景 早期互联网产品用户量少&#xff0c;并发量低&#xff0c;数据量小&#xff0c;多数只需要单个应用服务器可以满足需要&#xff0c;而数据库和文件服务部署在外部单个服务器上。随着业务在线化、互联网化的高速发展&#xff0c;企业对核心业务系统…

微信云开发AI短视频一键换脸小程序源码

简介&#xff1a; 微信云开发AI一键视频换脸小程序源码是由极客二改后发布的&#xff0c;小程序增加了广告控制&#xff0c; 插屏广告&#xff0c;激励广告和原生广告&#xff0c;由于采用了微信云开发没有后台&#xff0c; 所以不需要域名和服务器也可以正常搭建使用&#xf…

【论文精读6】MVSNet系列论文详解-CIDER

CIDER全名&#xff1a;Learning Inverse Depth Regression for Multi-View Stereo with Correlation Cost Volume,AAAI 2020(CCF A) 本文是MVSNet系列的第6篇&#xff0c;建议看过【论文精读1】MVSNet系列论文详解-MVSNet之后再看便于理解。 一、问题引入 针对问题&#xff1a…

理解 CNN

理解 CNN 注意&#xff1a;下面提到的图像指位图 目录理解 CNNCNN人类的视觉原理几个关键层卷积层(fliter、kernel)池化层 (pooling)激活层(activate)全连接层(Linear)pytorch实现TextCNN卷积传播图解不同视角看CNN参考CNN 卷积神经网络-CNN 最擅长的就是图片的处理。它受到人…

[附源码]JAVA毕业设计机房预约系统(系统+LW)

[附源码]JAVA毕业设计机房预约系统&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&…

Spring Data JPA 中的分页和排序

让我们学习如何使用 在 Spring 数据 JPA 中使用分页和排序有效地处理大量记录。 什么是分页和排序&#xff1f; 大多数情况下&#xff0c;来自数据库的结果集可能会让人不知所措。它可能会让人不知所措&#xff0c;以至于系统崩溃&#xff0c;因为它们无法在一次传递中处理那…

2019-10《信息资源管理 02378》真卷(独家文字版),圈定章节考点+统计真题分布

本系列博客合计 21 篇&#xff0c;每篇都将解析一张《信息资源管理》真卷&#xff0c;并附带答案解析与背诵技巧。 搜索 梦想橡皮擦&#xff0c;擦姐整理 全国 2019 年 10 月自学考试信息资源管理试题&#xff08;02378&#xff09; 单选题 1,信息技术是应用信息科学的原理和…

Linux基本工具——yum

Linux基本工具软件包管理器yum什么是软件包Linux的软件包yum的三板斧yum的扩展软件包管理器yum 工具的本质就是指令 什么是软件包 我们平时用手机与电脑的时候&#xff0c;如果想安装一个软件就需要去下载它的安装包&#xff08;软件包&#xff09;&#xff0c;下载安装包的…

前端怎么才能找到项目做?

前言 一般找项目最常用的就是在Github上&#xff0c;题主已经具备了html、css、js和vue的知识体系&#xff0c;那么在github或者找一些项目教程视频来实践是锻炼的最好途径&#xff0c;下面我整理了一些在github和B站上找了一些前端的经典项目&#xff0c;希望对你有所帮助~ …

Kotlin 开发Android app(十六):ContentProvider的使用

android的四大组件&#xff0c;已经介绍了两个&#xff0c;这一节介绍ContentProvider。前面的广播可以进行 app内的通讯&#xff0c;如果需要进行app之间的通讯&#xff0c;在android 中使用的是ContentProvider。ContentProvider 也分为三种&#xff0c;一&#xff0c;作为数…

物通博联持续参与京东方(BOE)工厂数字化项目

创新引领 数字驱动 京东方科技集团股份有限公司&#xff08;BOE&#xff09;创立于1993年&#xff0c;是全球领先的半导体显示技术、产品与服务提供商&#xff0c;核心业务包括显示器件、智慧系统和健康服务。产品广泛应用于手机、平板电脑、笔记本电脑、显示器、电视、车载、…

php万年历源代码!源代码![上一年、上一月、下一月、下一年、附加当天日期加背景颜色]-私聊源码

//当前年 $year isset($_GET[year])?$_GET[year]:date(Y); //echo $year; //制作当前月的变量 $monthisset($_GET[month])?$_GET[month]:date(n); //本月有多少天 $day date(t,mktime(0,0,0,$month,1,$year)); //本月从1号开始是星期几 $w date(w,mktime(0,0,0,$month,1…

python处理csv文件

如何使用python处理csv文件 素材准备 ​ csv⽂件其实就是⽂本⽂件&#xff0c;遵循了⼀定的格式&#xff0c;常⻅的csv⽂件⼀般是⽤逗号来隔开列&#xff0c;⽤换⾏符隔开不同的⾏&#xff0c;注意这⾥的符号都是英⽂符号。我们可以直接⽤open函数来打开csv⽂件&#xff1b; …

.net----数据库的访问ADO.NET、DataAdapter和DataSet

数据库的访问前言ADO.NET的概述ADO.NET数据源访问处理数据类库的两个组件&#xff1a;引用System.Data.dll和System.Xml.dll使用ADO.NET连接和操作数据库使用数据提供程序访问数据库操作的典型步骤&#xff1a;&#xff08;1&#xff09;建立数据库连接&#xff08;2&#xff0…

艾美捷曲妥珠单抗Trastuzumab参数和相关研究

曲妥珠单抗是一种重组人源化单克隆抗体&#xff0c;特异性地作用于人表皮生长因子受体-2(HER2)的细胞外部位。此抗体含人IgG1 框架&#xff0c;互补决定区源自鼠抗p185 HER2 抗体&#xff0c;能够与HER2 绑定。 HER2 原癌基因或C-erbB2 编码一个单一的受体样跨膜蛋白&#xff0…

Tyramide Cy5.5,Cyanine5.5 Tyramide,花青素Cy5.5酪酰胺远红色近红外发射染料

​一、理论分析&#xff1a; 中文名&#xff1a;花青素Cy5.5 酪酰胺 英文名&#xff1a;Cyanine5.5 Tyramide&#xff0c;Cy5.5 Tyramide&#xff0c;Tyramide Cy5.5 CAS号&#xff1a;N/A 化学式&#xff1a;C48H52CIN3O2 分子量&#xff1a;738.4 二、产品详情&#xff1a; 外…