使用System.arraycopy()容易忽略的问题

本文详细介绍了Java中的arraycopy()方法,包括其参数说明、常见使用方法及潜在问题。特别是关于浅复制导致的数据引用问题,通过实例展示了如何影响数组数据一致性。

arraycopy()方法在JDK中是这样介绍的:

void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array.
A subsequence of array components are copied from the source array referenced by src to the destination array referenced by dest.
The number of components copied is equal to the length argument. The components at positions srcPos through srcPos+length-1 in
the source array are copied into positions destPos through destPos+length-1, respectively, of the destination array.
If the src and dest arguments refer to the same array object, then the copying is performed as if the components
at positions srcPos through srcPos+length-1 were first copied to a temporary array with length components
and then the contents of the temporary array were copied into positions destPos through destPos+length-1 of the destination array.

下面简单介绍一下:

参数:
src:源数组;	srcPos:源数组要复制的起始位置;
dest:目的数组;	destPos:目的数组放置的起始位置;	length:复制的长度。

简单描述就是从src的srcPos位置拷贝length长度的数据到dest的destPos位置,如果src和dest是同一个对象的话,则相当于先将数据拷贝到一个临时的数组,然后再覆盖数组中destPos开始的一段数据。

常见的使用方法:

int[] is = new int[]{1,2,3,4,5}; 
int[] is2 = new int[is.length];
System.arraycopy(is, 0, is2, 0, is.length);
System.out.println(Arrays.toString(is2));

 

但是,使用此方法有个很严重的问题,由于它的复制是浅复制(shallow copy),复制后的数组与原数组中的数据指向同一个位置.

示例如下:

public class Clone2 {
    public static void main(String[] args) {
        Te[] t1 = new Te[1];
        t1[0] = new Te("a");
        Te[] t2 = new Te[1];
        System.out.println(t1[0]);
        //调用
        System.arraycopy(t1, 0, t2, 0, 1);
        System.out.println(t2[0]);
    }
}
class Te{
    String name;
    Te(String name) {
        this.name = name;
    }
}
//输出
/*
CloneTest.Te@74a14482
CloneTest.Te@74a14482
*/

从上面的输出可以看出复制后的数组中的元素与原来指向了一个位置,这样子很容易引发严重的问题.一旦我们更改了原来的数据,复制后的数据也会随之改变.

例如:

