问题及答案来源自《Java程序员面试笔试宝典》第四章 Java基础知识 4.4基本类型与运算

 

 

 

1、Java提供了哪些基本数据类型?

Java一共提高了八种原始的数据类型:byte、short、int、long、float、double、char、boolean

基本数据类型不是对象,而是基本数据类型,这些数据类型变量在声明之后就会立刻在栈上被分配内存空间

 

八种基本类型可以分为以下四类:

  • int相关:short(2字节)、int(4字节)、long(8字节)
  • float相关:float(4字节)、double(8字节)
  • boolean相关:boolean(1字节)、byte(1字节)
  • char相关:char(2字节)(unicode字符)

另外Java还提供了对这些原始数据类型的封装类(字符类型Character、布尔类型Boolean、数值类型Byte、Short、

Integer、Long、Float、Double)

 

封装类型和原始类型的不同之处:

  • 原始类型传递参数按值传递,封装类型传递参数传的是引用
  • 类实例化时,封装类型默认值是null,原始类型默认值与它们的类型有关(比如int默认值为0)

 

精度损失:

当把高精度的变量赋值给低精度的变量时会造成精度损失,例如将double类型的数值赋值给float类型的变量

eg:float f = 0.93; 这样会造成精度损失,正确的方法是采用强制类型转换,eg:float f = (float)0.93;

 

 

2、什么是不可变类?

不可变类:

不可变类是指当创建了这个类的实例后,就不允许修改它的值,不可变类类似于常量,即只允许别的程序读,

但是不允许别的程序进行修改

 

常见的不可变类:

基本类型的封装类(Integer、Float等)、String

 

String类是不可变类,那么下面这段代码为什么可行?



1 String s = "Hello";
2 s += " World";
3 System.out.println(s);



解释:

第2行代码中修改的只是s的引用,s由原来的指向"Hello"改成指向"Hello World",

原来的"Hello"还存在于内存中并没有被改变

 

  

3、值传递与引用传递有哪些区别?

Java语言中参数传递有两种方式:值传递和引用传递

值传递:

在方法调用中,实参把值传递给形参,形参只是用实参的值初始化一个临时的存储单元,因此形参与

实参虽然值一样,但是有着不同的存储单元,对形参的改变不会影响实参的改变

引用传递:

在方法调用中,传递的是对象(也可以看作是对象的地址),这是形参和实参的对象指向同一块存储单元,

因此对形参的修改就会影响实参的值

在Java中,原始数据类型在传递参数时按值传递,而普通对象在传递参数时按引用传递

实例如下:



1 public class test {
 2     public static void testPassParameter(StringBuffer ss1, int n){
 3         ss1.append(" World");     // 引用
 4         n = 8;                    // 值
 5     }
 6     
 7     public static void main(String[] args) {
 8         int i = 1;
 9         StringBuffer s1 = new StringBuffer("Hello");
10         testPassParameter(s1, i);
11         System.out.println(s1);        // Hello World
12         System.out.println(i);         // 1
13     }
14 }



 

Java中八种基本数据类型都是按值传递,其他所有类型都是按引用传递,由于Java中八种基本数据类型的包装类型

都是不可变类型,因此增加了对按引用传递的理解难度,详细情况看下面的实例:



1 public class test {
 2     public static void changeStringBuffer(StringBuffer ss1, StringBuffer ss2) {
 3         ss1.append(" World");
 4         ss2 = ss1;
 5     }
 6 
 7     public static void main(String[] args) {
 8         Integer a = new Integer(1);
 9         Integer b = a;
10         b = new Integer(b.intValue() + 1);
11         System.out.println(a + " " + b);    // 1 2  第10行代码实际上是创建了一个新的Integer对象
12         StringBuffer s1 = new StringBuffer("Hello");
13         StringBuffer s2 = new StringBuffer("Hello");
14         changeStringBuffer(s1, s2);
15         System.out.println(s1 + " " + s2);    // Hello World Hello
16     }
17 }



由上面的实例可以看出,按引用传递实际上当修改形参中地址对应的内容时,实参会发生相应变化,但是当

直接改变形参地址时实参不会改变,这说明了按引用传递实际上也是一种按值传递(传的是地址)

也就是说引用传递不会改变实际参数指向的地址,但是能改变实际参数指向的地址中的内容

 

 

4、不同数据类型的转换有哪些规则?

背景描述:

在Java中,当参与运算的两个变量的数据类型不同时,就需要进行隐式的数据转换,规则为从低精度向高精度转换,

即优先级满足:byte < short < char < long < float < double,例如不同数据类型的值在进行运算时,short类型数据

