java知识点之数据类型总结【全】

java数据类型总结

目录

一、java数据类型知识点总结

1、Java变量

1.1 什么是变量?

变量的三个元素:变量类型,变量名,和变量值!
变量:变量就是可以被改变的数据!(是一个数据存储空间的表示。)
变量是存储数据的一个基本单元,不同变量相互独立。

1.2 变量声明的方式

  1. 声明并赋值(数据类型 变量名=变量值)
    如:int i=0;
  2. 先声明后赋值(数据类型 变量名; 变量名=变量值)
    如:int i; i=0;
    int i,a,c;
    i=0;a=1;b=2;

1.3 变量的分类

变量又分为成员变量和局部变量:
在这里插入图片描述

1.4 变量的命名规范(扩展:包,类,方法等命名规范)

  1. 驼峰式命名法:尽量使用有意义的名称,不能以java的关键字命名
  2. 类名:每个单词首字母大写,其余小写(大驼峰)
  3. 文件名:文件名必须与类名一致
  4. 变量名:开头以小写字母,下划线_或$符,第一个单词字母首字母小写,其余全部首字母都大写,后面跟字母下划线但不能有空格跟其他符号(小驼峰)。
    声明变量的注意事项:
  5. 声明String类型的变量时,变量值必须用双引号包裹。声明char类型时,变量值必须用单引号包裹。其余数据类型时,不用这些东西包裹!
  6. 变量命名后必须赋值!

变量的常见错误:

  1. 类型不可以随便命名(public修饰的类的名称必须与java文件同名)
  2. Void不能少(main()方法中的void不能够缺少)
  3. java对英文字母的大小写敏感(java对大小写敏感)
  4. ;是必须的(在java中,一个完整的语句必须都要以;结束)
  5. “”是必须的(输出的字符串必须用引号包起来,而且必须是因为的引号)

命名规范扩展(可忽略这部分内容)

  1. 包命名规范
    包(Package)的作用是将功能相似或相关的类或者接口进行分组管理,便于类的定位和查找,同时也可以使用包来避免类名的冲突和访问控制,使代码更容易维护。通常,包命使用小写英文字母进行命名,并使用“.”进行分割,每个被分割的单元只能包含一个名词。
    一般地,包命名常采用顶级域名作为前缀,例如com,net,org,edu,gov,cn,io等,随后紧跟公司/组织/个人名称以及功能模块名称。
  2. 类命名规范
    类(Class)通常采用名词进行命名,且首字母大写,如果一个类名包含两个以上名词,建议使用驼峰命名(Camel-Case)法书写类名,每个名词首字母也应该大写。一般地,类名的书写尽量使其保持简单和描述的完整性,因此在书写类名时不建议使用缩写(一些约定俗成的命名除外。
    例如 :Internationalization and Localization 缩写成i18n,Uniform Resource Identifier缩写成URI,Data Access Object缩写成DAO,JSON Web Token缩写成JWT,HyperText Markup Language缩写成HTML等等)。
  3. 接口命名规范
    首先,接口(Interface)是一种表述某一类型对象动作的特殊类;简单来说,接口也是类(不太严谨),所以,接口的名称的书写也应该符合类名书写规范,首字母应该大写,与普通类名不同的是,接口命名时通常采用形容词或动词来描述接口的动作行为。
  4. 抽象类命名规范
    抽象类(Abstract Class)是一种特殊的类,其命名与普通类的命名规范相当。一般地,为了将抽象类与普通类和接口做出区别,提高抽象类的可读性,在命名抽象类时,会以“Abstract”/“Base”作为类命的前缀。
  5. 方法命名规范
    方法(Method)命名时,其首字母应该小写,如果方法签名由多个单词组成,则从第二个单词起,使用驼峰命名法进行书写。一般地,在对方法进行命名时,通常采用动词/动词+名词的组合

2、Java常量

2.1 什么是常量?

常量是指在程序的整个运行过程中值保持不变的量。在这里要注意常量和常量值是不同的概念,常量值是常量的具体和直观的表现形式,常量是形式化的表现。通常在程序中既可以直接使用常量值,也可以使用常量。常量在程序运行时不能被修改。通常用大写字母来表示常量,用 final 关键字来修饰。

2.2 常量值

