java基础知识--java数据类型相关

今天无意间看到脉脉上有人说自己面试遇到面试官问基础数据类型相关的问题竟然没回答出来,我也是笑了,自认为不敢说基础知识有多扎实,但是基本得一些东西还是知道的,这里写下来仅供参考

1. 基础数据类型以及他们的大小:

byte、short、int、long、float、double、char、boolean

先说下单位大小的换算,位:bit,计算机中最小单位,1bit能表示两个数据结果,如true和false,二进制的0和1;字节byte,1byte=8bit,所以1字节可以表示的结果数量是2的8次方,即256种结果。

int 4字节,即可以表示2的32次方个结果,所以int有符号的取值范围为2^31-1 ~ -2^31

short 2个字节,即可以表示2的16次方个结果,所以可以表示无符号整数 -32768~32767之间的任意整数 

long: 8个字节,64位带符号整数 -2^63到2^63-1之间的任意整数
float:4个字节,double: 8 个字节(这个取值范围我是记不住,数字太大)

char是2个字节,能够表示2的16次方个结果,所以一个char类型的可以存储一个汉字

boolean是1bit,结果只有true和false

基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成,如int和Integer转换,long转换到Long转换,下面用一个最简单的例子解释装箱和拆箱:

Integer x = 2;     // 装箱
int y = x;         // 拆箱

既然说到封装类型,那就不得不说下缓冲池的实现,敲黑板,必考题。

Integer类型当中,如果是-128~127之间的值,使用valueof()获取的结果必然是相等的,因为会使用缓存池中的对象,多次调用会取得同一个对象的引用;但是如果使用了new Integer(124)方式创建出来的则是不同的对象,结果必然不相等,看样例:

Integer x = new Integer(123); 

Integer y = new Integer(123); 

System.out.println(x == y); // false 

Integer z = Integer.valueOf(123); 

Integer k = Integer.valueOf(123); 

System.out.println(z == k); // true

valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。

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

在 Java 8 中,Integer 缓存池的大小默认为 -128~127,即上面的IntegerCache.low 和 IntegerCache.high分别为-128和127。

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

Integer m = 123;
Integer n = 123;
System.out.println(m == n); // true

Integer i = 129;
Integer j = 129;
System.out.println(i == j); // false

String类型

String 被声明为 final,因此它不可被继承。

内部使用 char 数组存储数据,该数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。

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

 

String声明为final不可变的好处

1. 可以缓存 hash 值

因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。

2. 性能

如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。对于相同的String对象,可以重复使用String pool。

3. 安全性

String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。

4. 线程安全

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

String, StringBuffer and StringBuilder

1. 可变性

  • String 不可变
  • StringBuffer 和 StringBuilder 可变

2. 线程安全

  • String 不可变,因此是线程安全的,性能介于下面两者之间,每次字符串操作会重新生成一个String对象
  • StringBuilder 不是线程安全的,效率高,常使用在字符串操作比较频繁的场景
  • StringBuffer 是线程安全的,内部使用 synchronized 进行同步,但是效率低

String.intern()

使用 String.intern() 可以保证相同内容的字符串变量引用同一的内存对象。

下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同对象,而 s3 是通过 s1.intern() 方法取得一个对象引用。intern() 首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。

String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);           // false
String s3 = s1.intern();
System.out.println(s1.intern() == s3);  // true

如果是采用 "bbb" 这种使用双引号的形式创建字符串实例,会自动地将新建的对象放入 String Pool 中。

String s4 = "bbb";
String s5 = "bbb";
System.out.println(s4 == s5);  // true

 

运算

参数传递

Java 的参数是以值传递的形式传入方法中,而不是引用传递。

以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。在将一个参数传入一个方法时,本质上是将对象的地址以值的方式传递到形参中。因此在方法中改变指针引用的对象,那么这两个指针此时指向的是完全不同的对象,一方改变其所指向对象的内容对另一方没有影响。

public class Dog {
    String name;

    Dog(String name) {
        this.name = name;
    }

    String getName() {
        return this.name;
    }

    void setName(String name) {
        this.name = name;
    }

    String getObjectAddress() {
        return super.toString();
    }
}
public class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        func(dog);
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        System.out.println(dog.getName());          // A
    }

    private static void func(Dog dog) {
        System.out.println(dog.getObjectAddress()); // Dog@4554617c
        dog = new Dog("B");
        System.out.println(dog.getObjectAddress()); // Dog@74a14482
        System.out.println(dog.getName());          // B
    }
}

但是如果在方法中改变对象的字段值会改变原对象该字段值,因为改变的是同一个地址指向的内容。

class PassByValueExample {
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        func(dog);
        System.out.println(dog.getName());          // B
    }

    private static void func(Dog dog) {
        dog.setName("B");
    }
}

隐式类型转换

1.1 字面量属于 double 类型,不能直接将 1.1 直接赋值给 float 变量,因为这是向下转型。Java 不能隐式执行向下转型,因为这会使得精度降低,需要使用1.1f

float f = 1.1;// 报错
float f = 1.1f;

字面量 1 是 int 类型,它比 short 类型精度要高,因此不能隐式地将 int 类型下转型为 short 类型,但是能使用+=进行隐式类型转换

short s1 = 1;
// s1 = s1 + 1;
s1 += 1;// 相当于s1 = (short) (s1 + 1);

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值