能够自动转换成int类型,int类型能够自动转换成float类型等,反之则需要通过强类型转换

 

类型自动转换:

低级数据类型可以自动转换为高级数据类型,转换规则如下:

java lg运算 java^运算_java

自动转换的注意事项:

  • char类型转换时会自动转换成其对应的ASCII码
  • byte、char、short类型的数据在参与运算时会自动转换成int型,但使用+=运算时不会产生类型转换
  • boolean类型是不能和其他数据类型相互转换的 

 

强制类型转换:

当需要从高级数据类型转换成低级数据类型时,就需要进行强制类型转换,强制类型转换如下:

  • byte =》char
  • char =》byte
  • short =》byte、char
  • int =》byte、short、char
  • long =》byte、short、char、int
  • float =》byte、short、char、int、long
  • double =》byte、short、char、int、long、float

另外要注意进行强制类型转换可能会损失精度(高精度转换成低精度)

 

 

5、强制类型转换的注意事项有哪些?

Java中的+=是Java中规定的运算法,Java编译器会对其进行特殊处理,因此语句short s1 = 1; s1 += 1; 能够编译通过 

 

 

6、运算符优先级是什么?

java lg运算 java^运算_System_02

 

 

7、Math类中round、ceil和floor方法的功能各是什么?

  • round:对数四舍五入
  • ceil:对数向上取整
  • floor:对数向下取整

下面是测试代码:



1 public class test {
 2     public static void main(String[] args) {
 3         float m = 6.4f;
 4         float n = -6.4f;
 5         System.out.println(Math.round(m));        // 6
 6         System.out.println(Math.round(n));        // -6
 7         System.out.println("===============");
 8         System.out.println(Math.ceil(m));        //7.0
 9         System.out.println(Math.ceil(n));        // -6.0
10         System.out.println("===============");
11         System.out.println(Math.floor(m));        // 6.0
12         System.out.println(Math.floor(n));        // -7.0
13         System.out.println("===============");
14     }
15 }



 

 

8、++i和i++有什么区别?

在java的执行过程中,i++和++i都直接对i进行了i=i+1的操作,

但是不同的是i++得到的是i未进行加法操作的前的值的副本,而++i直接得到计算后的值

比如a = i++;是将i的值赋值给a然后i的值再+1,而a=++i是将i的值+1然后再将+1后的i的值赋值给a

示例代码:



1 public class test {
 2     public static void main(String[] args) {
 3         int i = 1;
 4         System.out.println((i++)+(i++));        // 3
 5         System.out.println(i);                    // 3
 6         System.out.println((i++)+(++i));        // 8
 7         System.out.println(i);                    // 5    
 8         System.out.println((i++)+(i++)+(i++));    // 18
 9         System.out.println(i);                    // 8
10     }
11 }



 

 

9、无符号数的右移操作 

Java提供了两种右移运算符:>>和>>>,>>被称为有符号右移运算符,>>>被称为无符号右移运算符

两者的区别:

  • >>在右移时,若参与运算的数为正数则在高位补0,若为负数则在高位补1
  • >>>则不同,不论参与运算的数字为正数或负数,均会在高位补0

 

引申 - <<运算符和>>运算符有什么异同?

<<运算符标识左移,左移n位表示原来的值乘2的n次方,经常用来代替乘法操作

例如,一个数m乘以16可以表示为将这个数左移4位(m<<4)

由于CPU直接支持位运算,因此位运算比乘法运算的效率更高

与右移运算不同的是左移运算没有有符号和无符号的区别,在左移时,移除高位的同时在低位补0

 

 

10、char型变量中是否可以存储一个中文汉字?

在Java中,默认使用unicode编码方式,即每个字符(char)占用两个字节,因此char可以存储中文汉字

String是由char组成的,但它采用了更灵活的方式存储,即英文占用一个字节,而中文一般占用两个字节

示例代码:



1 public class test {
 2     public static void getLen(String s){
 3         System.out.println(s + "的长度是: " + s.length() + " 所占字节数是: " + s.getBytes().length);
 4     }
 5     
 6     public static void main(String[] args) {
 7         String s1 = "hello";
 8         String s2 = "你好";
 9         getLen(s1);
10         getLen(s2);
11     }
12 }



注:在Java中,中文字符所占的字节数取决于字符的编码方式,一般情况下,采用ISO8859-1编码方式时,

一个中文字符与一个英文字符一样只占1个字节;采用GB2312或GBK编码方式时,一个中文字符占2个字节;

而采用UTF-8编码方式时,一个中文字符会占3个字节