**定义:**常量值又称为字面常量,它是通过数据直接表示的,因此有很多种数据类型,像整型和字符串型等。下面一一介绍这些常量值。
整型常量值

  1. Java 的整型常量值主要有如下 3 种形式。
    十进制数形式:如 54、-67、0。
    八进制数形式:Java 中的八进制常数的表示以 0 开头,如 0125 表示十进制数 85,-013 表示十进制数 -11。
    十六进制数形式:Java 中的十六进制常数的表示以 0x 或 0X 开头,如 0x100 表示十进制数 256,-0x16 表示十进制数 -22。
    整型(int)常量默认在内存中占 32 位,是具有整数类型的值,当运算过程中所需值超过 32 位长度时,可以把它表示为长整型(long)数值。长整型类型则要在数字后面加 L 或 1, 如 697L,表示一个长整型数,它在内存中占 64 位。
  2. 实型常量值
    Java 的实型常量值主要有如下两种形式。
    十进制数形式:由数字和小数点组成,且必须有小数点,如 12.34、-98.0。
    科学记数法形式:如 1.75e5 或 32&E3,其中 e 或 E 之前必须有数字,且 e 或 E 之后的数字必须为整数。
    Java 实型常量默认在内存中占 64 位,是具有双精度型(double)的值。如果考虑到需要节省运行时的系统资源,而运算时的数据值取值范围并不大且运算精度要求不太高的情况,可以把它表示为单精度型(float)的数值。
    单精度型数值一般要在该常数后面加 F 或 f,如 69.7f,表示一个 float 型实数,它在内存中占 32 位(取决于系统的版本高低)。
  3. 布尔型常量值
    Java 的布尔型常量只有两个值,即 false(假)和 true(真)。
    字符型和字符串常量值
    Java 的字符型常量值是用单引号引起来的一个字符,如 ‘e’、E’。需要注意的是,Java 字符串常量值中的单引号和双引号不可混用。双引号用来表示字符串,像 “11”、“d” 等都是表示单个字符的字符串。

除了以上所述形式的字符常量值之外,Java 还允许使用一种特殊形式的字符常量值来表示一些难以用一般字符表示的字符,这种特殊形式的字符是以开头的字符序列,称为转义字符。
注意:这里表示字符和字符串的单引号和双引号都必须是英语输入环境下输入的符号。

3、Java数据类型

Java中的数据类型分为两大类:分别是基本数据类型和引用类型,基本类型包含byte,short,int,long,float,double,char,boolean八种类型,引用类型包含类,数组,接口三种类型。

3.1 基本数据类型

在Java中共有八种基本数据类型,它们分别是以下几种类型:
在这里插入图片描述
注意:char的数据范围不是0 - 65535(图中错误),因为Java中的char类型由两个字节即十六位来表示,因为是无符号数,所以为2的16次方,数值范围就为:0 - 2^16-1;

3.2 引用数据类型

在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。引用变量一旦声明后,类型就不能被改变了。Java中的引用类型共有三种,分别是类,数组,接口这些引用类型的默认值都是null

3.3 基本类型与引用类型区别

基本数据类型和引用类型的区别主要在于基本数据类型是分配在栈上的,而引用类型是分配在堆上的

3.4 数据类型之间的转换

整型、常量和字符型数据可以混合运算。不同类型数据转换为同一类型再运算,由低到高转换。

低------------------------------------------------------>高

byte,short,char -> int -> long -> float -> double

转换规则

  1. Boolean不能转换

  2. 对象类型不能转换为不相关类的对象

  3. 容量大的类型转换为容量小的类型需使用强制类型换换

  4. 转换可能导致溢出或损失精度

  5. 浮点数到整数是舍弃小数得到的

自动数据类型转换:
满足转换前数据类型位数要低于转换后数据类型位数

强制类型转换:
转换的数据类型必须是兼容的

总览:
在这里插入图片描述

在这里插入图片描述

4、面试中常见的数据类型问题(一)

4.1 int 与 Integer 的区别

定义:
int 是java的基本数据类型;
Integer 继承了Object类,是对象类型,是 int 的包装类。
区别:
1、值的存储
int 存储在栈中
Integer 对象的引用存储在栈空间中,对象的数据存储在堆空间中。

2、初始化
int 初始化值为0。
Integer 初始化值为null。

3、传参
int 是值传递,栈中的数据不可变。
Integer 对象是引用传递,引用不可变,但是引用指向的堆空间地址中的值是可以改变的。

4、泛型支持
泛型不支持int,但是支持Integer。

