Java面试题(基础)-数据类型

  • Java中的数据类型有哪些?

Java中的数据类型分为基本数据类型和引用数据类型两大类;

基本数据类型4类(整形、浮点型、布尔型、字符型)8种{byte(1个字节)、short(2个字节)、int(4个字节)、long(8个字节)、float(4个字节)、double(8个字节)、boolean(实现虚拟机不同有所差异)}。

引用数据类型(类、接口、数组、枚举类型)。

1字节=16位,可推算出表示范围,有符号需要去掉符号位(即从负数表示到正数,boolean、char类型除外)数据类型字节数确定也是保证Java程序的可移植,跨平台的基础。

  • char 型变量中能不能存贮一个中文汉字,为什么?

char类型可以存储一个中文汉字,Java中默认使用的编码是Unicode(也叫万国码,能表示英文、中文以及其它国家文件和一些特殊符号等等),Unicode编码是能表示汉字的,一个char类型占2个字节(16比特),放一个中文没问题的。

扩展:使用Unicode意味着字符在JVM内部和外部有不同的表现形式,在JVM内部都是Unicode,当这个字符被从JVM内部转移到外部时(例如存入文件系统中),需要进行编码转换。所以Java中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如InputStreamReader和OutputStreamReader,这两个类是字节流和字符流之间的适配器类,承担了编码转换的任务;

  • equals和 == 的区别?

对于基本数据类型比较的是值,对于引用类型来说 = = 比较的变量是栈内存中存放的地址信息是否相同,用来判断两个对象的地址是否相同,即是否指向相同的对象。equals在重写了equals方法后比较的是值的信息是否相同。equals方法最先比较的就是hashCode方法是否相同,如果一个类没有重写equals方法,则equals和= =的作用是相同的,这是因为所有的类都继承于Object 超类,而Object超类中的equals方法返回是用==判断的。String对象和Integer对象都重写了equals方法。重写equals方法一定也要重写hashcode方法。

扩展:重写hashCode方法和equals方法的几种方式(当然也可以自己重写)

在这里插入图片描述
如下面程序:

public static void main(String[] args) {
    
    
    String s1 = "abc";
    String s2 = new String("abc");
    String s3 = new String("abc");
    System.out.println("s1与s2使用==比较结果:" + (s1 == s2));
    System.out.println("s1.equals(s2)使用equals比较结果:" + s1.equals(s2));
    System.out.println("s2与s3使用==比较结果"+ (s2 == s3));
    System.out.println("s2与s3使用equals比较结果" + s2.equals(s3));
}

程序运行结果:(一定要注意基本数据类型包装类中的常用高频数值范围,可能会出现不一样的结果)
在这里插入图片描述

  • 简述自动装箱拆箱

对于Java基本数据类型,均对应一个包装类。
装箱就是自动将基本数据类型转换为包装器类型,如int->Integer
拆箱就是自动将包装器类型转换为基本数据类型,如Integer->int

  • int和Integer有什么区别?基本数据类型和基本数据类型包装类有什么异同?为什么有基本数据类型还要有基本数据类型包装类?

Java是面向对象的程序设计语言,讲究的是万物皆对象的理念。而基本数据类型在某些场景下无法使用,包装类可以向操作其它类一样简单操作对“基本数据类型进行操作”;
包装类提供了更多更实用的方法,如hashCode方法,equals方法以及valueOf方法等等,功能比基本数据类型丰富。从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
Java 为每个原始类型提供了包装类型:
原始类型: boolean,char,byte,short,int,long,float,double
包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
基本数据类型与基本数据类型比较
1)重写了hashcode和equals方法还有其它比较实用的方法,如valueOf、parseInt、parseDouble、toHexString等数值的常用进制转换方法等等。(使用包装类型进行值比较时,建议使用equals方法,而不是使用==去进行值比较,这是因为包装类型中对一个范围的数字使用了一种类似类似缓存池的东西,下面的例子将会介绍)
2)包装类可以为泛型参数,而基本数据类型不可以。例如我们定义一个List集合时,可以使用包装类型,但是却无法使用基本数据类型。
3)包装数据类型都实现了Serializable接口,所以可以序列化和反序列化。
扩展:
(1)把对象转换为字节序列的过程称为对象的序列化;把字节序列恢复为对象的过程称为对象的反序列化。
(2)对象的序列化主要有两种用途:第一种用途:把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;第二种用途:在网络上传送对象的字节序列。
4)基本数据类型的默认值与基本数据类型的包装类的默认值不同。包装类因为是类,所以包装类的默认值为null;基本数据类型,byte、short、int、long为0,boolean默认为false,float和double为0.0,char类型默认为空(不是null哦)

