Java基础之基本数据类型与String

语法基础

8种基本数据类型

基本类型是不同于类(Class)的特殊类型,在栈内存中管理

  • 字符型 char

  • 布尔型 boolean

  • 数值型
    不存在无符号的整型,范围也是固定的与环境无关

    • 整型
      • byte 一个字节存储,范围-128~127,初始化时默认为0
      • short 两个字节存储,范围-32768~32767,初始化时默认为0
      • int 四个字节存储,范围-2147483648~2147483647,初始化默认为0
      • long 八个字节存储,范围-9223372036854775808~9223372036854775807,初始化默认为0L
    • 浮点型
      • float
      • double

自动拆装箱

包装类型(Wrapper Class)

解决基本类型不面向对象(不继承Object)的缺陷,丰富了基本类型的操作

基本数据类型包装类
byteByte
booleanBoolean
shortShort
charCharacter
intInteger
longLong
floatFloat
doubleDouble
拆箱与装箱

将基本类型和包装类型(箱指代包装类型)转换

在Java SE5 前实现装箱需要手动new一个包装类
在Java SE5 后实现了自动的装箱和拆箱

原理:
自动装箱都是通过包装类的 valueOf() 方法来实现的。
自动拆箱都是通过包装类对象的 xxxValue() 来实现的。

自动拆装箱与缓存

如果一个变量 p 的值是:

  • -128 至 127 之间的整数
  • true 和 false 的布尔值
  • \u0000 至 \u007f 之间的字符

那么将p包装成a、b两个对象时,可以直接使用a==b判断a和b值是否相等,但是超过范围还是要用equals判断

可以通过java.lang.Integer.IntegerCache.high设置缓存最大值

其他类型的缓存机制也类似

自动拆装箱带来的问题
  • 逻辑运算更复杂
  • 如果包装对象为null,则可能拆箱时出现空指针错误
  • 大量的拆装箱操作会浪费资源

布尔型接口最佳实践

成员变量名用 success 不加is前缀,存在序列化时出错的可能,自动生成set和get方法时也会有问题

类型用包装类,没有初值时是null,会抛出错误

String

字符串的不可变性

不可变对象:创建之后内部状态保持不变的对象,既不能更新引用也不能改变内部状态

正常的改变String变量实际上是创建了新的字符串

为什么设计成不可变
  • 缓存
    大量字符串的创建非常耗费资源,利用对字符串的缓存功能可以节省大量堆空间
    JVM中专门开辟了一个空间存储字符串,称为字符串池
  • 安全性
    字符串不可修改来保存各种信息安全性更高
  • 线程安全
    多线程访问字符串或者更改字符串时,只会创建值不会修改值
  • hashcode缓存
    不可变性保证了字符串的值不会改变。因此,hashCode()方法在String类中被重写,以方便缓存,这样在第一次hashCode()调用期间计算和缓存散列,并从那时起返回相同的值。
  • 性能
    因为字符串不可变,所以可以用字符串池缓存,可以大大节省堆内存。而且还可以提前对hashcode进行缓存,更加高效
subString()方法

subString(int beginIndex, int endIndex) 方法的作用:
截取字符串并返回其[beginIndex,enIndex-1]范围内的内容

  • JDK6中的subString:
    在JDK6中String类包含三个成员变量:char valuep[], int offset,int count,分别存储真正的字符串数组,字符串第一个位置的索引,以及字符串的长度。
    调用subString方法时,创建新的String对象,但是string的value指向堆中的同一个字符数组,只有count和offset不同
    导致的问题:一个字符串被反复引用,无法被回收,可能导致内存泄漏
  • JDK7中的subString:
    为了解决JDK6中内存泄漏的风险,JDK7中subString方法会创建一个新的数组
replace相关方法

都用于替换字符

  • replace(CharSequence target,CharSequence replacement):用replacement替换所有的target,两个参数都是字符串

  • replaceAll(String regex,String replacement):replacement替换所有的regex匹配项,其中regex是个正则表达式,replacement是字符串

  • replaceFirst(String regex,String replacement):与replaceAll基本一致,但是只替换第一个匹配的部分

