换句话说,复合赋值表达式自动地将所执行计算的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,那么这个转型不会造成任何影响。然而,如果结果的类型比该变量的类型要宽,那么复合赋值操作符将悄悄地执行一个窄化原生类型转换。
因此,复合赋值表达式可能是危险的。为了避免这种令人不快的突袭,请不要将复合赋值操作符作用于byte、 short 或char类型的变量。
因为 S1 是 short 型的,占2个字节,而 1 是int型的,占4个字节。在两个类型的值相加的时候,会发生自动类型的提升。也就是说 s1 + 1 后,其结果是int型的,而不是 short 型的,所以可以想想看,把4个字节的东西放在两个字节的空间里,肯定编译不通过。
后面的那个不会发生类型的提升,JAVA规范上说 e1+=e2 实际上是 e1=(T1)(e1+e2),其中T1是e1的数据类型。 s1+=1等效于 s1=(short)(s1+1),所以是正确的。
1、自动类型转换
自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换。由于实际开发中这样的类型转换很多,所以 Java 语言在设计时,没有为该操作设计语法,而是由 JVM 自动完成。
转换规则:从存储范围小的类型到存储范围大的类型。
具体规则为:byte→short(char)→int→long→float→double
也就是说 byte 类型的变量可以自动转换为 short 类型,示例代码:
byte b=10;
short sh=b;
这里在给sh赋值时,JVM首先将b的值转换成short类型然后再赋值给sh。
当然,在类型转换的时候也可以跳跃,就是byte也可以自动转换为int类型的。
注意问题:在整数之间进行类型转换的时候数值不会发生变化,但是当将整数类型特别是比较大的整数类型转换成小数类型的时候,由于存储精度的不同,可能
会存在数据精度的损失。
2、强制类型转换
强制类型转换,也称显式类型转换,是指必须书写代码才能完成的类型转换。该类类型转换很可能存在精度的损失,所以必须书写相应的代码,并且能够忍受该种
损失时才进行该类型的转换。
转换规则:从存储范围大的类型到存储范围小的类型。
具体规则为:double→float→long→int→short(char)→byte
语法格式为:(转换到的类型)需要转换的值
double d=3.14;
int i=(int) d;
注意问题:强制类型转换通常都会存储精度的损失,所以使用时需要谨慎。
三、常见面试题:
1、short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 +=1;有什么错?
答:对于short s1=1;s1=s1+1来说,在s1+1运算时会自动提升表达式的类型为int,那么将int赋予给short类型的变量s1会出现类型转换错误。
对于short s1=1;s1+=1来说 +=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
2、char类型变量能不能储存一个中文的汉子,为什么?
char类型变量是用来储存Unicode编码的字符的,unicode字符集包含了汉字,所以char类型当然可以存储汉字的,还有一种特殊情况就是某个生僻字没有包含在
unicode编码字符集中,那么就char类型就不能存储该生僻字。
3、Integer和int的区别
int是java的8种内置的原始数据类型。Java为每个原始类型都提供了一个封装类,Integer就是int的封装类。
int变量的默认值为0,Integer变量的默认值为null,这一点说明Integer可以区分出未赋值和值为0的区别,比如说一名学生没来参加考试,另一名学生参加考
试全答错了,那么第一名考生的成绩应该是null,第二名考生的成绩应该是0分。关于这一点Integer应用很大的。
Integer类内提供了一些关于整数操作的一些方法,例如上文用到的表示整数的最大值和最小值。
4、switch语句能否作用在byte上,能否作用在long上,能否作用在string上?
byte的存储范围小于int,可以向int类型进行隐式转换,所以switch可以作用在byte上
long的存储范围大于int,不能向int进行隐式转换,只能强制转换,所以switch不可以作用在long上
string在1.7版本之前不可以,1.7版本之后switch就可以作用在string上了。
Switch-case-default
case 后面不可以放变量
判断整数:byte short char int enum
满足条件的case开始,向后执行所有case;
直到遇到break为止,遇到default也不停止。
String a="hello world"; //在java中有一个常量池,当创建String 类型的引用变量给它赋值时,java会到它的常量池中找"hello world"是不是在常量池中已存在。如果已经存在则返回这个常量池中的"hello world"的地址(在java中叫引用)给变量a 。注意a并不是一个对象,而是一个引用类型
的变量。它里面存的实际上是一个地址值,而这个值是指向一个字符串对象的。在程序中凡是以"hello world"这种常量似的形式给出的都被放在常量池中。 String b=new String("hello world"); //这种用new关键字定义的字符串,是在堆中分配空间的。而分配空间就是由new去完成的,由new去决定分配多大空间,并对空间初始化为字符串"hello world" 返回其在堆上的地址。 通过上面的原理,可以做如下实验: String a="hello world"; String b="hello world"; String c=new String("hello world"); String d=new String("hello world"); if(a==b) System.out.println("a==b"); else System.out.println("a!=b"); if(c==d) System.out.println("c==d"); else System.out.println("c!=d"); //输出结果: a==b c!=d 为什么会出现上面的情况呢? String a="hello world"; String b="hello world"; 通过上面的讲解可以知道,a和b都是指向常量池的同一个常量字符串"hello world"的,因此它们返回的地址是相同的。a和b都是引用类型,相当于c语言里面的指针。java里面没有指针的概念,但是实际上引用变量里面放的确实是地址值,只是java为了安全不允许我们对想c语言中的那样对指针进行操作(如++ 、--)等。这样就有效的防止了指针在内存中的游离。 而对于 String c=new String("hello world"); String d=new String("hello world"); 来说是不相等的,他们是有new在堆中开辟了两块内存空间,返回的地址当然是不相等的了。如果我们要比较这两个字符串的内容怎么办呢?可以用下面的语句: if(c.equals(d)) System.out.println("c==d"); else System.out.println("c!=d"); //输出 c==d
12. 0.6332的数据类型是()
A float B double C Float D Double
答案:B
解析:默认为double型,如果为float型需要加上f显示说明,即0.6332f
5. 具体选项不记得,但用到的知识如下:
String []a = new String[10];
则:a[0]~a[9] = null
a.length = 10
如果是int []a = new int[10];
则:a[0]~a[9] = 0
a.length = 10
12. 0.6332的数据类型是()
A float B double C Float D Double
答案:B
解析:默认为double型,如果为float型需要加上f显示说明,即0.6332f
13. 下面哪个流类属于面向字符的输入流( )
A BufferedWriter B FileInputStream C ObjectInputStream D InputStreamReader
答案:D
解析:Java的IO操作中有面向字节(Byte)和面向字符(Character)两种方式。
面向字节的操作为以8位为单位对二进制的数据进行操作,对数据不进行转换,这些类都是InputStream和OutputStream的子类。
面向字符的操作为以字符为单位对数据进行操作,在读的时候将二进制数据转为字符,在写的时候将字符转为二进制数据,这些类都是Reader和Writer的子类。总结:以InputStream(输入)/OutputStream(输出)为后缀的是字节流;
以Reader(输入)/Writer(输出)为后缀的是字符流。
扩展:Java流类图结构,一目了然,解决大部分选择题:
14. Java接口的修饰符可以为()
A private B protected C final D abstract
答案:CD
解析:接口很重要,为了说明情况,这里稍微啰嗦点:
(1)接口用于描述系统对外提供的所有服务,因此接口中的成员常量和方法都必须是公开(public)类型的,确保外部使用者能访问它们;
(2)接口仅仅描述系统能做什么,但不指明如何去做,所以接口中的方法都是抽象(abstract)方法;
(3)接口不涉及和任何具体实例相关的细节,因此接口没有构造方法,不能被实例化,没有实例变量,只有静态(static)变量;
(4)接口的中的变量是所有实现类共有的,既然共有,肯定是不变的东西,因为变化的东西也不能够算共有。所以变量是不可变(final)类型,也就是常量了。
(5) 接口中不可以定义变量?如果接口可以定义变量,但是接口中的方法又都是抽象的,在接口中无法通过行为来修改属性。有的人会说了,没有关系,可以通过 实现接口的对象的行为来修改接口中的属性。这当然没有问题,但是考虑这样的情况。如果接口 A 中有一个public 访问权限的静态变量 a。按照 Java 的语义,我们可以不通过实现接口的对象来访问变量 a,通过 A.a = xxx; 就可以改变接口中的变量 a 的值了。正如抽象类中是可以这样做的,那么实现接口 A 的所有对象也都会自动拥有这一改变后的 a 的值了,也就是说一个地方改变了 a,所有这些对象中 a 的值也都跟着变了。这和抽象类有什么区别呢,怎么体现接口更高的抽象级别呢,怎么体现接口提供的统一的协议呢,那还要接口这种抽象来做什么呢?所以接口中 不能出现变量,如果有变量,就和接口提供的统一的抽象这种思想是抵触的。所以接口中的属性必然是常量,只能读不能改,这样才能为实现接口的对象提供一个统 一的属性。
通俗的讲,你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现 implements)开放,接口是对开闭原则的一种体现。
所以:
接口的方法默认是public abstract;
接口中不可以定义变量即只能定义常量(加上final修饰就会变成常量)。所以接口的属性默认是public static final 常量,且必须赋初值。
注意:final和abstract不能同时出现。