第 1-2 课:你不知道的基础数据类型和包装类 + 面试题

基本数据类型

Java 基础数据按类型可以分为四大类:布尔型、整数型、浮点型、字符型,这四大类包含 8 种基础数据类型。

  • 布尔型:boolean
  • 整数型:byte、short、int、long
  • 浮点型:float、double
  • 字符型:char

八种基础类型取值如下:

数据类型代表含义默认值取值包装类
boolean布尔型false0(false) 到 1(true)Boolean
byte字节型(byte)0-128 到 127Byte
char字符型'\u0000'(空)'\u0000' 到 '\uFFFF'Character
short短整数型(short)0-215 到 215-1Short
int整数型0-231 到 231-1Integer
long长整数型0L-263 到 263-1Long
float单浮点型0.0f1.4e-45 到 3.4e+38Float
double双浮点型0.0d4.9e-324 到 1.798e+308Double

除 chat 的包装类 Character 和 int 的包装类 Integer 之外,其他基础数据类型的包装类只需要首字母大写即可。包装类的作用和特点,本文下半部分详细讲解。

我们可以在代码中,查看某种类型的取值范围,代码如下:

public static void main(String[] args) {// Byte 取值:-128 ~ 127System.out.println(String.format("Byte 取值:%d ~ %d", Byte.MIN_VALUE, Byte.MAX_VALUE));// Int 取值:-2147483648 ~ 2147483647System.out.println(String.format("Int 取值:%d ~ %d", Integer.MIN_VALUE, Integer.MAX_VALUE));
}

包装类型

我们知道 8 种基本数据类型都有其对应的包装类,因为 Java 的设计思想是万物既对象,有很多时候我们需要以对象的形式操作某项功能,比如说获取哈希值(hashCode)或获取类(getClass)等。
那包装类特性有哪些?

1. 功能丰富

包装类本质上是一个对象,对象就包含有属性和方法,比如 hashCode、getClass 、max、min 等。

2. 可定义泛型类型参数

包装类可以定义泛型,而基础类型不行。

比如使用 Integer 定义泛型,代码:

List<Integer> list = new ArrayList<>();

如果使用 int 定义就会报错,代码:

List list = new ArrayList<>();  // 编译器代码报错

3. 序列化

因为包装类都实现了 Serializable 接口,所以包装类天然支持序列化和反序列化。比如 Integer 的类图如下:

Integer 类图

4. 类型转换

包装类提供了类型转换的方法,可以很方便的实现类型之间的转换,比如 Integer 类型转换代码:

String age = "18";
int ageInt = Integer.parseInt(age) + 2;
// 输出结果:20
System.out.println(ageInt);

5. 高频区间的数据缓存

此特性为包装类很重要的用途之一,用于高频区间的数据缓存,以 Integer 为例来说,在数值区间为 -128~127 时,会直接复用已有对象,在这区间之外的数字才会在堆上产生。

我们使用 == 对 Integer 进行验证,代码如下:

public static void main(String[] args) {// Integer 高频区缓存范围 -128~127Integer num1 = 127;Integer num2 = 127;// Integer 取值 127 == 结果为 true(值127 num1==num2 => true)System.out.println("值127 num1==num2 => " + (num1 == num2));Integer num3 = 128;Integer num4 = 128;// Integer 取值 128 == 结果为 false(值128 num3==num4 => false)System.out.println("值128 num3==num4 => " + (num3 == num4));}

从上面的代码很明显可以看出,Integer 为 127 时复用了已有对象,当值为 128 时,重新在堆上生成了新对象。

为什么会产生高频区域数据缓存?我们查看源码就能发现“线索”,源码版本 JDK 8,源码如下:

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

由此可见,高频区域的数值会直接使用已有对象,非高频区域的数值会重新 new 一个新的对象。

各包装类高频区域的取值范围:

  • Boolean:使用静态 final 定义,就会返回静态值;
  • Byte:缓存区 -128~127,全部缓存;
  • Short:缓存区 -128~127,部分缓存;
  • Character:缓存区 0~127,部分缓存;
  • Long:缓存区 -128~127,部分缓存;
  • Integer:缓存区 -128~127,部分缓存。

包装类的注意事项

  • int 的默认值是 0,而 Integer 的默认值是 null。

  • 推荐所有包装类对象之间的值比较使用 equlas() 方法,因为包装类的非高频区数据会在堆上产生,而高频区又会复用已有对象,这样会导致同样的代码,因为取值的不同,而产生两种截然不同的结果。代码示例:

public static void main(String[] args) {// Integer 高频区缓存范围 -128~127Integer num1 = 127;Integer num2 = 127;// Integer 取值 127 == 结果为 true(值127 num1==num2 => true)System.out.println("值127 num1==num2 => " + (num1 == num2));Integer num3 = 128;Integer num4 = 128;// Integer 取值 128 == 结果为 false(值128 num3==num4 => false)System.out.println("值128 num3==num4 => " + (num3 == num4));// Integer 取值 128 equals 结果为 true(值128 num3.equals(num4) => true)System.out.println("值128 num3.equals(num4) => " + num3.equals(num4));
}
  • Float 和 Double 不会有缓存,其他包装类都有缓存。

  • Integer 是唯一一个可以修改缓存范围的包装类,在 VM optons 加入参数:

-XX:AutoBoxCacheMax=666 即修改缓存最大值为 666

示例代码如下:

public static void main(String[] args) {Integer num1 = -128;Integer num2 = -128;System.out.println("值为-128 => " + (num1 == num2));Integer num3 = 666;Integer num4 = 666;System.out.println("值为666 => " + (num3 == num4));Integer num5 = 667;Integer num6 = 667;System.out.println("值为667 => " + (num5 == num6));
}

执行结果如下:

值为-128 => true
值为666 => true
值为667 => false

由此可见将 Integer 最大缓存修改为 666 之后,667 不会被缓存,而 -128~666 之间的数都被缓存了。

相关面试题

1. 以下 Integer 代码输出的结果是?

Integer age = 10;
Integer age2 = 10;
Integer age3 = 133;
Integer age4 = 133;
System.out.println((age == age2) + "," + (age3 == age4));

答:true,false

2. 以下 Double 代码输出的结果是?

Double num = 10d;
Double num2 = 10d;
Double num3 = 133d;
Double num4 = 133d;
System.out.println((num == num2) + "," + (num3 == num4));

答:false,false

3. 以下程序输出结果是?

int i = 100;
Integer j = new Integer(100);
System.out.println(i == j);
System.out.println(j.equals(i));

A:true,true
B:true,false
C:false,true
D:false,false

答:A

题目分析:有人认为这和 Integer 高速缓存有关系,但你发现把值改为 10000 结果也是 true,true,这是因为 Integer 和 int 比较时,会自动拆箱为 int 相当于两个 int 比较,值一定是 true,true

4. 以下程序执行的结果是?

final int iMax = Integer.MAX_VALUE;
System.out.println(iMax + 1);

A:2147483648
B:-2147483648
C:程序报错
D:以上都不是
答:B
题目解析:这是因为整数在内存中使用的是补码的形式表示,最高位是符号位 0 表示正数,1 表示负数,当执行 +1 时,最高位就变成了 1,结果就成了 -2147483648。

5. 以下程序执行的结果是?

Set<Short> set = new HashSet<>();
for (short i = 0; i < 5; i++) {set.add(i);set.remove(i - 1);
}
System.out.println(set.size());

A:1
B:0
C:5
D:以上都不是

答:5

题目解析:Short 类型 -1 之后转换成了 Int 类型,remove() 的时候在集合中找不到 Int 类型的数据,所以就没有删除任何元素,执行的结果就是 5。

6. short s=2;s=s+1; 会报错吗?short s=2;s+=1; 会报错吗?

答:s=s+1 会报错,s+=1 不会报错,因为 s=s+1 会导致 short 类型升级为 int 类型,所以会报错,而 s+=1 还是原来的 short 类型,所以不会报错。

7. float f=3.4; 会报错吗?为什么?

答:会报错,因为值 3.4 是 double 类型,float 类型级别小于 double 类型,所以会报错。如下图所示:

报错示例图

8. 为什么需要包装类?

答:需要包装类的原因有两个。

① Java 的设计思想是万物既对象,包装类体现了面向对象的设计理念;
② 包装类包含了很多属性和方法,比基础数据类型功能多,比如提供的获取哈希值(hashCode)或获取类(getClass)的方法等。

9. 基础类 int 和包装类 Integer,在 -128~127 之间都会复用已有的缓存对象,这种说法正确吗?

答:不正确,只有包装类高频区域数据才有缓存。

10. 包装类 Double 和 Integer 一样都有高频区域数据缓存,这种说法正确吗?

答:不正确,基础数据类型的包装类只有 Double 和 Float 没有高频区域的缓存。

11. 包装类的值比较要使用什么方法?

答:包装类因为有高频区域数据缓存,所以推荐使用 equals() 方法进行值比较。

12. 包装类有哪些功能?

答:包装类提供的功能有以下几个。

  • 功能丰富:包装类包含了有 hashCode、getClass 、max、min 等方法;
  • 可定义泛型类型参数:例如 List<Integer> list = new ArrayList<>(); ;
  • 序列化:包装类实现了 Serializable 接口,所以包装类天然支持序列化和反序列化;
  • 类型转换:包装类提供了方便的类型转换方法,比如 Integer 的 parseInt() 方法;
  • 高频区域数据缓存:高频区域可使用已有的缓存对象。

详见正文“包装类型”部分内容。

13. 泛型可以为基础类型吗?为什么?

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

14. 选择包装类还是基础类的原则有哪些?

答:我们知道正确的使用包装类,可以提供程序的执行效率,可以使用已有的缓存,一般情况下选择基本数据类型还是包装类原则有以下几个。

① 所有 POJO 类属性必须使用包装类;
② RPC 方法返回值和参数必须使用包装类;
③ 所有局部变量推荐使用基础数据类型。

15. 基础数据类型在 JVM 中一定存储在栈中吗?为什么?

答:基础数据类型不一定存储在栈中,因为基础类型的存储位置取决于声明的作用域,来看具体的解释。

  • 当基础数据类型为局部变量的时候,比如在方法中声明的变量,则存放在方法栈中的,当方法结束系统会释放方法栈,在该方法中的变量也会随着栈的销毁而结束,这也是局部变量只能在方法中使用的原因;
  • 当基础数据类型为全局变量的时候,比如类中的声明的变量,则存储在堆上,因为全局变量不会随着某个方法的执行结束而销毁。

16. 以下程序执行的结果是?

Integer i1 = new Integer(10);
Integer i2 = new Integer(10);
Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf(10);
System.out.println(i1 == i2);
System.out.println(i2 == i3);
System.out.println(i3 == i4);

A:false,false,false
B:false,false,true
C:false,true,true
D:true,false,false

答:B

题目解析:new Integer(10) 每次都会创建一个新对象,Integer.valueOf(10) 则会使用缓存池中的对象。

17. 3*0.1==0.3 返回值是多少?

答:返回值为:false。

题目解析:因为有些浮点数不能完全精确的表示出来,如下代码:

System.out.println(3 * 0.1);

返回的结果是:0.30000000000000004。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TomCat JDK环境变量

TomCat安装之前要安装JDK&#xff0c;安装完之后添加环境变量&#xff1b;变量名&#xff1a;Java_Home 变量值&#xff1a; D:\jdk 1.6 变量名&#xff1a;Classpath 变量值&#xff1a; D:\jdk 1.6\jre\lib\rt.jar;.; 变量名&#xff1a;Path 变量值&#xff1a; D:\jdk 1.6\…

网络编程C/S模型怎样才能实现真正的聊天功能

学完socket编成后&#xff0c;就迫不及待地写一个简单的聊天程序&#xff0c;好在同学面前装装逼&#xff0c;毕竟外行看热闹。然而在自己的电脑上运行是毫无差错&#xff0c;发送接收都没有问题&#xff0c;然而将客户端的exe文件打包后发送给其他电脑上运行时程序死在了conne…

c++重载++运算符_C ++运算符重载| 查找输出程序| 套装3

c重载运算符Program 1: 程序1&#xff1a; #include <iostream>using namespace std;class Test {public:int A;Test(){A 0;}Test(int a){A a;}void print(){cout << A << " ";}};Test operator*(Test T1, Test T2){Test temp;temp.A T1.A * T…

将数据库表导入到solr索引

将数据库表导入到solr索引 编辑solrcofnig.xml添加处理器 <requestHandler name"/dataimport" class"org.apache.solr.handler.dataimport.DataImportHandler"><lst name"defaults"><str name"config">data-config…

第 1-4 课:Java 中的运算符和流程控制 + 面试题

算术运算符 Java 中的算法运算符,包括以下几种: 算术运算符名称举例+加法1+2=3-减法2-1=1*乘法2*3=6/除法24/8=3%求余24%7=3++自增1int i=1;i++--自减1int i=1;i--我们本文要重点讲的是 “++” 和 “--”,其他的算术运算符相对比较简单直观,本文就不花精力去讲解了,之所以…

p标题/p能设置字体的大小和颜色

添加style <p style"color:red;font-size:16px;">标题</p>方法2&#xff1a;引入CSS<style type"text/css">.title{color:red;font-size:16px;}</style><body><p class"title">标题</p></body>…

scala中创建时间序列_如何从Scala中的序列中提取唯一元素?

scala中创建时间序列While storing data elements to a data structure or extracting raw data duplicate data might be included and this data decreases the efficiency of the code. So, eliminating duplicate data or extracting unique elements is important. 在将数…

获取u盘文件

功能&#xff1a;开机自启动&#xff0c;无dos窗口弹出&#xff0c;复制速度较快 缺点&#xff1a;面对杀软很无奈 #pragma comment( linker, "/subsystem:windows /entry:mainCRTStartup" )//屏蔽dos窗口 #include <stdio.h> #include <stdlib.h> #inc…

php中socket的使用

一、开启socket phpinfo();查看是否开启了socket扩展&#xff0c;否则在php.ini中开启。 二、服务器端代码的写法 <?php error_reporting(E_ALL); set_time_limit(0); //ob_implicit_flush();$address 127.0.0.1; $port 10005; //创建端口 if( ($sock socket_create(AF_…

第 1-3 课:深入理解字符串 + 面试题

字符串介绍 字符串是程序开发当中,使用最频繁的类型之一,有着与基础类型相同的地位,甚至在 JVM(Java 虚拟机)编译的时候会对字符串做特殊的处理,比如拼加操作可能会被 JVM 直接合成为一个最终的字符串,从而到达高效运行的目的。 1 String 特性 String 是标准的不可变类…

清空session的方法

清空session的方法&#xff0c;常用来注销的时候清空所有的session. 方法一&#xff1a; Enumeration esession.getAttributeNames(); while(e.hasMoreElements()){ String sessionName(String)e.nextElement(); System.out.println("存在的session有&#xff1a;"…

输入输出数组元素的函数重载_C ++函数重载| 查找输出程序| 套装3

输入输出数组元素的函数重载Program 1: 程序1&#xff1a; #include <iostream>using namespace std;class Test {public:void fun(){cout << "Fun() called" << endl;}void fun(int num){cout << num << endl;}};int main(){Test T;…

通过xss所引起的信息泄露,防不胜防!

话不多说直接上&#xff1a; 信息搜集,通过google语法 site:"*.redacted.com"优化一下: site:"*.redacted.com" -www -blog -mail之后&#xff0c;利用subfinder、assetfinder和masass等被动枚举工具收集与目标相关的子域列表&#xff0c;并将它们保存在…

二叉树的前序、中序、后续、层序遍历(包含递归与非递归)

递归形式 递归形式遍历比较简单&#xff0c;不做详细论述。 前序遍历 void Preorder(treenode* root) //前序 {if (root ! NULL){printf("%c", root->data);Preorder(root->left);Preorder(root->right);}中序遍历 } void Inorder(treenode* root) …

第 1-6 课:玩转时间 + 面试题

在 JDK 8 之前,Java 语言为我们提供了两个类用于操作时间,它们分别是:java.util.Date 和 java.util.Calendar,但在 JDK 8 的时候为了解决旧时间操作类的一些缺陷,提供了几个新的类,用于操作时间和人气,它们分别是:LocalTime、LocalDateTime、Instant,都位于 java.time…

单调递增子序列

单调子序列包含有单调递增子序列和递减子序列&#xff0c;不失一般性&#xff0c;这里只讨论单调递增子序列。首先&#xff0c;从定义上明确我们的问题。给定序列a1, a2, …, an&#xff0c;如果存在满足下列条件的子序列 ai1<ai2<…<aim, (其中i1<i2<…<im)…

HTML文本框内容发生变化时引发事件执行

最近在做的程序中需要这样的一个功能:当HTML文本框内容生发变化时执行JavaScript函数.最初的想法是使用onchange,但这个事件只有当文本框失去焦点时才会触发,后来就找到了onpropertychange事件.如下:<input id"textRoad" type"text" size"15"…

第 1-5 课:深入了解 Java 中的异常处理 + 面试题

在程序开发中,异常处理也是我们经常使用到的模块,只是平常很少去深究异常模块的一些知识点。比如,try-catch 处理要遵循的原则是什么,finally 为什么总是能执行,try-catch 为什么比较消耗程序的执行性能等问题,我们本篇内容都会给出相应的答案,当然还有面试中经常被问到…

java math 类_Java Math类静态双层(double d)示例

java math 类数学班静态双层(双D) (Math Class static double floor(double d)) This method is available in java.lang package. 此方法在java.lang包中可用。 In this method if the value of the given positive argument after decimal point is 0 or greater than 0 so i…

在win server 2003上安装SQL Server 2008的步骤

1.安装Microsoft .NET Framework 3.5 Service Pack 1&#xff0c;下载地址&#xff1a;http://www.microsoft.com/zh-cn/download/confirmation.aspx?id22 2.运行SQL Server 2008安装包&#xff0c;安装过程中会提示需要重启&#xff0c;手动重启。 3.重启后若直接再次运行SQL…