mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix bytesToFloat bug
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
### 🐣新特性
|
||||
### 🐞Bug修复
|
||||
* 【core 】 LineReadWatcher#onModify文件清空判断问题(issue#2013@Github)
|
||||
* 【core 】 修复4位bytes转换float问题(issue#I4M0E4@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.7.17 (2021-12-09)
|
||||
|
@@ -54,13 +54,40 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
this.targetType = (null == clazz) ? Number.class : clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<Number> getTargetType() {
|
||||
return (Class<Number>) this.targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Number convertInternal(Object value) {
|
||||
return convert(value, this.targetType, this::convertToStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertToStr(Object value) {
|
||||
String result = StrUtil.trim(super.convertToStr(value));
|
||||
if (StrUtil.isNotEmpty(result)) {
|
||||
final char c = Character.toUpperCase(result.charAt(result.length() - 1));
|
||||
if (c == 'D' || c == 'L' || c == 'F') {
|
||||
// 类型标识形式(例如123.6D)
|
||||
return StrUtil.subPre(result, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换对象为数字
|
||||
* 转换对象为数字,支持的对象包括:
|
||||
* <ul>
|
||||
* <li>Number对象</li>
|
||||
* <li>Boolean</li>
|
||||
* <li>byte[]</li>
|
||||
* <li>String</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @param value 对象值
|
||||
* @param targetType 目标的数字类型
|
||||
@@ -68,12 +95,17 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
* @return 转换后的数字
|
||||
* @since 5.5.0
|
||||
*/
|
||||
protected static Number convert(Object value, Class<?> targetType, Function<Object, String> toStrFunc) {
|
||||
protected static Number convert(Object value, Class<? extends Number> targetType, Function<Object, String> toStrFunc) {
|
||||
// 枚举转换为数字默认为其顺序
|
||||
if (value instanceof Enum) {
|
||||
return convert(((Enum<?>) value).ordinal(), targetType, toStrFunc);
|
||||
}
|
||||
|
||||
// since 5.7.18
|
||||
if(value instanceof byte[]){
|
||||
return ByteUtil.bytesToNumber((byte[])value, targetType, ByteUtil.DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
if (Byte.class == targetType) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).byteValue();
|
||||
@@ -91,8 +123,6 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return ((Number) value).shortValue();
|
||||
} else if (value instanceof Boolean) {
|
||||
return BooleanUtil.toShortObj((Boolean) value);
|
||||
} else if (value instanceof byte[]){
|
||||
return ByteUtil.bytesToShort((byte[]) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
try{
|
||||
@@ -111,17 +141,13 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return (int) ((Calendar) value).getTimeInMillis();
|
||||
} else if (value instanceof TemporalAccessor) {
|
||||
return (int) DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
|
||||
} else if (value instanceof byte[]){
|
||||
return ByteUtil.bytesToInt((byte[]) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseInt(valueStr);
|
||||
} else if (AtomicInteger.class == targetType) {
|
||||
final Number number = convert(value, Integer.class, toStrFunc);
|
||||
if (null != number) {
|
||||
final AtomicInteger intValue = new AtomicInteger();
|
||||
intValue.set(number.intValue());
|
||||
return intValue;
|
||||
return new AtomicInteger(number.intValue());
|
||||
}
|
||||
} else if (Long.class == targetType) {
|
||||
if (value instanceof Number) {
|
||||
@@ -134,17 +160,13 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return ((Calendar) value).getTimeInMillis();
|
||||
} else if (value instanceof TemporalAccessor) {
|
||||
return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
|
||||
}else if (value instanceof byte[]){
|
||||
return ByteUtil.bytesToLong((byte[]) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseLong(valueStr);
|
||||
} else if (AtomicLong.class == targetType) {
|
||||
final Number number = convert(value, Long.class, toStrFunc);
|
||||
if (null != number) {
|
||||
final AtomicLong longValue = new AtomicLong();
|
||||
longValue.set(number.longValue());
|
||||
return longValue;
|
||||
return new AtomicLong(number.longValue());
|
||||
}
|
||||
} else if (LongAdder.class == targetType) {
|
||||
//jdk8 新增
|
||||
@@ -159,8 +181,6 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return ((Number) value).floatValue();
|
||||
} else if (value instanceof Boolean) {
|
||||
return BooleanUtil.toFloatObj((Boolean) value);
|
||||
} else if (value instanceof byte[]){
|
||||
return (float)ByteUtil.bytesToDouble((byte[]) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseFloat(valueStr);
|
||||
@@ -169,8 +189,6 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
return ((Number) value).doubleValue();
|
||||
} else if (value instanceof Boolean) {
|
||||
return BooleanUtil.toDoubleObj((Boolean) value);
|
||||
} else if (value instanceof byte[]){
|
||||
return ByteUtil.bytesToDouble((byte[]) value);
|
||||
}
|
||||
final String valueStr = toStrFunc.apply((value));
|
||||
return StrUtil.isBlank(valueStr) ? null : NumberUtil.parseDouble(valueStr);
|
||||
@@ -212,9 +230,7 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
if (value instanceof Number) {
|
||||
return NumberUtil.toBigDecimal((Number) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
return new BigDecimal((boolean) value ? 1 : 0);
|
||||
} else if (value instanceof byte[]){
|
||||
return NumberUtil.toBigDecimal(ByteUtil.bytesToDouble((byte[]) value));
|
||||
return ((boolean) value) ? BigDecimal.ONE : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
//对于Double类型,先要转换为String,避免精度问题
|
||||
@@ -234,31 +250,9 @@ public class NumberConverter extends AbstractConverter<Number> {
|
||||
if (value instanceof Long) {
|
||||
return BigInteger.valueOf((Long) value);
|
||||
} else if (value instanceof Boolean) {
|
||||
return BigInteger.valueOf((boolean) value ? 1 : 0);
|
||||
} else if (value instanceof byte[]){
|
||||
return BigInteger.valueOf(ByteUtil.bytesToLong((byte[]) value));
|
||||
return (boolean) value ? BigInteger.ONE : BigInteger.ZERO;
|
||||
}
|
||||
|
||||
return NumberUtil.toBigInteger(toStrFunc.apply(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertToStr(Object value) {
|
||||
String result = StrUtil.trim(super.convertToStr(value));
|
||||
if (StrUtil.isNotEmpty(result)) {
|
||||
final char c = Character.toUpperCase(result.charAt(result.length() - 1));
|
||||
if (c == 'D' || c == 'L' || c == 'F') {
|
||||
// 类型标识形式(例如123.6D)
|
||||
return StrUtil.subPre(result, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<Number> getTargetType() {
|
||||
return (Class<Number>) this.targetType;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,12 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.DoubleAdder;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* 对数字和字节进行转换。<br>
|
||||
@@ -21,6 +27,8 @@ import java.nio.ByteOrder;
|
||||
*/
|
||||
public class ByteUtil {
|
||||
|
||||
public static ByteOrder DEFAULT_ORDER = ByteOrder.LITTLE_ENDIAN;
|
||||
|
||||
/**
|
||||
* int转byte
|
||||
*
|
||||
@@ -51,14 +59,14 @@ public class ByteUtil {
|
||||
* @return short值
|
||||
*/
|
||||
public static short bytesToShort(byte[] bytes) {
|
||||
return bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||
return bytesToShort(bytes, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转short<br>
|
||||
* 自定义端序
|
||||
*
|
||||
* @param bytes byte数组
|
||||
* @param bytes byte数组,长度必须为2
|
||||
* @param byteOrder 端序
|
||||
* @return short值
|
||||
*/
|
||||
@@ -79,7 +87,7 @@ public class ByteUtil {
|
||||
* @return byte数组
|
||||
*/
|
||||
public static byte[] shortToBytes(short shortValue) {
|
||||
return shortToBytes(shortValue, ByteOrder.LITTLE_ENDIAN);
|
||||
return shortToBytes(shortValue, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +118,7 @@ public class ByteUtil {
|
||||
* @return int值
|
||||
*/
|
||||
public static int bytesToInt(byte[] bytes) {
|
||||
return bytesToInt(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||
return bytesToInt(bytes, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +152,7 @@ public class ByteUtil {
|
||||
* @return byte数组
|
||||
*/
|
||||
public static byte[] intToBytes(int intValue) {
|
||||
return intToBytes(intValue, ByteOrder.LITTLE_ENDIAN);
|
||||
return intToBytes(intValue, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +193,7 @@ public class ByteUtil {
|
||||
* @return byte数组
|
||||
*/
|
||||
public static byte[] longToBytes(long longValue) {
|
||||
return longToBytes(longValue, ByteOrder.LITTLE_ENDIAN);
|
||||
return longToBytes(longValue, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,7 +230,7 @@ public class ByteUtil {
|
||||
* @return long值
|
||||
*/
|
||||
public static long bytesToLong(byte[] bytes) {
|
||||
return bytesToLong(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||
return bytesToLong(bytes, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,6 +259,54 @@ public class ByteUtil {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* float转byte数组,默认以小端序转换<br>
|
||||
*
|
||||
* @param floatValue float值
|
||||
* @return byte数组
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static byte[] floatToBytes(float floatValue) {
|
||||
return floatToBytes(floatValue, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* float转byte数组,自定义端序<br>
|
||||
*
|
||||
* @param floatValue float值
|
||||
* @param byteOrder 端序
|
||||
* @return byte数组
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static byte[] floatToBytes(float floatValue, ByteOrder byteOrder) {
|
||||
return intToBytes(Float.floatToIntBits(floatValue), byteOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转float<br>
|
||||
* 默认以小端序转换<br>
|
||||
*
|
||||
* @param bytes byte数组
|
||||
* @return float值
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static double bytesToFloat(byte[] bytes) {
|
||||
return bytesToFloat(bytes, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转float<br>
|
||||
* 自定义端序<br>
|
||||
*
|
||||
* @param bytes byte数组
|
||||
* @param byteOrder 端序
|
||||
* @return float值
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static float bytesToFloat(byte[] bytes, ByteOrder byteOrder) {
|
||||
return Float.intBitsToFloat(bytesToInt(bytes, byteOrder));
|
||||
}
|
||||
|
||||
/**
|
||||
* double转byte数组<br>
|
||||
* 默认以小端序转换<br>
|
||||
@@ -259,7 +315,7 @@ public class ByteUtil {
|
||||
* @return byte数组
|
||||
*/
|
||||
public static byte[] doubleToBytes(double doubleValue) {
|
||||
return doubleToBytes(doubleValue, ByteOrder.LITTLE_ENDIAN);
|
||||
return doubleToBytes(doubleValue, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,7 +339,7 @@ public class ByteUtil {
|
||||
* @return long值
|
||||
*/
|
||||
public static double bytesToDouble(byte[] bytes) {
|
||||
return bytesToDouble(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||
return bytesToDouble(bytes, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,7 +361,7 @@ public class ByteUtil {
|
||||
* @return bytes
|
||||
*/
|
||||
public static byte[] numberToBytes(Number number) {
|
||||
return numberToBytes(number, ByteOrder.LITTLE_ENDIAN);
|
||||
return numberToBytes(number, DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,8 +380,62 @@ public class ByteUtil {
|
||||
return intToBytes((Integer) number, byteOrder);
|
||||
} else if (number instanceof Short) {
|
||||
return shortToBytes((Short) number, byteOrder);
|
||||
} else if (number instanceof Float) {
|
||||
return floatToBytes((Float) number, byteOrder);
|
||||
} else {
|
||||
return doubleToBytes(number.doubleValue(), byteOrder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换为指定类型数字
|
||||
*
|
||||
* @param <T> 数字类型
|
||||
* @param bytes byte数组
|
||||
* @param targetClass 目标数字类型
|
||||
* @param byteOrder 端序
|
||||
* @return 转换后的数字
|
||||
* @throws IllegalArgumentException 不支持的数字类型,如用户自定义数字类型
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Number> T bytesToNumber(byte[] bytes, Class<T> targetClass, ByteOrder byteOrder) throws IllegalArgumentException {
|
||||
Number number;
|
||||
if (Byte.class == targetClass) {
|
||||
number = bytes[0];
|
||||
} else if (Short.class == targetClass) {
|
||||
number = bytesToShort(bytes, byteOrder);
|
||||
} else if (Integer.class == targetClass) {
|
||||
number = bytesToInt(bytes, byteOrder);
|
||||
} else if (AtomicInteger.class == targetClass) {
|
||||
number = new AtomicInteger(bytesToInt(bytes, byteOrder));
|
||||
} else if (Long.class == targetClass) {
|
||||
number = bytesToLong(bytes, byteOrder);
|
||||
} else if (AtomicLong.class == targetClass) {
|
||||
number = new AtomicLong(bytesToLong(bytes, byteOrder));
|
||||
} else if (LongAdder.class == targetClass) {
|
||||
final LongAdder longValue = new LongAdder();
|
||||
longValue.add(bytesToLong(bytes, byteOrder));
|
||||
number = longValue;
|
||||
} else if (Float.class == targetClass) {
|
||||
number = bytesToFloat(bytes, byteOrder);
|
||||
} else if (Double.class == targetClass) {
|
||||
number = bytesToDouble(bytes, byteOrder);
|
||||
} else if (DoubleAdder.class == targetClass) {
|
||||
final DoubleAdder doubleAdder = new DoubleAdder();
|
||||
doubleAdder.add(bytesToDouble(bytes, byteOrder));
|
||||
number = doubleAdder;
|
||||
} else if (BigDecimal.class == targetClass) {
|
||||
number = NumberUtil.toBigDecimal(bytesToDouble(bytes, byteOrder));
|
||||
} else if (BigInteger.class == targetClass) {
|
||||
number = BigInteger.valueOf(bytesToLong(bytes, byteOrder));
|
||||
} else if (Number.class == targetClass) {
|
||||
// 用户没有明确类型具体类型,默认Double
|
||||
number = bytesToDouble(bytes, byteOrder);
|
||||
} else {
|
||||
// 用户自定义类型不支持
|
||||
throw new IllegalArgumentException("Unsupported Number type: " + targetClass.getName());
|
||||
}
|
||||
|
||||
return (T) number;
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ByteUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
@@ -343,4 +344,13 @@ public class ConvertTest {
|
||||
final BigDecimal bigDecimal = Convert.toBigDecimal(str);
|
||||
Assert.assertEquals(str, bigDecimal.toPlainString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toFloatTest(){
|
||||
// https://gitee.com/dromara/hutool/issues/I4M0E4
|
||||
String hex2 = "CD0CCB43";
|
||||
final byte[] value = HexUtil.decodeHex(hex2);
|
||||
final float f = Convert.toFloat(value);
|
||||
Assert.assertEquals(406.1F, f, 2);
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ public class ByteUtilTest {
|
||||
@Test
|
||||
public void intAndBytesLittleEndianTest() {
|
||||
// 测试 int 转小端序 byte 数组
|
||||
int int1 = 1417;
|
||||
int int1 = RandomUtil.randomInt();
|
||||
|
||||
byte[] bytesInt = ByteUtil.intToBytes(int1, ByteOrder.LITTLE_ENDIAN);
|
||||
int int2 = ByteUtil.bytesToInt(bytesInt, ByteOrder.LITTLE_ENDIAN);
|
||||
@@ -28,7 +28,7 @@ public class ByteUtilTest {
|
||||
@Test
|
||||
public void intAndBytesBigEndianTest() {
|
||||
// 测试 int 转大端序 byte 数组
|
||||
int int2 = 1417;
|
||||
int int2 = RandomUtil.randomInt();
|
||||
byte[] bytesInt = ByteUtil.intToBytes(int2, ByteOrder.BIG_ENDIAN);
|
||||
|
||||
// 测试大端序 byte 数组转 int
|
||||
@@ -65,9 +65,30 @@ public class ByteUtilTest {
|
||||
Assert.assertEquals(long1, long2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void floatAndBytesLittleEndianTest() {
|
||||
// 测试 long 转 byte 数组
|
||||
float f1 = (float) RandomUtil.randomDouble();
|
||||
|
||||
byte[] bytesLong = ByteUtil.floatToBytes(f1, ByteOrder.LITTLE_ENDIAN);
|
||||
float f2 = ByteUtil.bytesToFloat(bytesLong, ByteOrder.LITTLE_ENDIAN);
|
||||
Assert.assertEquals(f1, f2, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void floatAndBytesBigEndianTest() {
|
||||
// 测试大端序 long 转 byte 数组
|
||||
float f1 = (float) RandomUtil.randomDouble();
|
||||
|
||||
byte[] bytesLong = ByteUtil.floatToBytes(f1, ByteOrder.BIG_ENDIAN);
|
||||
float f2 = ByteUtil.bytesToFloat(bytesLong, ByteOrder.BIG_ENDIAN);
|
||||
|
||||
Assert.assertEquals(f1, f2, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shortAndBytesLittleEndianTest() {
|
||||
short short1 = 122;
|
||||
short short1 = (short) RandomUtil.randomInt();
|
||||
|
||||
byte[] bytes = ByteUtil.shortToBytes(short1, ByteOrder.LITTLE_ENDIAN);
|
||||
short short2 = ByteUtil.bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||
|
Reference in New Issue
Block a user