public class DataTest {
    
    
    public static void main(String[] args) {
    
    
        // 定义了一个字符串,字符串的内容为256
        String numberString = "252";
        // Integer中的parseInt方法返回值类型为Integer
        // 之所以能用int类型去接,是因为自动拆箱,将包装类型拆箱为基本数据类型
        int number = Integer.parseInt(numberString);
        // number 为基本数据类型,进行加4操作,返回的应该是基本数据类型中的int型
        // 之所以能用Integer包装类型去接,是因为自动装箱,将int数据类型自动装箱
        Integer hexInteger = number + 4;
        // 可以对包装类型赋值像给基本数据类型中的int赋值一样,自动装箱
        // int自动装箱调用了Integer中的valueOf方法(请注意此方法)
        // 下面等同于 Integer equalsInteger = Integer.valueOf(256);
        Integer equalsInteger = 256;
        // 这里很容易理解,==比较的是两个对象的地址,hexInteger和equalsInteger
        // 是两个不同的Integer对象,他们的地址是不同的,==比较结果是false
        // 比较结果为false,但是如果我们将数换为64呢?==比较的结果如何???
        System.out.println(hexInteger == equalsInteger);
        // 包装类型都重写了equals方法,所以这里比较的是两个对象的值内容       System.out.println(hexInteger.equals(equalsInteger));
        // 将数字转化为16进制字符串
        System.out.println(Integer.toHexString(hexInteger));
    }
}

程序运行结果如下:
在这里插入图片描述
在上述程序示例中的一个问题,如果我们换成64呢?结果还是一样吗?

public class DataTest {
    
    
    public static void main(String[] args) {
    
    
        // 定义了一个字符串,字符串的内容为60
        String numberString = "60";
        // Integer中的parseInt方法返回值类型为Integer
        // 之所以能用int类型去接,是因为自动拆箱,将包装类型拆箱为基本数据类型
        int number = Integer.parseInt(numberString);
        // number 为基本数据类型,进行加4操作,返回的应该是基本数据类型中的int型
        // 之所以能用Integer包装类型去接,是因为自动装箱,将int数据类型自动装箱
        Integer hexInteger = number + 4;
        // 可以对包装类型赋值像给基本数据类型中的int赋值一样,自动装箱
        // int自动装箱调用了Integer中的valueOf方法(请注意此方法)
        Integer equalsInteger = 64;
        // 比较结果为false,但是如果我们将数换为64呢?==比较的结果如何???
        System.out.println(hexInteger == equalsInteger);
        // 包装类型都重写了equals方法,所以这里比较的是两个对象的值内容
  	 System.out.println(hexInteger.equals(equalsInteger));
        // 将数字转化为16进制字符串     System.out.println(Integer.toHexString(hexInteger));
    }
}

程序输出结果如下:
在这里插入图片描述
这里改为64以后,为什么==比较也是true了呢?
这里就需要对装箱的实现以及装箱的概念有所了解。当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,看看valueOf方法的源码就知道了,valueOf方法源码如下:

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

这里面有一个IntegerCache是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() {
    
    }
}

简单的说,如果整型字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象,超出这个范围的数值才会真正的new一个对象出来。所以上面的两段程序的输出结果是不一样的。
扩展:基本数据类型包装类中的Byte、Short、Integer、Long的高频缓存范围为-128到127;Character的高频缓存为-128到127;Float、Double没有高频缓存区。Integer是唯一一个可以修改高频缓存范围的包装类。通过在VM optons中如下设置:-XX:AutoBoxCacheMax=8866 即修改缓存最大值为8866。
再看如下程序:

