黑马程序员-javaSE学习之语言基础细节详解

来源:互联网 发布:苏享茂 知乎 编辑:程序博客网 时间:2024/05/18 00:11

------- android培训、java培训、期待与您交流! ----------

一、基本数据类型转换详解:

1、基本数据类型的转换是指由系统根据转换规则自动完成,不需要程序员明确地声明不同数据类型之间的转换。转换在编译器执行,而不是等到运行期再执行。 
2、基本数据类型的转换在赋值、方法调用和算术运算三种情况下都会发生。在进行方法调用时,数据类型指调用方法向被调用方法传递参数,即实参和型参类型不一致,从而发生了类型转换。 
3、赋值和方法调用的基本数据类型转换规则一样。合法的基本类型转换原则是指从取值范围窄的类型向取值范围宽的类型转换(自动转换),如果是从取值范围宽的类型向取值范围窄的类型转换,则会产生编译错误(此时需要强制转换)。 
4、具体规则: 
1)布尔型和其它基本数据类型之间不能相互转换; 
2byte型可以转换为shortint、、longfloatdouble; 
3short可转换为intlongfloatdouble; 
4char可转换为intlongfloatdouble; 
5int可转换为longfloatdouble; 
6long可转换为floatdouble; 
7float可转换为double
也就是说,只能有取值窄的范围向宽范围转换,反之则不行。 
5Java中无后缀数字型,文字型共有两种默认类型,无小数点的整数型文字值、默认类型为整型int,带有小数点的浮点数型文字值,默认类型为双精度double。 
6、在赋值语句中,默认类型为整型的无小数点整数型文字值作为右操作数时,可以赋值给取值范围比整型小的变量,前提是文字值对于的实际数值在变量类型的取值范围内。而默认类型为双精度的带有小数点的浮点数型文字值只能赋值给双精度型变量,不能赋值给单精度型变量。 
7、基本数据类型的转换在算术运算情况下,正对单操作数运算符和双操作数运算符的转换规则是不一样的。 
但操作数运算符算术运算时基本转换规则如下: 
1)当运算符为取正运算符(+)。取负运算符(-)或按位取反运算符(~)时,如果操作数为bytecharshort,则先被转换为int,再参与运算。 
2)当运算符为自动递增运算符(++)或自动递减运算符(--)时,如果操作数为byteshortchar,则不用先被转换为int,而是直接参与算术运算,且运算结果类型也不变。 
3)如果操作数为intlong,则无论运算符为何种单操作数运算符,均不发生类型转换,且运算结果类型也不变。 
双操作数运算符算术运算时基本转换规则如下: 
1)如操作数之一为double,则另一个操作数先被转化为double,再参与算术运算。 
2)如两操作数均不为double,当操作数之一为float,则另一操作数先被转换为float,再参与运算。 
3)如两操作数均不为doublefloat,当操作数之一为long,、则另一操作数先被转换为long,再参与算术运算。 
4)如两操作数均不为doublefloatlong,则两操作数先被转换为int,再参与运算

 

二、经典面试题剖析

在笔试和面试中,我们经常遇到这样的题目,或许答案您已经知道了,但是我们来详细讲述一下得出答案的原理。

第一种面试题目:

byte s=4;s=s+4;byte s=4; s+=4;

原理1:整数的默认数据类型是int

原理2:对于一个变量的声明期间,java编译器会检查变量声明语句中变量初始化表达式两边的数据类型,自动进行转换。

原理3::对于s=s+4;这条语句是两次运算,即cpu的运算器执行一次相加运算,一次赋值运算。对于s+=4这条语句是一次运算,cpu的运算器执行一次相加运算,此时加完的值就是s的值。

剖析:

1)由于4是默认的整数类型int,所以在检查器检测到byte s=4的时候,就会将原本四个字节存储的4这个数用两个字节来存储,再将内容的地址给变量s,此时s的内容就是4,而且是byte类型。其实这一个过程就是做了一个强制转换,只不过这个强制转换是由编译器自动完成的,不需要我们来做。

2)对于s=s+4;这条语句,由于sbyte类型,4int类型,此时会发生自动转换,即得到的数据存储在4个字节的内存中,即此时的数据时int类型,而此时再想把这个数据赋值给变量s,已经不可能了,因为数据类型不匹配,所以就会发生编译错误。由于没有编译器自动检查了,我们需要手动去强制转换,才能避免这个错误。

3)对于②,byte s=4;是同样的道理;而对于s+=4;则不会发生编译错误,因为对于+=这种运算符,编译器是支持自动检查的功能的,就是说编译器看到这条语句所作的动作是:将左右两边的值统一为byte类型后再进行相加操作,此时就不会发生编译错误了。

 

第二种面试题目:

byte s=4;byte s1=3;byte s2=5;s=s1+s2;

在理解了第一种面试题目之后,这道题就更容易了,因为对于s,s1,s2都是byte类型,我们在将两个byte类型进行相加的操作的时候,是有可能超出byte类型的范围的,所以对于byte类型变量不能进行相加的操作,但是可以进行自增的操作。

 

第三种面试题目:

int s=4;int s1=3;int s2=5;s=s1+s2;我们都知道这道题的答案是8,不会发生错误,这又是为什么呢?很多人可能会说,当两个数都非常大的时候,不是也会发生超出范围的错误么?

这里,我们要知道,我们使用的数据类型是int,即使用的数据类型就是默认的数据类型,对于默认的数据类型,java中有这样一种机制,当两个数相加太大,超过了范围之后,会按照最高位(符号位)的数值重新定位这个数,要是1,就定义为负数,即如下图所示:

0000 -0000  0000-0000  0000-0000  0000-0001

0111-1111   1111-1111  1111-1111   1111-1111

当这两个数相加的时候,结果是:

1000-0000  0000-0000  0000-0000  0000-0000 此时的数值为-231次方,所以不会发生超出数据类型的错误。

 

 下面有一道选择题:我们从中可以学习到一些东西!

1. 下面哪些赋值语句是正确的?(D )ABD

A. long test = 012;long型可以用long test = 012l 也可以用 test=012赋值 

B. float f = -412;对于float = 412.0的时候必须在其后面加上f,但是f=12就不需要了,因为java会检查,自动将12转换成float

C. int other = (int) true;

D. double d = 0x12345678;

E. byte b = 128;

对于float和double都是小数型,默认是double,所以当我们定义的float 变量赋的值为小数型的时候,必须加上f或者F来明确表示其类型。


三、自增自减运算符案例及其原理详细讲解

原理:对于a++++a这两种方式有这么一句话很明显的表示出了他们的区别,就是++在前,先运算后再使用a++在后,先使用a后再运算。有以下三种例题:

第①题:

int a=4;int b=3;

System.out.println(“a=”+a+”,b=”+b);

运算结果是a=4,b=4

 

第②题:

int a=4;

int b=a++;

System.out.println(“a=”+a+”,b=”+b);

运算结果是a=5,b=4

 

第③题:

int a=4;

a=a++;

System.out.println(“a=”+a);

运算结果是a=4

 

剖析:对于第①题没有什么好说的,我们来看看第②题的内存变化,我们可以有下图来进行阐述:


以上的过程可以简化成以下几步:

1.a的内存空间中存储了a的内容,a=4.

2.a的临时存储空间中也存储了a的内容,temp=a=4;

3.a进行自增运算,此时a的值为5;

4.最关键的一步,对于a++而言,给b的赋的值不是a运算后的值,而是a临时存储的那个值,即b=temp=4;

 

对于第③题就更简单了,有如下图示,运算过程是这样的:

1.a的内存中存储了a的值:a=4

2.a的临时存储空间也存储了a的内容:temp=4

3.a进行自增运算:a=a+1=5;

4.将临时存储空间的值赋值给a:a=temp=4;


四、小知识-一些不太容易引起重视却很重要的细节

4.1 java中的作用域与变量

       在学习到变量的时候我们知道变量的三要素是类型、名称和值。其实变量还有一个很重要的要素,那就是作用域,即变量能够存在或者说活动的范围。java中我们用{}来规定变量的作用域,就是说变量声明或者说是定义在哪一对{}中,它的作用域就有多大。例如一个变量定义在main方法中,就是所它定义在main方法所在的{}中,它的作用域就在整个main方法中;定义在一条语句中,作用域就只在那么一条语句中;定义在类中,那么作用域就存在整个类中,定义在一个函数中,作用域就只有那个函数所有。一旦函数结束,变量也就会释放内存空间,即消失在内存中。举几个例子如下所示:

       ①{int x=8;}  作用域只在局部代码块中

       ②show(){int x=8;}  作用域只在整个函数中

       ③class{int x=8;}  作用域只在整个类中

       ④for(int x=0;i<6;i++){}  作用域只在整个for循环内

       当然,除了以上的方式,java中还有两种关键字与变量的作用域有些关系,分别是static和权限访问修饰符。这两种修饰符只能使用在成员变量的修饰上。权限修饰符有四种,在后面的内容中我们会有讲到,它们主要的作用是控制访问的权限,而static的作用是控制变量存在的时间,一旦被声明为static,该变量就成为了静态变量,只要虚拟机加载了拥有静态变量的类,在虚拟机没有结束的情况下,该变量就不会释放空间。

有这么一道基础测试题,比较好的应用这些知识,如下所示:

 编译并运行以下代码将发生什么? ( E)

public static void main(String args[]){

     char digit = 'a';

     for (int i = 0; i < 10; i++){

       switch (digit)

       {

         case 'x' :

         {

         int j = 0;System.out.println(j);

         }

         default :

         {

         int j = 100;System.out.println(j);

         }

       }

    }

int i = j;

    System.out.println(i);

}

A. 输出11100

B. 输出10100,然后抛出运行期异常

C. 编译错误,因为变量i不能在main() 方法中被声明2

D. 编译错误,因为变量j不能在main() 方法中被声明2

E. 以上都不对


4.2 结束标识符";"与{}

    我们知道,java中的一条语句的结束必须以分号结尾。纵观整个java语言,java中的结束标志总共有两个,一个是分号,一个是大括号。在java中,一般情况下,所有的语句的结束标记都是分号,所有的函数以及判断、循环结构等都是以大括号结尾的。


原创粉丝点击