提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、数据类型
基本数据类型: byte,short,int,long,boolean,char,float,double
引用数据类型: 类的实例对象,枚举,接口和数组类型
- 基本数据类型的变量,存储的就是数据本身的值;
- 引用数据类型的变量,存储的则是数据的地址,这个地址指向了数据的值。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获取实体。
- 基本数据类型为值传递,引用数据类型为引用传递
二、赋值与浅拷贝
1. 一个由于赋值引发的错误
public void consume(Param param) {
try {
Thread thread = new Thread(() -> {
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getConsumerProps());
consumer.subscribe(param.getTopics());
while (flagMap.get(param.getId())) {
ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofMillis(100));
if (consumerRecords.iterator().hasNext()) {
for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
param.setRecord(String.valueOf(consumerRecord));
WorkerQueue.offer(param);
}
}
}
consumer.close();
});
thread.start();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
consume方法是将Kafka中的数据拼接入参后置入一个队列中。队列中存储的是param的引用,因此当队列长度>0时,param的record属性改变,会使队列中所有元素都改变为当前param。
2. 浅拷贝方式
public class Param implements Cloneable {
private String reocrd;
private List<SegmentMatchParam> list;
@Override
public HitIntelligenceParam clone() {
HitIntelligenceParam hitIntelligenceParam = null;
try {
hitIntelligenceParam = (HitIntelligenceParam) super.clone();
} catch (CloneNotSupportedException e) {
logger.error(e.getMessage(), e);
}
return hitIntelligenceParam;
}
}
Param对象重写clone方法,浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
Param record = param.clone();
record.setRecord(String.valueOf(consumerRecord.value()));
WorkerQueue.offer(new Worker(record));
3. 赋值与浅拷贝
当我们把一个对象赋值给一个新的变量时,赋的时该对象在栈中的地址,而在堆中的数据只有一份。两个对象指向同一块存储空间,无论哪个对象发生改变,改变的都是存储空间中的内容。
浅拷贝是按位拷贝对象,它会创建一个新的对象,这个对象是原对象的属性精准拷贝,即如果是属性是基本类型,拷贝的就是基本属性的值,如果属性是引用类型(内存地址),拷贝的就是内存地址。浅拷贝中,如果其中一个对象改变了这个地址,就会影响到另一个对象,即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
三、浅拷贝与深拷贝
如果在拷贝一个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。
1. 浅拷贝
对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝.
2. 深拷贝
对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
四、实现
浅拷贝
public class Param implements Cloneable {
private String reocrd;
private SegmentMatchParam segment;
@Override
public Param clone() {
Param param = null;
try {
param = (Param) super.clone();
} catch (CloneNotSupportedException e) {
logger.error(e.getMessage(), e);
}
return param;
}
}
Param类实现Clonable接口,重写clone方法。拷贝record的值和segment的内存地址。
2. 深拷贝
常用方案:
1、序列化(serialization)这个对象,再反序列化回来,就可以得到这个新的对象,无非就是序列化的规则需要我们自己来写。
2、继续利用 clone() 方法,既然 clone() 方法,是我们来重写的,实际上我们可以对其内的引用类型的变量,再进行一次 clone()。针对以上例子,SegmentMatchParam 类也需实现Clonable接口并重写clone()方法。
public class SegmentMatchParam implements Cloneable {
@Override
public SegmentMatchParamclone() {
SegmentMatchParam param = null;
try {
param = (SegmentMatchParam ) super.clone();
} catch (CloneNotSupportedException e) {
logger.error(e.getMessage(), e);
}
return param;
}
}
总结
赋值操作:不创建对象,赋值内存地址,一个对象改变,内存中的数据则改变。
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建新对象,存储其内容。
原文地址:https://blog.csdn.net/weixin_41832813/article/details/118090534