Java Findbugs通过参数或克隆()分配字节数组值

Java Findbugs通过参数或克隆()分配字节数组值,java,arrays,bytearray,findbugs,Java,Arrays,Bytearray,Findbugs,例如,我有一个构造函数 public Example(byte[] bytes) { this.bytes = bytes; } 在运行Funbug之后,它会说我应该考虑克隆它而不是…所以我试了一下,它消除了警告 public Example(byte[] bytes) { this.bytes = bytes.clone(); } 然而,我想知道这种改变是否有任何影响或负面的副作用。据我所知,它也适用于所有数组,而不仅仅是字节[] 感谢我们的想法是获取一个防御副本,这样以后

例如,我有一个构造函数

public Example(byte[] bytes) {
    this.bytes = bytes;
}
在运行Funbug之后,它会说我应该考虑克隆它而不是…所以我试了一下,它消除了警告

public Example(byte[] bytes) {
    this.bytes = bytes.clone();
}
然而,我想知道这种改变是否有任何影响或负面的副作用。据我所知,它也适用于所有数组,而不仅仅是字节[]


感谢

我们的想法是获取一个防御副本,这样以后对数组的更新就不会写入示例对象。它也有助于垃圾收集,因为您没有保留对数组的引用


就含义而言,您可能会使用更多内存,因为最终可能会将数组存储两次。

我们的想法是获取一个防御性副本,以便对数组的后续更新不会写入示例对象。它也有助于垃圾收集,因为您没有保留对数组的引用


就含义而言,您可能会使用更多内存,因为最终可能会将数组存储两次。

这是一种非常普遍的情况—当您创建一个依赖于某个外部数组或列表的对象时—该对象是否应该简单地重复使用现有引用;或者你需要创建输入数据的副本吗

重复使用意味着:您不会将CPU周期花费在复制操作上;很明显,你可以重复使用记忆,也可以重复使用事物的一个副本,而不是两个、三个

另一方面:当你保留引用,而其他人更新外部事物时。。。持有该引用的所有对象也可能会受到影响


从这个意义上说:您应该主要基于从设计角度看什么是最好的来平衡这两个选项。一般来说,现在很多人都试图实现不可变的类/对象。含义:一经创造,对象的内容将不再改变;换句话说:如果你想变得不可变,你必须转向防御性复制。但是可以从中获得很多好处。

这是一种非常普遍的情况——当您创建一个依赖于外部数组或列表的对象时——该对象是否应该简单地重复使用现有引用;或者你需要创建输入数据的副本吗

重复使用意味着:您不会将CPU周期花费在复制操作上;很明显,你可以重复使用记忆,也可以重复使用事物的一个副本,而不是两个、三个

另一方面:当你保留引用,而其他人更新外部事物时。。。持有该引用的所有对象也可能会受到影响


从这个意义上说:您应该主要基于从设计角度看什么是最好的来平衡这两个选项。一般来说,现在很多人都试图实现不可变的类/对象。含义:一经创造,对象的内容将不再改变;换句话说:如果你想变得不可变,你必须转向防御性复制。但是可以从中获得很多好处。

可能的错误是,如果在实例中重用数组,就会将其与调用代码耦合,即,对数组所做的每一次更改(但在该类之外)都可能产生副作用

例如:

char[] chars = new char[]{ 'a', 'b', 'c', ..., 'z' };
Alphabet lower = new Alphabet( chars );

for( int i = 0; i < chars.length; i++ ) {
  chars[i] = Character.toUpperCase( chars[i] );
}
Alphabet upper = new Alphabet( chars );
如果数组在字母表中重复使用(即未克隆),您可能会认为小写字符处理小写字符,而实际上它使用的数组的元素已被大写计数器部分替换

因此,在大多数情况下,创建阵列的副本更安全,例如,通过对其调用克隆,还有其他方法

这样做的缺点当然是增加了内存使用量和执行复制的一些性能成本——这两个成本对于一些小型阵列来说可以忽略不计,但随着阵列大小和/或数量的增加,这一成本会增加


另一个缺点可能是调用代码可能期望共享阵列,而创建克隆可能会破坏这一点。您还必须检查这一点。

可能的错误是,如果在实例中重用该数组,则会将其与调用代码耦合,即对该数组所做的每一次更改(但在该类之外)都可能产生副作用

例如:

char[] chars = new char[]{ 'a', 'b', 'c', ..., 'z' };
Alphabet lower = new Alphabet( chars );

for( int i = 0; i < chars.length; i++ ) {
  chars[i] = Character.toUpperCase( chars[i] );
}
Alphabet upper = new Alphabet( chars );
如果数组在字母表中重复使用(即未克隆),您可能会认为小写字符处理小写字符,而实际上它使用的数组的元素已被大写计数器部分替换

因此,在大多数情况下,创建阵列的副本更安全,例如,通过对其调用克隆,还有其他方法

这样做的缺点当然是增加了内存使用量和执行复制的一些性能成本——这两个成本对于一些小型阵列来说可以忽略不计,但随着阵列大小和/或数量的增加,这一成本会增加


另一个缺点可能是调用代码可能期望共享阵列,而创建克隆可能会破坏这一点。您还必须检查它。

更多的内存使用和更少的性能
更多的内存使用和更少的性能。谢谢!因为这个例子,我更能理解这个。谢谢!我更理解这个例子。