public class Clone2 {
    public static void main(String[] args) {
        Te[] t1 = new Te[1];
        t1[0] = new Te("a");
        Te[] t2 = new Te[1];
        System.out.println("t1修改前:"+t1[0]);
        //修改t1[0]
        t1[0].name = "2";
        System.out.println("t1修改后:"+t1[0]);
        //调用
        System.arraycopy(t1, 0, t2, 0, 1);
        System.out.println("t2:"+t2[0]);
    }
}
class Te{
    String name;
    Te(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Te{" +
                "name='" + name + '\'' +
                '}';
    }
}
//输出:
/*
t1修改前:Te{name='a'}
t1修改后:Te{name='2'}
t2:Te{name='2'}
 */
对t1[0]进行修改,但是由于t1[0]和t2[0]引用了同一个对象,因此后者也会随之改变,在平时的使用中如果不注意的话会引起相当大的问题。
 
而且由于System.arraycoppy()是JDK中的native方法,JDK中有关于集合,数组操作的基本上都调用此方法,因此在使用这些的时候要注意。
 
 
 

转载于:https://www.cnblogs.com/weikongziqu/p/5808184.html

Java的大学基础知识,以面向的思维,带参的方法,把以下学生管理类的代码(完善,优化,纠错)import java.util.Scanner; public class StuMgs { //管理学生的对象数据 Student[] stuArr = new Student[5]; int count = 0; public void getMenu(Scanner input){ while(true){ System.out.println("1-增加学员,2-展示学员,3-查找学员,4-修改学员,5-退出系统"); System.out.println("请选择功能:"); int key=input.nextInt(); switch(key){ case 1: //增加学员 add(input); break; case 2: //展示学员 show(); break; case 3: //查找学员 find(input); break; case 4: //修改学员 update(input); break; case 5: //退出系统 System.out.println("您已退出程序。"); System.exit(0); break; default: System.out.println("输入无效,请重新选择"); break; } } } //4-修改学员信息 private void update(Scanner input){ System.out.println("请输入"); String result = input.next(); if(result.equals("n")){ System.out.println(""); return; } for(int i=0;i<stuArr.length;i++){ if(stuArr[i]!=null && stuArr[i].score<60){ for(int j=0;j<stuArr.length;j++){ } } } } //3-查找学员 private void find(Scanner input){ System.out.println("请输入要查找的学生的姓名:"); String name=input.next(); System.out.println("请输入要开始查找的位置:"); int begin=input.nextInt(); System.out.println("请输入要结束查找的位置:"); int end=input.nextInt(); for(int i=begin;i<=end;i++){ if(name.equals(stuArr[i])){ System.out.println("恭喜您,查到了该生姓名:"); } } } //1-增加学员信息 private void add(Scanner input){ if(getSize()== stuArr.length){ System.out.println(""); return; } //获取要添加的对象 System.out.println("请输入姓名:"); String name=input.next(); System.out.println("请输入年龄:"); int age=input.nextInt(); System.out.println("请输入成绩:"); double score=input.nextDouble(); Student stu =new Student(); stu.name=name; stu.age=age; stu.score=score; //添加到数组中 for(int i = 0; i< stuArr.length; i++){ } } //2-展示学生信息 private void show(){ System.out.println("序号\t 姓名\t 年龄\t 成绩"); if(getSize()==0); System.out.println("暂无数据"); return; } for(int i=0 ;i<stuArr.length;i++){ if(stuArr[i] !=null){ System.out.println(i + 1 + "/t"); stuArr[i].show(); } } }
09-07
结合以下两组代码:public class Main { public static void main(String[] args) { // 定义一个数组并初始化 int[] a = {3, 5, 8, 2, 6, 10, 1, 11, 7, 18}; int i, min, pos; int s = 0; // 用于存储数组元素的和 double avg = 0.00000; // 用于存储数组元素的平均值 // 找到数组中的最小值及其位置 min = a[0]; // 假设第一个元素为最小值 pos = 0; // 最小值的位置初始化为0 // 输出数组元素 for (i = 0; i <= 9; i++) { System.out.print(a[i] + "\t"); } System.out.println(); // 换行 // 遍历数组,找到最小值及其位置 for (i = 1; i <= 9; i++) { if (min > a[i]) { min = a[i]; // 更新最小值 pos = i; // 更新最小值的位置 } } System.out.println("min=" + min + ",位置pos=" + pos); // 输出最小值及其位置 // 计算数组元素的和 for (i = 0; i <= 9; i++) { s += a[i]; } System.out.println("数组和:" + s); // 输出数组元素的和 // 计算数组元素的平均值 avg = (double) s / 10; // 将和转换为double类型再除以元素个数 System.out.println("平均值:" + avg); // 输出平均值 // 将最小值交换到数组的第一个位置 int tmp = a[0]; // 保存第一个元素的值 a[0] = a[pos]; // 将最小值放到第一个位置 a[pos] = tmp; // 将原来的第一个元素放到最小值原来的位置 // 输出交换后的数组元素 System.out.print("交换后的数组:"); for (i = 0; i <= 9; i++) { System.out.print(a[i] + "\t"); } } } 第二种: int read = 0; System.out.println("输入数据:"); try{ read = System.in.read(); }catch(Exception e){ e.printStackTrace(); } System.out.println("您输入的数据为:" + read); 来帮我解决这一问题: 题目描述:编写一个Java程序,该程序首先从控制台读取一系列整数(直到输入“end”为止),然后将这些整数存储到一个一维数组中。程序需要计算并输出这个数组中的最大值和最小值。 要求: 使用循环结构来实现。 确保处理了用户直接输入“end”而没有输入任何数字的情况。 考虑数组为空时的边界情况。 目前我没有学习import相关知识 最好使用该知识 而只使用以上代码相关知识
03-17
重新写一下MainActivity.java 以下是我的BluetoothHelper.java package com.example.heart_oxygen_monitoring_system; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothManager; import android.content.Context; import android.util.Log; import java.util.Set; public class BluetoothHelper { private static final String TAG = "BluetoothHelper"; private final BluetoothAdapter bluetoothAdapter; public BluetoothHelper(Context context) { BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager == null) { Log.e(TAG, "Bluetooth not supported on this device"); bluetoothAdapter = null; return; } bluetoothAdapter = bluetoothManager.getAdapter(); } public BluetoothAdapter getBluetoothAdapter() { return bluetoothAdapter; } public boolean isBluetoothEnabled() { return bluetoothAdapter != null && bluetoothAdapter.isEnabled(); } public boolean isBluetoothSupported() { return bluetoothAdapter != null; } @SuppressLint("MissingPermission") public Set<BluetoothDevice> getBondedDevices() { if (bluetoothAdapter == null) { return null; } return bluetoothAdapter.getBondedDevices(); } @SuppressLint("MissingPermission") public boolean startDiscovery() { if (bluetoothAdapter == null) { return false; } if (bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); } return bluetoothAdapter.startDiscovery(); } @SuppressLint("MissingPermission") public boolean cancelDiscovery() { if (bluetoothAdapter == null) { return false; } return bluetoothAdapter.cancelDiscovery(); } } 以下是我的BinaryPacketParser.java package com.example.heart_oxygen_monitoring_system; import android.util.Log; public class BinaryPacketParser { private static final String TAG = "BinaryPacketParser"; // 数据包常量 private static final byte HEADER = (byte) 0xA5; private static final byte FOOTER = (byte) 0x5A; private static final int PACKET_SIZE = 19; private byte[] buffer = new byte[1024]; private int bufferPosition = 0; private int packetCount = 0; private int errorCount = 0; // 修改接口定义,只有三个参数 public interface PacketListener { void onSensorDataReceived(int heartRate, int spo2, int temperature); void onPacketError(String error); void onDebugInfo(String info); } public void processData(byte[] newData, int bytesRead, PacketListener listener) { if (bytesRead <= 0) return; if (bufferPosition + bytesRead >= buffer.length) { bufferPosition = 0; listener.onPacketError("缓冲区溢出,已重置"); } System.arraycopy(newData, 0, buffer, bufferPosition, bytesRead); bufferPosition += bytesRead; processBuffer(listener); } private void processBuffer(PacketListener listener) { while (bufferPosition >= PACKET_SIZE) { int packetStart = findPacketStart(); if (packetStart == -1) { bufferPosition = 0; return; } if (packetStart > 0) { listener.onDebugInfo("丢弃 " + packetStart + " 字节无效数据"); System.arraycopy(buffer, packetStart, buffer, 0, bufferPosition - packetStart); bufferPosition -= packetStart; } if (bufferPosition >= PACKET_SIZE) { byte[] packet = new byte[PACKET_SIZE]; System.arraycopy(buffer, 0, packet, 0, PACKET_SIZE); // 调试输出 listener.onDebugInfo("收到数据包: " + bytesToHex(packet)); if (validatePacket(packet)) { parsePacket(packet, listener); packetCount++; } else { errorCount++; // 详细错误信息 byte calculatedChecksum = calculateChecksum(packet); listener.onPacketError(String.format("校验和错误: 期望=0x%02X, 实际=0x%02X", packet[17] & 0xFF, calculatedChecksum & 0xFF)); } int remaining = bufferPosition - PACKET_SIZE; if (remaining > 0) { System.arraycopy(buffer, PACKET_SIZE, buffer, 0, remaining); } bufferPosition = remaining; } } } private int findPacketStart() { for (int i = 0; i <= bufferPosition - 1; i++) { if (buffer[i] == HEADER) { return i; } } return -1; } private boolean validatePacket(byte[] packet) { // 检查包头包尾 if (packet[0] != HEADER || packet[PACKET_SIZE - 1] != FOOTER) { return false; } // 计算校验和(1-16字节,与STM32端一致) byte calculatedChecksum = calculateChecksum(packet); return calculatedChecksum == packet[17]; } // 计算校验和(1-16字节) private byte calculateChecksum(byte[] packet) { int sum = 0; for (int i = 1; i <= 16; i++) { sum += packet[i] & 0xFF; } return (byte)(sum & 0xFF); } private void parsePacket(byte[] packet, PacketListener listener) { try { // 解析温度(小端模式) int temperature = (packet[4] & 0xFF) << 24 | (packet[3] & 0xFF) << 16 | (packet[2] & 0xFF) << 8 | (packet[1] & 0xFF); // 解析心率(小端模式) int heartRate = (packet[8] & 0xFF) << 24 | (packet[7] & 0xFF) << 16 | (packet[6] & 0xFF) << 8 | (packet[5] & 0xFF); // 解析血氧(小端模式) int spo2 = (packet[12] & 0xFF) << 24 | (packet[11] & 0xFF) << 16 | (packet[10] & 0xFF) << 8 | (packet[9] & 0xFF); // 解析湿度(浮点数,小端模式)但忽略使用 int humidityBits = (packet[16] & 0xFF) << 24 | (packet[15] & 0xFF) << 16 | (packet[14] & 0xFF) << 8 | (packet[13] & 0xFF); float humidity = Float.intBitsToFloat(humidityBits); listener.onDebugInfo(String.format("解析成功: Temp=%d, HR=%d, SpO2=%d, Hum=%.1f(忽略)", temperature, heartRate, spo2, humidity)); // 只传递三个参数 listener.onSensorDataReceived(heartRate, spo2, temperature); } catch (Exception e) { errorCount++; listener.onPacketError("解析异常: " + e.getMessage()); } } private String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { hexString.append(String.format("%02X ", b)); } return hexString.toString(); } public void reset() { bufferPosition = 0; packetCount = 0; errorCount = 0; } public String getStats() { return String.format("包数: %d, 错误: %d", packetCount, errorCount); } }
最新发布
09-11
java.lang.UnsupportedOperationException: Provided data element number (1049024) should be multiple of the Mat channels count (3) 报错了 /** * ocr配置 */ @PostConstruct public void initOcrEngine() { tesseract = new Tesseract(); //语言包路径和支持语言 tesseract.setDatapath(tessDataPath); tesseract.setLanguage("eng+chi_sim"); tesseract.setPageSegMode(6); // 完全自动页面分割模式 tesseract.setOcrEngineMode(2); // LSTM引擎 tesseract.setTessVariable("preserve_interword_spaces", "1"); } /** * OCR识别图片内容 */ private String extractImageText(MultipartFile file) { try (InputStream is = file.getInputStream()) { BufferedImage image = ImageIO.read(is); if (image == null) { return MessageUtils.message("Image.parsing.failed"); } Mat opencvMat = bufferedImageToMat(image); Mat processedMat = preprocessImage(opencvMat); BufferedImage processedImage = matToBufferedImage(processedMat); // BufferedImage processedImage = preprocessImage(image); String result = tesseract.doOCR(processedImage); result = postProcess(result); result = result.replaceAll("\\s+", " ").trim(); System.out.println("图片内容:\n" + result); return result; } catch (Exception e) { e.printStackTrace(); return MessageUtils.message("file.read.picture.error"); } } // 核心图像预处理 private Mat preprocessImage(Mat image) { // 1. 尺寸检查(确保300+ DPI) if (image.rows() < 300 || image.cols() < 300) { Mat resized = new Mat(); Imgproc.resize(image, resized, new Size(image.cols()*1.5, image.rows()*1.5), 0, 0, Imgproc.INTER_LINEAR); image = resized; } // 2. 灰度化 + 二值化 Mat gray = new Mat(); Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY); Imgproc.threshold(gray, gray, 0, 255, Imgproc.THRESH_BINARY_INV + Imgproc.THRESH_OTSU); // 3. 文本区域聚焦(可选) Mat roi = detectTextRegion(gray); return roi.empty() ? gray : roi; } // 文本区域检测 private Mat detectTextRegion(Mat binaryImage) { // 1. 使用正确的轮廓存储类型(List<MatOfPoint>) List<MatOfPoint> contours = new ArrayList<>(); Mat hierarchy = new Mat(); // 2. 正确调用findContours(OpenCV 4.x API) Imgproc.findContours( binaryImage, contours, // 正确类型 hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE ); // 3. 寻找最大轮廓 double maxArea = 0; Rect maxRect = null; // 初始化为null更安全 // 4. 正确遍历轮廓列表 for (MatOfPoint contour : contours) { double area = Imgproc.contourArea(contour); if (area > maxArea) { maxArea = area; maxRect = Imgproc.boundingRect(contour); } } // 5. 安全返回结果 return (maxRect != null) ? new Mat(binaryImage, maxRect) : new Mat(); } // 文本后处理 private String postProcessText(String text) { // 1. 清理OCR常见噪声 text = text.replaceAll("[^\\p{L}\\p{Nd}.,:;!?@#$%&*()_+=\\-\\s]", "") .replaceAll("\\s+", " ") .trim(); // 2. 结构化数据提取(示例:提取日期) String datePattern = "\\d{4}[-/年]\\d{1,2}[-/月]\\d{1,2}日?"; java.util.regex.Matcher matcher = java.util.regex.Pattern .compile(datePattern).matcher(text); return matcher.find() ? "检测到日期: " + matcher.group() + "\n全文:\n" + text : text; } // 图像格式转换工具 private Mat bufferedImageToMat(BufferedImage bi) { Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3); byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData(); mat.put(0, 0, data); return mat; } private BufferedImage matToBufferedImage(Mat mat) { int type = (mat.channels() == 1) ? BufferedImage.TYPE_BYTE_GRAY : BufferedImage.TYPE_3BYTE_BGR; BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type); byte[] data = new byte[mat.cols() * mat.rows() * mat.channels()]; mat.get(0, 0, data); System.arraycopy(data, 0, ((DataBufferByte) image.getRaster().getDataBuffer()).getData(), 0, data.length); return image; }
07-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值