Class DynamicNumber
- All Implemented Interfaces:
Serializable,Cloneable,Comparable<DynamicNumber>
This class can hold any subclass of Number and provides
convenience methods to interpret and convert the value to various
numeric types like byte, short, int, long, BigInteger, float,
double, and BigDecimal.
It supports promotion of types to larger ranges and normalization to the smallest suitable numeric type.
- Author:
- Chakib Daii
- See Also:
-
Field Summary
Fields -
Constructor Summary
ConstructorsConstructorDescriptionDynamicNumber(Number value) Constructs aDynamicNumberfrom aNumber.DynamicNumber(Object value) Constructs aDynamicNumberfrom anObjectby parsing it to a numeric value. -
Method Summary
Modifier and TypeMethodDescriptionReturns the value as aBigDecimal.Returns the value as aBigInteger.clone()Creates and returns a copy of thisDynamicNumber.intcompareTo(DynamicNumber anotherDynamicNumber) doubleReturns the value as a double.booleanCompares thisDynamicNumberto another object for equality.floatReturns the value as a float.get()Returns the underlyingNumbervalue.inthashCode()Returns the hash code of the underlying numeric value.intintValue()Returns the value as an int.booleanisAssignableFrom(Class<?> targetType) Checks if the current numeric value can be assigned to the specified target type.static booleanisAssignableFrom(Class<?> valueClass, Class<?> targetType) Determines whether a value of the given runtime class can be assigned to a target type using relaxed numeric and primitive compatibility rules.booleanChecks if the value is aBigDecimal.booleanChecks if the value is aBigInteger.booleanisByte()Checks if the value is aByte.booleanChecks if the value is a floating point type (Float, Double, or BigDecimal).booleanisDouble()Checks if the value is aDouble.booleanisFloat()Checks if the value is aFloat.booleanChecks if the internal value is positive or negative infinity.static booleanisInfinite(Number number) Checks if the given number is positive or negative infinity.booleanisInt()Checks if the value is anInteger.booleanChecks if the value is an integral integer type (Byte, Short, Integer, Long, or BigInteger).booleanisLong()Checks if the value is aLong.booleanisNaN()Checks if the internal value is a floating-point NaN (Not-a-Number).static booleanChecks if the given number is NaN (Not-a-Number).booleanisShort()Checks if the value is aShort.longReturns the value as a long.Normalizes the internal number value to the smallest suitable numeric type.normalize(boolean processFloatingNumbers) Normalizes the internal number to the most compact numeric type possible, optionally including support for floating point number simplification.private static intnumericRank(Class<?> clazz) Returns the numeric rank of a class to determine widening order.static DynamicNumberCreates a newDynamicNumberfrom aNumber.static DynamicNumberCreates a newDynamicNumberby parsing anObject.promote()Promotes the number to the next wider numeric type.Sets the underlying value.toString()Returns the string representation of the numeric value.Methods inherited from class java.lang.Number
byteValue, shortValue
-
Field Details
-
value
The underlying numeric value.
-
-
Constructor Details
-
DynamicNumber
Constructs aDynamicNumberfrom aNumber.- Parameters:
value- the numeric value, must not be null- Throws:
NaftahBugError- if the value is null
-
DynamicNumber
Constructs aDynamicNumberfrom anObjectby parsing it to a numeric value.- Parameters:
value- the value to parse as a number, must not be null- Throws:
NaftahBugError- if the value is null- See Also:
-
-
Method Details
-
of
Creates a newDynamicNumberfrom aNumber.- Parameters:
value- the number- Returns:
- a new
DynamicNumberwrapping the given value
-
of
Creates a newDynamicNumberby parsing anObject.- Parameters:
value- the value to parse- Returns:
- a new
DynamicNumberrepresenting the parsed value
-
isNaN
Checks if the given number is NaN (Not-a-Number).Only applies to
FloatandDoublevalues. If the number is an instance ofDynamicNumber, it will be unwrapped first.- Parameters:
number- the number to check- Returns:
trueif the number isNaN,falseotherwise
-
isInfinite
Checks if the given number is positive or negative infinity.Only applies to
FloatandDoublevalues. If the number is an instance ofDynamicNumber, it will be unwrapped first.- Parameters:
number- the number to check- Returns:
trueif the number isInfinityor-Infinity,falseotherwise
-
isAssignableFrom
Determines whether a value of the given runtime class can be assigned to a target type using relaxed numeric and primitive compatibility rules.This method extends
Class.isAssignableFrom(Class)semantics by:- Normalizing primitive types to their boxed equivalents
- Allowing numeric widening conversions between
Numbertypes based on a predefined numeric rank hierarchy
Two types are considered compatible if:
- They are equal after primitive normalization, or
- Both are subclasses of
Numberand the value type’s numeric rank is less than or equal to the target type’s numeric rank
If either
valueClassortargetTypeisnull, this method returnsfalse.- Parameters:
valueClass- the runtime class of the value being assignedtargetType- the desired target type- Returns:
trueif a value ofvalueClasscan be assigned totargetTypeunder these rules;falseotherwise
-
numericRank
Returns the numeric rank of a class to determine widening order.The hierarchy is:
Byte: 1 Short: 2 Integer: 3 Long: 4 BigInteger: 5 Float: 6 Double: 7 BigDecimal: 8
Any unknown numeric class returnsInteger.MAX_VALUE.- Parameters:
clazz- the numeric class- Returns:
- the rank of the numeric type
-
isByte
public boolean isByte()Checks if the value is aByte.- Returns:
- true if the underlying value is a Byte
-
isShort
public boolean isShort()Checks if the value is aShort.- Returns:
- true if the underlying value is a Short
-
isInt
public boolean isInt()Checks if the value is anInteger.- Returns:
- true if the underlying value is an Integer
-
isLong
public boolean isLong()Checks if the value is aLong.- Returns:
- true if the underlying value is a Long
-
isBigInteger
public boolean isBigInteger()Checks if the value is aBigInteger.- Returns:
- true if the underlying value is a BigInteger
-
isInteger
public boolean isInteger()Checks if the value is an integral integer type (Byte, Short, Integer, Long, or BigInteger).- Returns:
- true if the value is an integral number
-
isFloat
public boolean isFloat()Checks if the value is aFloat.- Returns:
- true if the underlying value is a Float
-
isDouble
public boolean isDouble()Checks if the value is aDouble.- Returns:
- true if the underlying value is a Double
-
isBigDecimal
public boolean isBigDecimal()Checks if the value is aBigDecimal.- Returns:
- true if the underlying value is a BigDecimal
-
isDecimal
public boolean isDecimal()Checks if the value is a floating point type (Float, Double, or BigDecimal).- Returns:
- true if the value is a decimal number
-
intValue
public int intValue()Returns the value as an int. -
longValue
public long longValue()Returns the value as a long. -
floatValue
public float floatValue()Returns the value as a float.- Specified by:
floatValuein classNumber- Returns:
- the float value
-
doubleValue
public double doubleValue()Returns the value as a double.- Specified by:
doubleValuein classNumber- Returns:
- the double value
-
asBigInteger
Returns the value as aBigInteger.If the underlying value is not already a BigInteger, it converts by parsing the string representation.
- Returns:
- the BigInteger representation
-
asBigDecimal
Returns the value as aBigDecimal.Converts from BigInteger or parses from string if needed.
- Returns:
- the BigDecimal representation
-
get
Returns the underlyingNumbervalue.- Returns:
- the wrapped numeric value
-
set
Sets the underlying value.- Parameters:
value- the new numeric value- Returns:
- this
DynamicNumberinstance for chaining
-
promote
Promotes the number to the next wider numeric type.- Byte -> Short
- Short -> Int
- Int -> Long
- Long -> BigInteger
- Float -> Double
- Double -> BigDecimal
- Returns:
- a promoted
DynamicNumber, or this if no promotion
-
normalize
Normalizes the internal number value to the smallest suitable numeric type.This method simplifies the internal representation of the number when possible:
- Converts a
BigDecimalwith no fractional part to aBigInteger - Downcasts a
BigIntegertolongif it fits - Downcasts integral
longvalues toint,short, orbyteif within range - If floating point support is enabled via
normalize(boolean), it also tries to:- Convert
Doublevalues toFloatif within precision range - Convert whole
FloatorDoublevalues to integral types
- Convert
- Returns:
this, after normalizing the value in place- See Also:
- Converts a
-
normalize
Normalizes the internal number to the most compact numeric type possible, optionally including support for floating point number simplification.The normalization process works as follows:
BigDecimal: If it has no fractional part, it's converted toBigIntegerBigInteger: Downcast tolongif it fits (bit length ≤ 63)long: Downcast toint,short, orbyteif within rangeDouble/Float: IfprocessFloatingNumbersistrue, and:- It's a finite, whole number → convert to
longand then normalize further Doublefits inFloatrange → convert toFloat
- It's a finite, whole number → convert to
Special floating-point values like
NaNorInfinityare preserved and skipped.- Parameters:
processFloatingNumbers- whether to process and simplifyFloat/Doubletypes- Returns:
this, after normalizing the value in place
-
equals
Compares thisDynamicNumberto another object for equality.Equality is based on numeric value comparison using
NumberUtils.equals(T, T). -
hashCode
public int hashCode()Returns the hash code of the underlying numeric value. -
toString
Returns the string representation of the numeric value. -
isNaN
public boolean isNaN()Checks if the internal value is a floating-point NaN (Not-a-Number).- Returns:
trueif the value is NaN, otherwisefalse- See Also:
-
isInfinite
public boolean isInfinite()Checks if the internal value is positive or negative infinity.- Returns:
trueif the value isInfinityor-Infinity, otherwisefalse- See Also:
-
clone
Creates and returns a copy of thisDynamicNumber.This performs a shallow clone. If your subclass adds mutable fields, ensure they are also copied to prevent shared state.
- Overrides:
clonein classObject- Returns:
- a cloned copy of this instance
- Throws:
NaftahBugError- if cloning fails unexpectedly
-
compareTo
- Specified by:
compareToin interfaceComparable<DynamicNumber>
-
isAssignableFrom
Checks if the current numeric value can be assigned to the specified target type.This is a strict numeric assignability check for
Numbervalues. It allows "widening" conversions only, according to the following hierarchy:Byte < Short < Integer < Long < BigInteger < Float < Double < BigDecimal
For example, aBytevalue can be assigned toInteger, but anIntegervalue cannot be assigned toByte.- Parameters:
targetType- the targetClassto check against; must not be null- Returns:
trueif the value can be safely assigned totargetType,falseotherwise
-