Java数据类型转换

基本类型转换

byte a = 127,b=1;
//byte c = a + b; // 编译无法识别变量的数据类型 Required type:byte; Provided:int
System.out.println(a + b);//128 整数的数据类型默认为byte
byte d = (byte)(a + b);  //强制类型转换 位数多 -> 位数少
System.out.println(d); // -128

# 基本数据类型和包装数据类型 > 对原文章的逻辑做了重新梳理 > [cloud.tencent.com/developer/article](https://cloud.tencent.com/developer/article/1512392)

基本数据类->包装数据类型 叫装箱.反过来叫拆箱.
Java 5引入自动拆箱和装箱. 发生在编译器,错误提示在编译器.
image.png

自动装箱
Integer value=10; //int直接赋值Integer合法,由编译器实现
自动拆箱
int value=new Integer(10);  //int value=0; new Integer(10); value指向new Integer(10)

自动拆箱和装箱的时机
int a1 = 1;
Integer a2 = 1;
System.out.println(a2.equals(a1)); // equals(Object obj)  Object是对象 a1自动装箱
a1=a1+a2;  or  a2=a1+a2; // 算术运算自动拆箱
//自动装箱和拆箱的实现 jdk1.8 Integer 数据类型转换valueOf(),xxValue()
public final class Integer extends Number implements Comparable<Integer> {
    private final int value; //final 表示Integer对象一经构造完成,它代表的值不再变
    
    //构造函数
    public Integer(int value) {
        this.value = value;
    }
    
    //重写equals方法,比较两个Integer对象的value,来判断是否相等
    public boolean equals(Object obj) { 
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

     /**
     * 内部静态类,缓存数据,保存Integer数组
     * low  缓存数据最小值 固定为-128
     * high 缓存数据最大值 默认为127.[127,Integer.MAX_VALUE - (-low) -1]
     * high >最大值,则cache.length>Integer.MAXVALUE,则溢出
     * cache[]保存[low,high]所对应的Integer对象,长度是high-low+1(因为有元素0,所以要加1)
     */
    private static class IntegerCache {
        static final int low = -128; //缓存数据最小值
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }
    
    /**
     * 基本数据类型->包装数据类型
     * 先判断i是否在[low,high]之间
     * Y,则复用Integer.cache[i-low].如果Integer.valueOf(3),直接返回Integer.cache[131]
     * N, 调用构造方法,构造出一个新的Integer对象
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    
    /**
     * 包装数据类型->基本数据类型
     * 先判断i是否在[low,high]之间
     * 直接返回值
     */
    public int intValue() {
        return value;
    }
}

基本数据类型和包装数据类型判等:
Integer a1 = 1; 
Integer a2 = 1; 
Integer a3 = new Integer(1); 
System.out.println(a1 == a2); //true,因为a1和a2是同一个对象,都是Integer.cache[129] 
System.out.println(a1 == a3);//false,a3构造了一个新的对象,不同于a1,a2 
System.out.println(a3.equals(a1));//true,比较值


基本数据类型缓存(常量(对象)池)

同类型比较,数据类型在缓存范围内才发生自动装箱和拆箱

Integer a1 = 128,a2 = 128;
System.out.println(a1 == a2); //false Integer 范围为[-128,127]
Integer a3 = -128,a4 = -128;
System.out.println(a3 == a4); //true  

Byte b1 = 127,b2 = 127;
System.out.println(b1 == b2); //true Byte 范围为[-128,127]
Byte b3 = -128,b4 = -128;
System.out.println(b3 == b4); //true 

Long c1 = 128L,c2 = 128L;
System.out.println(c1 == c2); //false Long 范围为[-128L,127L]
Long c3 = -128L,c4 = -128L;
System.out.println(c3 == c4);//true

Character d1 = 128,d2 = 128;
System.out.println(d1 == d2); // false Long 范围为[0,127]
Character d3 = 127,d4 = 127;
System.out.println(d3 == d4);// true
System.out.println(d1); //€  打印的是字符,如图

Double和Float是连续不可数的.就是比较值.

Boolean没有自动装箱与拆箱.

不同类型比较
Integer i = 10;
Byte b = 10;
// System.out.println(i == b); //Byte和Integer.两个对象无法直接比较,报错
System.out.println("i == b " + i.equals(b)); // false  包装类先比较是否是同一个类,不是的话直接返回false.
int ii = 128;
short ss = 128;
long ll = 128;
char cc = 128;
System.out.println("ii == ss " + (ii == ss)); // true 基本数据类型直接比较值,值一样就可以
System.out.println("ii == ll " + (ii == ll)); // true
System.out.println("ii == cc " + (ii == cc)); // true

image.png

String

参考https://blog.csdn.net/a724888/article