String的拼接
使用+拼接

Java中+对字符串进行拼接,类似于对运算符重载,但其实Java是不支持运算符重载的,这仅仅是一种语法糖。

底层的拼接是靠向StringBuilder中添加字符串然后toString
特殊情况:如果是两个字面量拼接,那么在编译期就会用一个拼接后的字符串(如 “a”+“b” 用"ab"替代)

阿里巴巴Java开发手册中不建议在循环体里使用+进行字符串拼接

concat方法

用法: String 拼接后string = string.concat(“字符串”).concat(String对象);

底层实现:先创建字符数组,后将待拼接的对象的字符串值复制到数组中,最后返回Stirng对象,本质上也是new了一个新的String

StringBuffer

String如果理解成字符串常量,那么StringBuffer类就是字符串变量,它的对象是可以扩充和修改的

用法 StringBuffer stringBuffer = stringBuffer对象.append(“字符串”).append(String对象);

底层实现:与Stirng类似的封装了一个字符数组value,但是并不是final的,可以修改,调用append将字符拷贝到内部的value中,如果长度不够还会进行扩展
此外,StringBuffer线程安全的

StringBuilder

用法和StringBuffer基本一致
底层实现也基本一致,但是线程不安全

StringUtils.join

StringUtils由apache.commons提供,其中的join方法可以拼接字符串
用法 StringUtils.join(“字符串”,Strng对象,…);

也可以将数组或集合以拼接符拼接到一起形成字符串如

String []list  ={"Univero","更新Java相关技术文章"};
String result= StringUtils.join(list,",");
System.out.println(result);
//结果:Univero,更新Java相关技术文章

底层实现:底层也是通过StringBuilder实现的

StringJoiner

StringJoiner是java.util包中的一个类,用于构造一个由分隔符分隔的字符序列(可选),并且可以从提供的前缀开始并以提供的后缀结尾。虽然这也可以在StringBuilder类的帮助下在每个字符串之后附加分隔符,但StringJoiner提供了简单的方法来实现,而无需编写大量代码。

用法:StringJoiner(CharSequence delimiter,CharSequence prefix,CharSequence suffix),参数依次为分隔符、前缀、后缀
拼接时使用add()方法,用法与StringBuilder的append方法类似

底层实现:依赖于StringBuilder

为什么使用StringJoiner:
可以简化Stream通过Collectors.joining(CharSequence)拼接字符串,如

list.stream().collect(Collectors.joining(":"));

Java 8中提供了StringJoiner来丰富Stream的用法,而且StringJoiner也可以方便的增加前缀和后缀。

效率比较

StringBuilder < StringBuffer < concat < + < StringUtils.join

+ 每次都要创建StirngBuilder,再将StringBuilder,再进行append,会耗费更多的时间
所以,阿里巴巴Java开发手册建议:循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。而不要使用+。

1、如果不是在循环体中进行字符串拼接的话,直接使用+就好了。

2、如果在并发场景中进行字符串拼接的话,要使用StringBuffer来代替StringBuilder。

3、如果是通过一个List进行字符串拼接,则考虑使用StringJoiner。

String.valueOf 和 Integer.toString的区别
int i = 5;

String i1 = "" + i;
String i2 = String.valueOf(i);
String i3 = Integer.toString(i);

上述三种方式都可以将int类型转换成字符串
第一种方法其实是String i1 = (new StringBuilder()).append(i).toString();
而第二种和第三种方法没有区别,因为String.valueOf(i)也是调用Integer.toString(i)来实现的。

switch对String类型的支持

字符串的switch是通过equals()和hashCode()方法来实现的。记住,switch中只能使用整型,比如byte。short,char(ASCII码是整型)以及int。而hashCode返回的是int

String的长度限制

字符串有长度限制,在编译期,要求字符串常量池中的常量不能超过65535,并且在javac执行过程中控制了最大值为65534。

在运行期,长度不能超过Int的范围,否则会抛异常。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值