Integer源码分析——下(jdk11)

Integer与原生类型转换

Integer提供了几个与原生类型转换的方法:

 public int intValue() {
        return value;
  }

    public long longValue() {
        return (long)value;
    }

    public float floatValue() {
        return (float)value;
    }

    public double doubleValue() {
        return (double)value;
    }

由上面的源码可知,Integer类型转换原生类型,只需要把value进行对应类型的强制转换即可,因为Integer中实际存储的值存储在value变量中。

Integer.getInteger(String nm)

getInteger是Integer的静态方法,参数nm是系统变量key,即从系统变量nm读取字符串,然后再转换为对应的Integer,此方法有3个重载方法:

public static Integer getInteger(String nm) 
public static Integer getInteger(String nm, int val)
public static Integer getInteger(String nm, Integer val) 

这三个方法中,后面两个方法提供了一个默认值,当nm的系统变量为null,返回方法传入的默认值val

下面重点分析getInteger(String nm, Integer val)的实现逻辑,因为其他两个方法的实现,都是通过调用此方法来实现的:

 public static Integer getInteger(String nm, Integer val) {
        String v = null;
        //获取系统变量nm的值
        try {
            v = System.getProperty(nm);
        } catch (IllegalArgumentException | NullPointerException e) {
        }
        //当v不为null的时候,调用Integer.decode(v)方法
        if (v != null) {
            try {
                return Integer.decode(v);
            } catch (NumberFormatException e) {
            }
        }
        //如果v==null,返回默认值
        return val;
}

程序中使用System.getProperty(nm);获取的系统变量,通常是程序,用户,jvm等相关信息,如果用户想要设置自定义的系统变量,通常可以在启动程序的时候,使用下面的方法:java -jar JarName -DpropertyName=value
propertyName就是用户设置的系统变量的key

下面介绍一下Integer.decode(v)的实现原理

public static Integer decode(String nm) throws NumberFormatException {
        //表示进制 8, 10,16,默认是10
        int radix = 10;
        //字符串的当前位置
        int index = 0;
        boolean negative = false;
        Integer result;

        if (nm.length() == 0)
            throw new NumberFormatException("Zero length string");
        //获取nm的第一个字符,然后判断是正数还是负数
        char firstChar = nm.charAt(0);
        if (firstChar == '-') {
            negative = true;
            index++;
        } else if (firstChar == '+')
            index++;

        //然后获取除了符号位之后的数字字符串的开头几个字符,
        //来判断数字的进制形式
        if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
            index += 2;
            radix = 16;
        }
        else if (nm.startsWith("#", index)) {
            index ++;
            radix = 16;
        }
        else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
            index ++;
            radix = 8;
        }
        
        if (nm.startsWith("-", index) || nm.startsWith("+", index))
            throw new NumberFormatException("Sign character in wrong position");
        //对字符串经过上面步骤的校验,获取nm代表字符串的进制和数字字符串,
        //通过调用Integer.valueOf对nm进行真正的字符到数字的转换,
        //Integer.valueOf具体实现原理参考:[Integer源码分析——上 (jdk11)]
        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? Integer.valueOf(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            String constant = negative ? ("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }
        return result;
}

Integer源码分析——上 (jdk11)

注意这里进行了两步转换:


result = Integer.valueOf(nm.substring(index), radix);
result = negative ? Integer.valueOf(-result.intValue()) : result;
 

由于nm.substring(index)是去掉了正负符号和进制类型,因此第一次调用valueOf得到的是正数。如果nm表示的负数,然后需要第二步进行一个正负转换。

这里注意的是当抛出NumberFormatException异常是,会执行下面两行代码:

String constant = negative ? ("-" + nm.substring(index))
                                       : nm.substring(index);
result = Integer.valueOf(constant, radix);

这里的原理呢?
当nm="-2147483648",在执行Integer.valueOf(nm.substring(index), radix)的时候,nm.substring(index)的结果是"2147483648",由于int类型值得范围是:

-2147483648<=int<=2147483647

而因此在执行Integer.valueOf("2147483648", 10),会抛出异常NumberFormatException,因为"2147483648"在转换的时候出现了溢出,因此需要通过String constant = negative ? ("-" + "2147483648") : "2147483648"; 把"2147483648"转换为"-2147483648",然后再调用Integer.valueOf("-2147483648", radix);
这样的处理方法可以正确的解决"-2147483648"转为int的溢出问题。

Integer常用的方法的实现原理就分析到这里,谢谢!

你可能感兴趣的:(Integer源码分析——下(jdk11))