专业编程基础技术教程

网站首页 > 基础教程 正文

java基础知识回顾-八大基本类型和String类型

ccvgpt 2024-07-26 00:16:43 基础教程 12 ℃

在我们面试过程中经常会提到八大基本类型。那么有哪些八大基本类型呢?以及他们的封装类又是什么呢?

首先,我们熟知的八大基本类型是:int,short,float,double,long,boolean,byte,char;因为java是面向对象的一门语言,所以这八大基本类型都有对应的封装类:Integer,Short,Float,Double,Long,Boolean,Byte,Character。

java基础知识回顾-八大基本类型和String类型

这八大基本类型与其对应的封装类型之间的赋值使用自动装箱和拆箱完成。

Java虚拟机处理基础类型与引用类型的方式是不一样的,对于基本类型,Java虚拟机会为其分配据类型实际占用的内存空间,而对于引用类型变量,他仅仅是一个指向堆区中某个实例的指针。


// 基本数据类型int自动装箱为Integer包装类
// (实际上在编译时会调用Integer .valueOf方法来装箱)int b = a;
// 自动拆箱(实际上会在编译调用intValue)
Integer a = 1;

那么 new Integer(123)与 Integer.valueOf(123) 有什么区别?

new Integer(123) 每次都会创建一个新对象,而 Integer.valueOf(123) 使用到了缓存对象,因此多次使用 Integer.valueOf(123) 时,只会取得同一个对象的引用。


Integer num1 = new Integer(123);
Integer num2 = new Integer(123);
System.out.println(num1 == num2 ); // 输出false
Integer num3 = Integer.valueOf(123);
Integer num4 = Integer.valueOf(123);
System.out.println(num3 == num4 ); // 输出true

编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。


Integer a = 127;Integer b = 127;
System.out.println(num1 == num2 ); // 输出true
Integer c = 128;Integer d = 128;
System.out.println(num3 == num4 ); // 输出false

这是为什么呢?我们查看Integer类的源码发现,使用 valueOf()时,先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。但是在Integer中,缓存池的范围为: -128 ~ 127


 public static Integer valueOf(int i) {
 if (i >= IntegerCache.low && i <= IntegerCache.high)
 return IntegerCache.cache[i + (-IntegerCache.low)];
 return new Integer(i);
 }



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() {}
 }

String类型:

java.lang.String类使用了final修饰,不能被继承。Java程序中的所有字面值,即双引号括起的字符串,如"abc",都是作为String类的实例实现的。String是常量,其对象一旦构造就不能再被改变。换句话说,String对象是不可变的,每一个看起来会修改String值的方法,实际上都是创造了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。String对象具有只读特性,指向它的任何引用都不可能改变它的值,因此,也不会对其他的引用有什么影响。但是字符串引用可以重新赋值。java字符串在内存中采用unicode编码方式,任何一个字符对应两个字节的定长编码,即任何一个字符(无论中文还是英文)都算一个字符长度,占用两个字节。


public final class String
 implements java.io.Serializable, Comparable<String>, CharSequence {
 /** The value is used for character storage. */
 private final char value[];

那么知道String不可变性,那这样设计有什么好处呢?

1.字符串池的需要

字符串常量池(String intern pool) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时。假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。Java为了提高性能,静态字符串(字面量/常量/常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串。对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果常量池中存在即返回该对象。

2.允许String对象缓存HashCode

Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。

字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存。这也是一种性能优化手段,意味着不必每次都去计算新的哈希码

3.安全性

String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等,假若String不是固定不变的,将会引起各种安全隐患。

4.线程安全

String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

String是不可变,那么有没有可变的字符串呢?

在Java中提供了StringBufferStringBuilder,是可变的。在String中,定义的是一个final字符数组,所以不可变,而StringBuffer和StringBuilder因为继承了AbstractStringBuilder,根据源码可看出是一个可变的字符数组。

根据点击进去的源码还可以知道,StringBuffer是线程安全的,其中的方法都被synchronized所修饰。


最后,我自己是一名从事了多年开发的Java老程序员,辞职目前在做自己的Java私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的Java学习干货,可以送给每一位喜欢Java的小伙伴,想要获取的可以关注我的头条号并在后台私信我:01,即可免费获取。

Tags:

最近发表
标签列表