5、运算
int 可以直接做运算,是类的特性。
Integer 的对象可以调用该类的方法,但是在拆箱之前不能进行运算,需要转化为基本类型int。
拓展:
相同值下的 int 和 Integer 的比较结果
两个通过new生成的变量,结果为false。

int 和 Integer 的值比较,若两者的值相等,则为true。
(注意:在比较时,Integer会自动拆箱为int类型,然后再做比较。)

new 生成的Integer变量 和 非new 生成的Integer变量比较,,结果为false。
(注意:new 生成的Integer变量的值在堆空间中,非new 生成的Integer变量的值在在常量池中。)
(注意:非new生成的Integer变量,会先判断常量池中是否有该对象,若有则共享,若无则在常量池中放入该对象;也叫享元模式。)

两个非new 生成的Integer对象比较,则结果为true。
(注意:此处需要一个前提:值的范围在 -128 ~ 127 之间

Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
        System.out.println(f1 == f2);//true
        System.out.println(f3 == f4);//false

4.2 short s1 = 1; s1 = s1 + 1; 有错吗?short s1 = 1; s1 += 1 有错吗?

答案:前者错!后者对!

对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int 型,需要强制转换类型才能赋值给 short 型。

而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1; 相当于 s1 = (short)(s1 + 1); 其中有隐含的强制类型转换。

4.3 String、StringBuffer、StringBuilder的区别?

String是字符串常量,final修饰;StringBuffer字符串变量(线程安全);StringBuilder 字符串变量(线程不安全).此外StringBuilder和StringBuffer实现原理一样,都是基于数组扩容来实现的.

可变不可变
String:字符串常量,在修改时不会改变自身;若修改,等于重新生成新的字符串对象。

StringBuffer:在修改时会改变对象自身,每次操作都是对 StringBuffer 对象本身进行修改,不是生成新的对象;使用场景:对字符串经常改变情况下,主要方法:append(),insert()等。

● 线程是否安全

String:对象定义后不可变,线程安全。

StringBuffer:是线程安全的(对调用方法加入同步锁),执行效率较慢,适用于多线程下操作字符串缓冲区大量数据。

StringBuilder:是线程不安全的,适用于单线程下操作字符串缓冲区大量数据。

● 共同点

StringBuilder与StringBuffer有公共父类 AbstractStringBuilder(抽象类)。

StringBuilder、StringBuffer 的方法都会调用 AbstractStringBuilder 中的公共方法,如 super.append(…)。只是 StringBuffer 会在方法上加 synchronized 关键字,进行同步。最后,如果程序不是多线程的,那么使用StringBuilder 效率高于 StringBuffer。

String和StringBuffer的区别?
String和StringBuffer主要区别是性能:String是不可变对象,每次对String类型进行操作都等同于产生了一个新的String对象,然后指向新的String对象.所以尽量不要对String进行大量的拼接操作,否则会产生很多临时对象,导致GC开始工作,影响系统性能.

StringBuffer是对象本身操作,而不是产生新的对象,因此在有大量拼接的情况下,我们建议使用StringBuffer(线程安全).

需要注意现在JVM会对String拼接做一定的优化,比如

String s="This is only "+ "simple" +"test";

以上代码在编译阶段会直接被优化成会`String s=“This is only simple test”.

StringBuffer和StringBuilder
StringBuffer和StringBuilder的实现原理一样,其父类都是AbstractStringBuilder.StringBuffer是线程安全的,StringBuilder是JDK 1.5新增的,其功能和StringBuffer类似,但是非线程安全.因此,在没有多线程问题的前提下,使用StringBuilder会取得更好的性能.

4.3 3*0.1==0.3返回值是什么

false,因为有些浮点数不能完全精确的表示出来.

4.4 如何将byte转为String

可以使用String接收 byte[] 参数的构造器来进行转换,注意要使用的正确的编码,否则会使用平台默认编码.这个编码可能跟原来的编码相同.也可能不同.

4.5 可以将int强转为byte类型么?会产生什么问题?

可以做强制转换,但是Java中int是32位的而byte是8 位的.如果强制转化int类型的高24位将会被丢弃,byte 类型的范围是从-128到128.

4.6 a=a+b与a+=b有什么区别吗?

+=操作符会进行隐式自动类型转换,此处a+=b隐式的将加操作的结果类型强制转换为持有结果的类型,而a=a+b则不会自动进行类型转换.如:

byte a = 127;
byte b = 127;
b = a + b; // 报编译错误:cannot convert from int to byte
b += a; 

以下代码是否有错,有的话怎么改?

short s1= 1;
s1 = s1 + 1;

有错误.short类型在进行运算时会自动提升为int类型,也就是说s1+1的运算结果是int类型,而s1是short类型,此时编译器会报错.

以下代码是否有错,有的话怎么改?

short s1= 1; 
s1 += 1; 

+=操作符会对右边的表达式结果强转匹配左边的数据类型,所以没错.

4.7 String类可以被继承吗?

答案:不能!!! String类在声明时使用final关键字修饰,被final关键字修饰的类无法被继承。

为什么Java语言的开发者,把String类定义为final的呢?

因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。因为不可变对象不能更改,它们可以在多个线程之间自由共享。

因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。

从内存角度来看:字符串常量池的要求:创建字符串时,如果该字符串已经存在于池中,则将返回现有字符串的引用,而不是创建新对象。多个String变量引用指向同一个内地地址。如果字符串是可变的,用一个引用更改字符串将导致其他引用的值错误。这是很危险的。
缓存Hashcode:字符串的Hashcode在java中经常配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable。不可变的特性保证了hashcode永远是相同的。不用每次使用hashcode就需要计算hashcode。这样更有效率。因为当向集合中插入对象时,是通过hashcode判别在集合中是否已经存在该对象了(不是通过equals方法逐个比较,效率低)。
方便其它类使用:其他类的设计基于string不可变,如set存储string,改变该string后set包含了重复值。
安全性:String被广泛用作许多java类的参数,例如网络连接、打开文件等。如果对string的某一处改变一不小心就影响了该变量所有引用的表现,则连接或文件将被更改,这可能导致严重的安全威胁。
总结 :由于效率和安全性的原因,字符串被设计为不可变。

final关键字除了修饰类之外,还有哪些用法呢?

final修饰的变量,一旦赋值,不可重新赋值;

final修饰的方法无法被覆盖;

final修饰的实例变量,必须手动赋值,不能采用系统默认值;

final修饰的实例变量,一般和static联用,用来声明常量;

注意:final不能和abstract关键字联合使用。

总之,final表示最终的、不可变的。\

4.8 String s = “Hello”;s = s + " world!";这两行代码执行后,原始的 String 对象中的内容变了没有?

答案:没有!!!

因为 String被设计成不可变类,所以它的所有对象都是不可变对象。(说白了,就是 final 关键字在起作用)

在这段代码中,s原先指向一个 String 对象,内容是 “Hello”,然后我们对 s 进行了“+”操作,那么 s 所指向的那个对象是否发生了改变呢?

答案是没有。这时s不指向原来那个对象了,而指向了另一个 String 对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。
通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用 String 来代表字符串的话会引起很大的内存开销。因为 String 对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个 String 对象来表示。这时,应该考虑使用 StringBuffer/StringBuilder类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都 new 一个 String。

4.9 char类型变量能不能储存⼀个中⽂的汉⼦,为什么?

char类型变量是⽤来储存Unicode编码的字符的,unicode字符集包含了汉字,所以char类型当然可以存储汉字的,还有⼀种特殊情况就是某
个⽣僻字没有包含在
unicode编码字符集中,那么就char类型就不能存储该⽣僻字。

5、面试中常见的数据类型问题(二)

5.1 switch语句能否作⽤在byte上,能否作⽤在long上,能否作⽤在string上?

byte的存储范围⼩于int,可以向int类型进⾏隐式转换,所以switch可以作⽤在byte上
long的存储范围⼤于int,不能向int进⾏隐式转换,只能强制转换,所以switch不可以作⽤在long上
string在1.7版本之前不可以,1.7版本之后switch就可以作⽤在string上了。

5.2 java 中 3*0.1 == 0.3 将会返回什么?true 还是 false?

答:false,因为浮点数不能完全精确的表⽰出来,⼀般都会损失精度。

5.3 java 中 float f = 3.4; 是否正确?

答:不正确,3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于向下转型(down-casting,也称为窄化)会造成精度损
失,因此需要强制类型转换 float f = (float)3.4; 或者写成 float f = 3.4F; 才可以。

5.4 &和&&的区别?

答:&运算符有两种⽤法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是⾮常巨⼤的,虽然⼆者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进⾏运算。很多时候我们可能都需要⽤&&⽽不是&,例如在验证⽤户登录时判定⽤户名不是null⽽且不是空字符串,应当写为:username != null &&!username.equals(“”),⼆者的顺序不能交换,更不能⽤&运算符,因为第⼀个条件如果不成⽴,根本不能进⾏字符串的equals⽐较,否则会产⽣NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。

5.5 java中 1.0 - 0.9 == 0…1将会返回什么?true还是false

答案: fasle, 浮点数不能精确的表示出来,因此造成不等,浮点数比较大小应该采用范围的形式,比如:
1.0 - 0.9< 0.00001

5.6 int 类型最大值是 2147483647 ,当最大值+1后的结果?

在这里插入图片描述
问题来了为什么int 类型最大值+1后会变成负数
这是因为整数在内存中使用的是补码的形式表示,最高位是符号位,0表示正数,1表示负数。

5.7 自动拆箱和装箱扩展

与自动拆箱和装箱有关的其他面试题:


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

请根据以上示例代码,判断出两个输出结果分别为什么?

正确答案:false和true

快看看你答对了吗?如果不对,请查看下面的解析过程

代码分析:

public class AutoUnboxingTest {
    
    
    public static void main(String[] args) {
    
    
        Integer a = new Integer(3); //a是Integer类的实例化对象,属于引用类型
        Integer b = 3; //将3自动装箱成Integer类型
        int c = 3; //整型变量c
        //a是引用类型,引用的是堆中的内存地址,b是在栈中的变量值
        System.out.println(a==b); //值为false,两个引用没有引用同一对象
        //c也是在栈中的变量值,a会自动拆箱成int类型再与c比较
        System.out.println(a==c); //值为true,都属于基本类型的变量值
    }
}

5.8 ==和equals的区别?

==是运算符,用于比较两个变量是否相等,对于基本类型而言比较的是变量的值,对于对象类型而言比较的是对象的地址.
equals()是Object类的方法,用于比较两个对象内容是否相等.默认Object类的equals()实现如下:

public class Object {
    
    
       
        public boolean equals(Object obj) {
    
    
        return (this == obj);
    }
}

不难看出此时equals()是比较两个对象的地址,此时直接==比较的的结果一样.对于可能用于集合存储中的对象元素而言,通常需要重写其equals()方法.

==比较的是地址,基本数据类型因为储存在栈中,所以相同值比较出来的结果为true,引用类型因为引用在栈中,对象在堆中,所以比较出来的结果为false。对引用类型来说,==比较的是两个引用是否指向同一对象。
Equals比较的是两个引用数据的内容,equals方法是可以重写的。而基本数据类型不存在equals这个说法。

a==b与a.equals(b)有什么区别
如果a 和b 都是对象,则 a==b 是比较两个对象内存地址,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true.而 a.equals(b) 是进行内容比较,其比较结果取决于equals()具体实现.多数情况下,我们需要重写该方法,如String 类重写 equals()用于两个不同对象,但是包含的字母相同的比较:

 public boolean equals(Object anObject) {
    
    
        if (this == anObject) {
    
    						// 同一个对象直接返回true
            return true;
        }
        if (anObject instanceof String) {
    
    
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
    
    
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
    
          		  // 按字符依次比较
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

5.9 64位的JVM当中,int的长度是多少?

Java中数据类型所占用的位数和平台无关,在 32 位和64位 的Java 虚拟机中,int 类型的长度都是占4字节.

了解泛型么?简述泛型的上界和下界?
有时候希望传入的类型有一个指定的范围,从而可以进行一些特定的操作,这时候就需要通配符了?在Java中常见的通配符主要有以下几种:

<?>: 无限制通配符 <? extends E>: extends 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类 <? super E>: super关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类 它们的目的都是为了使方法接口更为灵活,可以接受更为广泛的类型. < ? extends E>: 用于灵活读取,使得方法可以读取 E 或 E 的任意子类型的容器对象。 < ? super E>: 用于灵活写入或比较,使得对象可以写入父类型的容器,使得父类型的比较方法可以应用于子类对象。 用简单的一句话来概括就是为了获得最大限度的灵活性,要在表示生产者或者消费者的输入参数上使用通配符,使用的规则就是:生产者有上限(读操作使用extends),消费者有下限(写操作使用super). 赶紧点赞、收藏起来吧!不然下次就找不到了

猜你喜欢

转载自blog.csdn.net/weixin_43474701/article/details/124333461
今日推荐