【JavaSE基础】基本数据类型的包装类及String类

基本数据类型的包装类

Java将基本数据类型值封装成了对象。封装成对象有什么好处?——这样可以提供更多操作基本数值的功能

一般我们对数值的基本操作就是通过运算符来进行运算,但是如果我们想要获得一个数值的二进制,这个就是对数值的更多操作,需要将这些功能封装到对象中。

基本数据类型及其包装类分别为:
byte -> Byte; short -> Short; int -> Integer; long -> Long; float -> Float;
double -> Double; boolean -> Boolean; char -> Character;

以 Integer 为例,在对变量赋值时,Integer类进行了两步操作:
加包:Integer a = Integer.valueOf(10);
拆包:int a = a.intValue();

加包:
即 Integer a = 10;
相当于 Integer a = Integer.valueOf(10);
拆包:
即 int b = a;
相当于 int b = a.intValue();

针对基本数据类型的包装类采用 == 比较是否相等:
Integer内部缓存:-128~127;
Integer部份源码:

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() {}
}
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
public int intValue() {
    return value;
}

如果 -128 < a,b <127 a == b 为 true;
如果a,b不在缓存中,则为 new 新Integer,则a == b 为false;

public class TestDemo{
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);
    }
}

结果:

在这里插入图片描述

public class TestDemo{
    public static void main(String[] args) {
        Integer a = 1000;
        Integer b = 1000;
        System.out.println(a == b);
    }
}

结果:

在这里插入图片描述

原因:Integer类中存在内部缓存:大小为 -128~127;当变量初始化的值在其中时,底层会直接将缓存中的地址赋给变量,所以在 == 比较时两者地址值是一样的,显示true;当变量初始化的值不在其中时,底层会new出新的Integer对象,将其赋值给变量,只要new对象,必有新内存的开辟,两者存储地址不同。在 == 比较时会显示flase;

String类

让我们先看看如何查看Java运行过程的变量值和包装类
在这里插入图片描述
javap -verbose用于查看java文件运行过程中的变量值以及包装类

1. 谈谈对String类的理解

String类:->字符串常量池(>= JDK1.7)

为了减少字符串常量在JVM中的创建。引用字符串常量池:
遇到字符串常量,先去字符串常量池中查找,找到返回常量的地址赋值给str1.如果没找到,给字符串常量池中添加一个新的常量,返回该地址。

  1. String类 底层数据结构:<= JDK1.8 char[]

  2. 字符串比较方法:equals比较
    == 比较字符串常量取值的地址
    equals-> 字符串(char[])

  3. 字符串拼接方式:

    1. 常量+常量 -> 编译器优化 “tu”+“lun” ->“tulun”
    2. 变量+常量 -> String str4 = str+“lun”;
      (1) StringBuilder s = new StringBuilder();
      (2) s.append(str);//字符串拼接操作append
      (3) s.append(“lun”);//s->所指对象"tulun" 对象类型StringBuilder
      (4) String str4 = s.toString();
public class StringTest {
    public static void main(String[] args) {
        String str = "ab";
        String str1 = "abc";
        String str2 = "ab"+"c";
        String str3 = new String("abc");
        String str4 = str+"c";
        System.out.println(str1 == str2);//true
        System.out.println(str2 == str3);//false
        System.out.println(str2 == str4);//false
        System.out.println(str3 == str4);//false
    }
}

由此可见,当常量 + 常量时,编译器对字符串进行了优化,发现常量池中已经存在该字符串,因此将常量池中该值的地址直接赋值给新对象,并未进行新内存的开辟,字符串存储地址未发生改变,所以显示true;而在变量 + 常量时,编译器使用StringBuilder 生成新对象,通过new对象开辟了新内存,其与原变量的地址不同,因此,显示false;

在这里插入图片描述

2. 谈谈String 和 StringBuilder 和 StringBuffer之间的区别
  1. 拼接方式:
    String +
    StringBuilder 、StringBuffer -> .append()
  2. String 变量+常量 -> StringBuilder -> 效率考虑
    (1) 
    String str = "";
	for(int i=0;i<10000;i++){ 
        	str = str+"1";//new  append() toString 
        }
   (2) 
   StringBuilder s = new StringBuilder();
	for(int i=0;i<10000;i++){ 
		s.append("1"); 
	}//s.toString()
      
public class StringTest {
	public static void main(String[] args) {
    		long begin1 = System.currentTimeMillis();
    		String str = "";
    		for(int i=0;i<10000;i++){
        		str = str+"1";//new  append() toString
    		}
   		long end1 = System.currentTimeMillis();
    		System.out.println(end1-begin1);

    		long begin2 = System.currentTimeMillis();
    		StringBuilder s = new StringBuilder();
    		for(int i=0;i<10000;i++){
        		s.append("1");
    		}
    		long end2 = System.currentTimeMillis();
    		System.out.println(end2-begin2);


    		StringBuffer stringBuffer = new StringBuffer();
    		for(int i=0;i<10000;i++){
        		stringBuffer.append("1");
    		}
    	}
}

结果:

在这里插入图片描述
由此可见使用String + 号拼接效率明显低于StringBuilder,因此,如果在进行字符串拼接时,变量+常量的情况下,String的+拼接会new StringBuilder 对象,此时如果拼接次数过多,应该选择StringBuilder,让其在一开始new对象,而不是每拼接一次new一次对象。这样可以提高程序执行的效率。

  1. String StringBuilder -> 多用在单线程环境
    StringBuffer(synchronized) -> 多用在多线程环境
3. == 和 equals在字符串比较上的区别:

1) 对于==,比较的是值是否相等

  • 如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
  • 如果作用于引用类型的变量,则比较的是所指向的对象的地址。

2) 对于equals方法,

  • 注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象。
  • 如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
  • 诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

而在字符串的比较上, == 比较的是两个字符串的地址是否相等,如果想比较字符串中的内容是否相等,此时应该使用equals。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值