  1. 直接赋值- 产生一个实例化对象。一个匿名对象被引用。
 String s2="aaa";//直接赋值,匿名对象自动保存到字符串常量池中
 String s3="aaa";
 System.out.println(s2==s3);//true,两个对象指向同一个堆内存空间。 

  1. 构造方法赋值-产生两个实例化对象
String s="aaa";//直接赋值
String s1=new String("aaa");//构造方法实例化,匿名对象将成为垃圾空间
System.out.println(s==s1);// false,比较地址。直接赋值自动入池。实例化new不会入池。
System.out.println(s.equals(s1));//true,比较内容

String s2=new String("aaa").intern();//实例化方法手工入池 public String intern(); s2指向池
System.out.println(s==s2);//true 地址

String s3=new String("aaa");
s3.intern(); //s3指向new区,s3.intern()将new区的内容入池,但s3依旧指向new区
System.out.println(s==s3);//false
String s3=new String("aaa"); 
s3.intern();    //false 地址


由上,为避免产生垃圾,String实例化要直接赋值。

匿名对象
null.equals():运行时异常NullPointerException。可看出,匿名对象一定是开辟好堆内存空间的对象

+ 连接对象-- 同时可以得出,运算时,编译期可识别常量,不可识别变量。要知道
要知道,避免使用魔法值,+做字符串连接,用StringBuilder
String s="aaa";//直接赋值
String s2="a"+"a"+"a";//表达式都为常量,编译期自动处理字符串连接,s2是整体存在,不会产生内存垃圾.
System.out.println(s==s2);// True 地址判断,,数据加载时,值相同。

静态常量池和运行时常量池
String value="a"; String s3="a"+"a"+value; //表达式有变量,运行期计算,地址不一样。
System.out.println(s==s3);//false 地址判断  s3在静态常量池,s4在运行时常量池。

String不可变

不可变的含义: 修改数据会指向新地址.



不可变的优势 --String很常用
cnblogs.com/cangwei22/p/10582600

  1. 避免一个变量改变池中的共享数据
String a="abc"; 
String b="abc";
System.out.println(a==b); //true 共用池中数据,避免产生垃圾空间。

b="a";
System.out.println("a:"+a+"; b:"+b); //a:abc; b:a   b要改变值,不能直接改变池中数据,
//需要定义String为 final ,避免池中数据改变,影响指向池中
  1. String作为HashMap的key, String的不可变保证了hash值的不可变。
  2. String作为网络连接的参数,String的不可变性提供安全性。
  3. String不可变,线程安全。

不可变的实现
Jdk1.8保存字符数组private final char[] value;jdk1.9保存字节数组private final byte[] value;

final int[] value={1,2,3};
int[] another={4,5,6};
//value=another;    //编译报错,但真正不可变是 编译器不允许把value指向堆区另一个地址。
value[2]=100;  
System.out.println(Arrays.toString(value)); //[1, 2, 100] 
  1. 持有String对象的引用本身是可以改变的,比如可以指向其他的对象。
  2. final只能保证类不可被继承,类的对象在堆内存中的地址不会被改变。
  3. final修饰的char数组保证了char数组的引用不可变。但是可以通过char[0] = 'a'来修改值。不过String内部并不提供方法来完成这一操作,所以String的不可变是基于代码封装和访问控制的。


StringBuffer和StringBuilder

+ 连接对象,有变量运算用StringBuilder。无变量运算用String
String a = "a";
a = a + a;//计算变量,运行时计算, 先把a封装成StringBuilder,调用append方法,返回toString。生成大量StringBuilder实例
String a2 = "a"+"a";//计算无变量,编译期直接合成"aa",直接引用"aa",

StringBuilder 和StringBuffer 继承自AbstractStringBuilder。AbstractStringBuilder定义为 char[] value,定义了字符串的基本操作:append,insert,indexof;
安全性:String内容不可变,相当于常量,可看作线程安全。StringBuilder线程不安全,有10%-15%的性能提升。StringBuffer加同步锁,线程安全。
多用StringBuilder。 StringBuilder常用方法

Java9改进了字符串(包括String、StringBuffer、StringBuilder)的实现。在Java9以前字符串采用char[]数组来保存字符,因此字符串的每个字符占2字节;而Java9的字符串采用byte[]数组再加一个encoding-flag字段来保存字符,因此字符串的每个字符只占1字节。所以Java9的字符串更加节省空间,字符串的功能方法也没有受到影响。
原文链接:https://blog.csdn.net/csxypr/article/details/92378336

posted @ 2020-06-11 08:16  wana  阅读(300)  评论(0编辑  收藏  举报