public class DataTest {
    
    
    public static void main(String[] args) {
    
    
        int a = 100;
        Integer b = new Integer(100);
        Integer c = new Integer(100);
        System.out.println(a == b);
        System.out.println(a == c );
        System.out.println(b == c);
        System.out.println(b.equals(a));
        System.out.println(c.equals(a));
        System.out.println(b.equals(c));
    }
}

程序运行结果如下:
在这里插入图片描述
a与b、a与c使用= =比较,会将Integer包装类自动拆箱为基本数据类型中的int,进行值比较与a与b、a与c、b与c使用equals(包装类重新了equals方法)方法一样进行的都是值比较,所以是true;而b与c使用==进行比较的结果却为false,这是因为new出来的对象不会使用高频缓存范围的数值,是先创建对象,这两个对象是不同的对象,所以地址是不同的,返回false;(当然这么写代码,如果你的编程软件安装了阿里代码开发检测工具的时候是会有黄色警告的)

  • 在程序中选择包装类还是基本类的原则有哪些?

包装类型比基本数据类型的应用范围更广,同时提供了很多方法,很方便,一般情况下确定是使用基本数据类型还是包装类型原则如下:
1)所有的POJO类属性必须使用包装类;
2)RPC中的方法返回值和参数必须使用包装类;
3)所有局部变量推荐使用基本数据类型;

  • 泛型可以为基本类型吗?为什么?

泛型不能使用基本数据类型。泛型在 JVM(Java虚拟机)编译的时候会类型檫除,比如代码 List list 在 JVM 编译的时候会转换为 List list ,因为泛型是在 JDK 5 时提供的,而 JVM 的类型檫除是为了兼容以前代码的一个折中方案,类型檫除之后就变成了 Object,而 Object 不能存储基本数据类型,但可以使用基本数据类型对应的包装类,所以像 List list 这样的代码是不被允许的,编译器阶段会检查报错,而 List list 是被允许的。

  • 定义变量 float f = 5.2;是否有问题?能否通过编译?**

有问题,不能通过编译;在Java中没小数点的默认是int,有小数点的默认是double。将double转换为float需要进行强制类型转换,如 float f = (float)5.2;或者float f = 5.2f; 表示这是一个float类型的数据。
扩展:隐式转换,即自动转换,它不要求加以声明,是系统默认的。它是由小至大的转换:
byte——>short——>int——>long——>float——>double
char——>int——>long——>float——>double
显式转换,即强制转换,它是由大至小的转换,它的格式为:
类型 变量=(类型) 变量2;

  • short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?**

Java规范有这样的规则:1.高位转低位需要强制转换 2.低位转高位自动转.在Java中没小数点默认的为int类型,1是int 型,s1是 short型,通过加1运算后s1 自动转为int 型,所以要强制转换,改为 s1 = (short)s1 + 1;
short s1 = 1; s1 += 1;正确
这个不会发生类型的提升,JAVA规范上说 :
e1+=e2 实际上是 e1=(T1)(e1+e2) ,其中T1是e1的数据类型。
s1+=1等效于 s1=(short)(s1+1),所以是正确的。

  • Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?**

Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行向下取整。(这其实就是简单的数学概念,明白四舍五入就错不了)

  • 3*0.1==0.3的比较结果?

比较结果为false。浮点数在计算机中不能准确的表示出来,30.1结果输出为0.30000000000000004;
扩展:有的人说在0.1改为0.1f结果就为true了,这里是错误的,因为3
0.1f结果为float,结果为0.3没问题,但是与0.3(小数类型没有显式定义数据类型的话,默认是double)比较,会将float的0.3隐世转换为double类型,还是0.30000000000000004与0.3比较,所以还是false;
测试程序如下:

public static void main(String[] args) {
    
    
    float a = 1.2f;
    double b = a;
    System.out.println(a);
    System.out.println(b);
    System.out.println(3*0.4f);
    System.out.println(1.2);
    System.out.println( (float)(3*0.4)== 1.2);
}

程序输出结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/chen15369337607/article/details/126023298
今日推荐