《Android程序员面试分类模拟1.docx》由会员分享,可在线阅读,更多相关《Android程序员面试分类模拟1.docx(30页珍藏版)》请在三一办公上搜索。
1、Android程序员面试分类模拟1论述题1. 什么是实例变量?什么是局部变量?什么是类变量?什么是final变量?正确答案:实例变量:变量归对象所有,只有在实例化对象后才可以。每当实例化一个对象时(江南博哥),会创建一个副本并初始化,如果没有显示初始化,会初始化一个默认值:各个对象中的实例变量互不影响。局部变量:在方法中定义的变量,在使用前必须初始化。类变量:用StatiC可修饰的属性;变量归类所有,只要类被加载,这个变量就可以被使用(类名,变量名所有实例化的对象共享类变量。final变量:表示这个变量为常量,不能被修改。2. Java中作用域有哪些?正确答案:在计算机程序中,声明在不同地方的
2、变量具有不同的作用域,例如:局部变量、全局变量等。在JaVa语言中,作用域是由花括号的位置决定的,它决定了其定义的变量名的可见性与生命周期。在JaVa语言中,变量的类型主要有3种:成员变量、静态变量和局部变量。类的成员变量的作用范围与类实例化对象的作用范围相同,当类被实例化的时候,成员变量就会在内存中分配空间并初始化,直到这个被实例化对象的生命周期结束时,成员变量的生命周期才结束。被StatiC修饰的成员变量被称为静态变量或全局变量,与成员变量不同的是静态变量不依赖于特定的实例,而是被所有实例所共享,也就是说只要一个类被加载,JW就会给类的静态变量分配存储空间。因此,就可以通过类名和变量名来访
3、问静态变量。局部变量的作用范围与可见性为它所在的花括号内。此外,成员变量也有4种作用域,它们的区别如下表所示。作用域的对比作用域/可见性当前类同-package/类其他packagepublicJprivateJXprotecteddefaultpublic:表明该成员变量或方法对所有类或对象都是可见的,所有类或对象都可以直接访问。private:表明该成员变量或方法为私有的,只有当前类对其有访问权限,除此之外其他类或者对象都没有访问权限。protected:表明成员变量或方法对该类自身,与它在同一个包中的其他类,在其他包中的该类的子类都可见。default:只有自己和与其位于同一包内的类可见
4、。如果父类与子类位于同一个包内,则子类对父类的default成员变量或方法都有访问权限,但是如果父类与子类位于不同的PaCkage(包)内,则没有访问权限。需要注意的是这些修饰符只能修饰成员变量,不能用来修饰局部变量。private与protected不能用来修饰外部类(只有publicabstract或final能用来修饰外部类),但它们可以用来修饰内部类。3. Overload和OVelTide有什么区别?正确答窠:OVerload(重载)和OVeiride(覆盖)是JaVa多态性的不同表现。其中,Overload是在一个类中多态性的一种表现,是指在一个类中定义了多个同名的方法,它们或有不
5、同的参数个数或有不同的参数类型。在使用重载时,需要注意以下几占1)重载是通过不同的方法参数来区分的,例如:不同的参数个数、不同的参数类型或不同的参数顺序。2)不能通过方法的访问权限、返回值类型和抛出的异常类型来进行重载。3)对于继承来说,如果基类方法的访问权限为PriVate,那么就不能在派生类时对其重载,如果派生类也定义了一个同名的函数,这只是一个新的方法,不会达到重载的效果。OVellide是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同的作用。在使用覆盖时需要注意以下几点:1)派生类中的程盖的方法必须要和基类中被溟盖的方法有相同的方法名和参数。2)派生类中的覆盖方法的返回值
6、必须和基类中被覆盖方法的返回值相同。3)派生类中的覆盖方法所抛出的异常必须和基类中被覆盖的方法所抛出的异常一致或是其子类。4)基类中被覆盍的方法不能为private,否则其子类只是定义了一个方法,并没有对其实现覆番。重载与覆盖的区别主要有以下几个方面的内容:D覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。2)覆盖只能由个方法或只能由一对方法产生关系;方法的重载是多个方法之间的关系。3)覆盖要求参数列表相同;重载要求参数列表不同。1. 覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定的;而重载关系是根据调用时的实参表与形参表来选择方法体的
7、。4. 如何理解UniCOdC编码?正确答案:对于计标质而言,它只能识别01字串,但是Ol字串可读性太差,因此就需要把可读性更好盼字符串转换为Ol字串存储在计算机中。那么如何建立可读字符与Ol字串之间的关系呢?这就需要一个标准,在Java中使用的是Unicode标准,这个标准定义了字符与数字之间的映射关系。Unicode的第一个版本是用两个字节(16bit)来表示所有字符,其实Unicode标准主要涉及两个方面:D规范会定义字符与数字之间的映射关系,也就是说规范会给每个字符指定唯一的数字。2)如何在计算机中存储字符对应的数字。于是出现r不同的存储方式,例如:UTF-8和UTF-16等编码。为了
8、理解不同编码的区别,下面以UTF-8和UTF-16为例来介绍它们的区别。UTFT6使用定长的字节存储,也就是说,对于任意的字符,都是用两个字节来存储,而UTF-8则使用变长的字节来存储。例如“汉”字对应的UniCode编码是6C49(二进制:0110110001001001,十进制:27721)。如果使用UTFT6来存储这个汉字,那么只需要使用两个字节存储6C49即可。但是如果要使用UTF-8来存储6C49,首先需要确定需要几个字节来保存这个数字,而UTF-8由于里面有额外的标志信息,所有1个字节只能表示2的7次方128个字符,两个字节只能表示2的11次方2048个字符,而3个字节能衣示2的1
9、6次方,65536个字符。显然“汉”的编码介于2048与65536之间,因此需要3个字节来保存。UTF-8使用下面的方法来确定一个字符使用了几个字节来保存:1)1个字节,使用OXXXXXXX的格式,XX代表任意实际的编码;2)2个字节:1IOxxxxxIOxxxxxx;3)3个字节:11IOxxxxIOxxxxxx1Oxxxxxxo显然,对于“汉”,使用UTF-8保存的时候,保存的内容为IUo(HlO1011000110001001(E68189)下面通过一个例子来加深理解:importjava.io.UnsupportedEncodingException;publicclassTestpr
10、ivatestaticfinalStringHEX_DIGITS=Pl23456789ABCDEF”;publicstaticStringhexConvert(bytebuf,intlength)if(buf=null)return(null);StringBuffcrsb=newStringBuffer(2*length):for(inti=0;i4):sb.append(HEXDIGITS.charAt(bufi&0x000000F);Ireturn(sb.toString():)publicstaticvoidencodeBytes(Stringstr)throwsIlnsupporte
11、dEncodingExceptionSystem,out.Println(+str+”占用的字节数”);byteb;b=str.getBytes(UTF-8);System,out.printIn(wUTF8编码:+b.length+”字节+HEX=ThexConvert(b,b.length):b=str.gelBytes(UTFT6);SyStem.out.printIn(UTF16编码:+b.length+”字节+HEX=+hexConvert(b,b.length):b=str.getBytes(Unicode);System,out.printin(Unicode:+b.length
12、+”字节,+*HEX=*+hexConvert(bb.length);b=str.getBytesO;System,out.Println(默认编码“+System,getProPerly(file.encoding)+编码:+b.length+”字节+HEX=+hexConvert(b,b.length);publicstaticvoidmain(Stringargs)throwsUnsupportedEncodingException(encodeBytes(汉);encodeBvtes(*a*);)程序运行结果为:汉占用的字节数UTF8编码:3字节HEX=E6B189IJTFI6编码:4
13、字节HEX=FEFF6C49Unicode:4字节HEX=FEFF6C49默认编码UTF-8编码:3字节HEX=E6B189a占用的字节数UTF8编码:1字节HEX=61UTF16编码:4字节HEX=FEFFo061Unicode:4字节HEX=FEFFO061默认编码UTF-8编码:1字节HEX=61从运行结果可以发现,“汉”这个字符在使用UTF-8编码的时候与上面的分析结果相同,而使用UTF-8保存英文字符只需要1个字节。而UTF-16使用了4个字节来保存所有字符,其中开头的两个字节表示字节序,FEFF表示大端(从左到右填充),FFEF表示小端(从右到左填充)。如果指定字节序,那么就只需要
14、两个字节。上面介绍的UniCode只能表示65536个字符,为了表示更多的字符,出现了UniCodC的第二个版本,可以用4个字节表示所有字符,相对应地也就出现了UTF-8、UTF-16和UTF-32等编码。这里就不详细介绍了。JVM规范规定JaVa采用UTF-16编码作为内码,也就是说在JVM内部,字符是用两个字节表示的。5. 运行时异常和普通异常有什么区别?正确答案:Java提供Jz两种错误的处理类,分别为Error和Exception.且它们拥有共同的父类:ThrowableeErrOr表示程序在运行期间出现了非常严重的错误,且该错误是不可恢复的,由于这属于JVM层次的严重错误,会导致程序
15、终止执行。此外,编译器不会检杳ErrOr是否被处理,因此在程序中不推荐去捕获ErrOr类型的异常,主要原因是运行时异常多是由于逻辑错误导致的,属于应该解决的错误,也就是说一个正确的程序中是不应该存在Error的。OUlofMCmoryE门pr、ThreadDcath等都属于错误。当这些异常发生时,JVM一般会选择将线程终止。EXCePtiOn表示可恢复的异常,是编译器可以捕捉到的。它包含两种类型:运行时异常(运runtimeexception)和普通异常(有时也被叫作CheCkedexception)。1)检查异常走在程序中最经常碰到的异常,所有继承闩EXCePtion并且不是运行时异常的异常
16、都是检查异常,例如最常见的10异常和SQ1.异常。对于这种异常,都发生在编译阶段,Java编译器强制程序去捕获此类型的异常,即把可能会出现这些异常的代码放到try块中,把对异常的处理的代码放到catch块中。这种异常一般在如下几种情况中使用。异常的发生并不会导致程序出错,进行处理后可以继续执行后续的操作;如连接数据库失败后,可以重新连接后进行后续操作。程序依赖于不可靠的外部条件,如系统1002)对于运行时异常,编译器没有强制对其进行捕获并处理。如果不对这种异常进行处理,当出现这种异常时,会由JVV来处理。例如:NUIIPointerEXCePtiOn异常,它就是运行时异常。在JaVa语言中,最
17、常见的运行时异常有如下几种:NUIlPOinterEXCePtiOn(空指针异常)、ArrayStOreEXCePtion(数据存储异常)、CIaSSCaSlEXCePtiOn(类型转换异常)、IneXOUtOfBoUndEXCePtiOn(数组越界异常)、AiTayStoreException(数据存储异常)、BUfferOVerfloWEXCePtion(缓冲区溢出异常)和ArithmetiCEXCePtion(算术异常)等。出现运行时异常后,系统会把异常一直往上层抛,直至遇到处理代码为止。如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()
18、抛出。抛出之后,如果是线程,这个线程也就退出了如果是主程序抛出的异常,那么整个程序也就退出了。所以,如果不对运行时异常进行处理,后果是非常严重的,一旦发生,要么是线程中止,要么是主程序终止。在使用异常处理时,还需要注意以卜几个问题:I)JaVa异常处理用到了多态的概念,如果在异常处理过程中,首先捕获了基类,然后再捕获子类,那么捕获子类的代码块将永远不会被执行。因此,在进行异常捕获的时候,正确的写法是:首先捕获子类,然后再捕获基类的异常信息。如下例所示:正确的写法错误的写法叫/Zaccessdbcodecatch(SQ1.Excq)6onel)/(IealwiihthisexceptionIca
19、tcb(ExceptioneZ)O/Zaccessdbcodecatch(Excepionel)A,dealWiththisexceptioncatch(SQ1.Exccptiofle2)(2)尽早抛出异常,同时对捕获的异常进行处理,或者从错误中,恢熨,或者让程序继续执行。对捕获的异常不进行任何处理是一个非常不好的习惯,这样的代码将非常不利于调试。但也不是抛出异常越多越好,对于有些异常类型,例如运行时异常,实际上根本不必处理。3)可以根据实际的需求自定义异常类,这些自定义的异常类只要继承自Exception类即可。4)异常能处理就处理,不能处理就抛出。对于一般异常,如果不能进行行之有效的处理,
20、最好转换为运行时异常抛出。最终没有处理的异常JVM会进行处理。6. break、COntinUe以及relurn的区别是什么?正确答案:break:直接强行跳出当前循环,不再执行剩余部分。当循环中遇到break语句时,忽略循环体中任何其他语句和循环条件测试,程序控制在循环后面语句重新开始。所以,当多层循环嵌套,break语句出现在嵌套循环中的内层循环,它将仅仅只是终止了内层循环的执行,而不影响外层循环的执行。continue:停止当次循环,回到循环起始处,进入下一次循环操作。ContinUe语句之后的语句将不再执行,用于跳过循环体中的一部分语句,也就是不执行这部分语句,而不是跳出整个循环执行下
21、一条语句,这就是ContinUe与break的主要区别。简单地说,continue只是中断一次循环的执行而已。return:return语句是一个跳转语句,用来表示从一个方法返回(返回一个值或其他复杂类型,可以使程序控制返回到调用它方法的地方。当执行main方法时,return语句可以使程序执行返回到Java运行系统。由于break只能跳出当前的循环,那么如何才能实现跳出多重循环呢?可以在多重循环的外面定义一个标识,然后在循环体里使用带有标识的break语句即可跳出多重循环。例如:publicclassBreak(publicstaticvoidmain(Stringargs)(out:for
22、(inti=0;i5;i+)for(intj=0jj=2)breakout;System,out.rintln(j);I“System,out.printIn(*break*):)程序运行结果为:01break上例中,当内部循环j=2时,程序跳出双重循环,执行System.OUt.printIn(break)语句。7. abstractCIaSS(抽象类)与interface(接口)有何异同?正确答案:如果一个类中包含抽象方法,那么这个类就是抽象类。在JaVa语言中,可以通过把类或者类中的某些方法声明为abstract(abstract只能用来修饰类或者方法,不能用来修饰属性)来表示一个类是抽
23、象类。只要包含一个抽象方法的类就必须被声明为抽象类,抽象类可以声明方法的存在而不去实现它,被声明为抽象的方法不能包含方法体。在实现时,必须包含相同的或者更低的访问级别(public-protected-private)抽象类在使用的过程中不能被实例化,但是可以创建个对象使其指向具体夕类的一个实例。抽象类的夕类为父类中所有的抽象方法提供具体的实现,否则它们也是抽象类。接口就是指一个方法的集合,在JaVa语言中,接口是通过关键字interface来实现的。在JDK8之前,接口中既可以定义方法也可以定义变量,其中变量必须是PUbIic、StatiC或final,而方法必须是PUbliC或abstra
24、ct.由于这些修饰符都是默认的,所以在JDK8之前,卜.面的写法都是等价的。interfaceI1(publicstaticfinalintidl=0;intid2=0;publicabstractvoidflO;voidf2();)从JDK8开始,通过使用关键字default可以给接口中的方法添加默认实现,此外,接口中还可以定义静态方法,示例代码如下所示:interfaceInter8defaultvoidg()System,out.printIn(wthisisdefaultmethodininterface*);)staticvoidh()System,out.printIn(*this
25、isstaticmethodininterface*):)那么,为什么要引入接口中方法的默认实现呢?其实,这样做的最重要的一个目的就是为了实现接口升级。在原有的设计中,如果想要升级接口,例如给接口中添加一个新的方法,那么会导致所有实现这个接口的类都需要被修改,这给Java语言已有的一些框架进行升级带来了很大的麻烦。如果接口能支持默认方法的实现,那么可以给这些类库的升级带来许多便利。例如,为了支持1.ambda表达式,CCdIeCtion中引入了foreach方法,可以通过这个语法增加默认的实现,从而降低了对这个接口进行升级的代价,不需要对所有实现这个接口的类进行修改。在JDK8之前,实现接口的
26、非抽象类必须要实现接口中的方法,在JDK8中引入接口中方法的默认实现后,实现接口的类也可以不实现接口中的方法,例如:classimplementsInter8(接口中的方法已经有r默认的实现,因此,这里可以重写方法的实现,也可以使用默认的实现)接口中的静态方法只能通过接口名来调用,不可以通过实现类的类名或者实现类的对象来调用。而default方法则只能通过接口实现类的对象来调用。示例代码如下:PUbIiCstaticvoidnain(Stringargs)(Inter8.h();newO.gO:)在JaVa中由于不支持多重继承,也就是说一个类只能继承一个父类,不能同时继承多个父类,但是一个类可
27、以实现多个接口。因此经常通过实现多个接口的方式来实现多重继承的目的。那么如果多个接口中存在同名的static和default方法会有什么样的情况发生呢?静态方法并不会导致歧义的出现,因为静态方法只能通过接口名来调用;对于default方法来说,在这种情况下,这个类必须要重写接口中的这个方法。否则无法确定到底使用哪个接口中默认的实现。从上面的介绍可以看出接口与抽象类有很多相似的地方,那么它们有哪些不同点呢?(1)抽象类D抽象类只能被继承(用extends),并且一个类只能继承一个抽象类。2)抽象类强调所屈关系,其设计理念为is-a关系。3)抽象类更倾向于充当公共类的角色,不适用于R后重新对里面的
28、代码进行修改。4)除了抽象方法之外,抽象类还可以包含具体数据和具体方法(可以有方法的实现)。5)抽象类不能被实例化,如果子类实现了所有的抽象方法,那么子类就可以被实例化了。如果子类只实现了部分抽象方法,那么子类还是抽象类,不能被实例化。接口1)接口需要实现(用implements),一个类可以实现多个接口,因此使用接口可以间接地实现多重继承的目的。2)接口强调特定功能的实现,其设计理念是has-a关系o3)接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法。4)接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。5)接口中的所有方法都是PUbIiC的,因此,在
29、实现接口的类中,必须把方法声明成PUblic,因为类中默认的访问属性是不可见的,而不是PUblic,这就相当于在了类中降低/方法的可见性,会导致编译错误。总之,接口是种特殊形式的抽象类,使用接口完全有可能实现与抽象类相同的操作,但一般而言,抽象类多用于在同类事物中有无法具体描述的方法场景,所以当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类,而接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。此外,接口可以继承接口,抽象类可以实现接口,也可以继承具体类还也可以有静态的main方法。8. 为什么Java中有些接口没
30、有声明任何方法?正确答案:由于JaVa不支持多重继承,即一个类只能有一个父类,为了克服单继承的缺点,Java语言引入了接D这一概念。接口是抽象方法定义的集合(接口中也可以定义一些常量值),是一种特殊的抽象类。接口中只包含方法的定义,没有方法的实现(JaVa8引入了接口的默认方法与静态方法,也就是说从Java8开始,接口也可以包含行为,而不仅仅包含方法的定义)。接口中成员的作用域修饰符都是PUbIia接口中的常量值默认使用PUbIiCstaticfinal修饰。由于一个类可以实现多个接口,因此通常可以采用实现多个接口的方式来间接地达到多重继承的目的。在JaYa语言中,有些接口内部没有声明任何方法
31、,也就是说实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被称为标识接口,标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识的作用,用来表明实现它的类属于一个特定的类型。这个标签类似于汽车的标志图标,每当人们看到个汽车的标志图标时,就能知道这款汽车的品牌。JaVa类库中已存在的标识接口有Cloneable和Serializable等。在使用的时候会经常用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。下面通过一个例子来详细说明标识接口的作用。例如要开发一款游戏,游戏里面有一个人物角色专门负贡出去寻找有用的材料,假设这个人物只收集矿石和武器,而不会
32、收集垃圾,下例通过标识接口来实现这个功能。importjava,uti1.Array1.ist;interfaceStuff矿石interfaceOreextendsStuff武器interfaceWeaponextendsStuff()垃圾interfaceRubbishextendsStuff金矿classGoldimplementsOrepublicStringtoString()returnGold;II/铜矿classCopperimplementsOre(publicStringtoString()return“Copper”;)枪classGunimplementsWeapon(
33、publicStringtoString()It“returnGun;)/榴弹classGrenadeimplementsWeaponpublicStringtoString()returnGrenade”;)classStoneimplementsRubbish(publicStringtoString()(return“Stone”;)publicclassTestpublicstaticArray1.istcolIectStuff(Stuffs)Array1.istal=newArray1.isKStuffO;for(inti=0;is.length;i+)(if(!(siinstanc
34、eofRubbish)al.add(si);)returnal;)publicstaticvoidmain(Stringargs)Stuffs=newGold(),newCopper(),newGunO,newGrenadeO,newStoneO);Array1.istal=colIectStuff(三);System,out.printIn(wTheuseful!Stuffcollectedis:);for(inti=0;iGrenade.因此会收集,只要是实现RUbbiSh的类,都会被认为是无用的东西,例如Stonc,因此不会被收集。9. finally块中的代码什么时候被执行?正确答案:
35、问题描述:try里有一个return语句,那么紧跟在这个try后的finally。里的code会不会被执行?什么时候被执行?在return前还是后?在Java语言的异常处理中,finally语句块的作用就是为了保证无论出现什么情况,finally块里的代码一定会被执行。当程序执行return的时候就意味着结束对当前方法的调用并跳出这个方法体,任何语句要执行都只能在return前执行(除非碰到exit函数),因此finally块里的代码也是在return前执行的。此外,如果try-finalIy或者CatCh-finally中都有return,则finally块中的return语句将会覆盖别处的
36、return语句,最终返回到调用者那里的是finally中return的值。卜面通过一个例子(示例1)来说明这个问题。publicclassTestpublicstaticinttestFinally()tryreturn1;catch(Exceptione)return0;finallySystem,out.PrintIn(executefinally);)publicstaticvoidmain(Stringargs)intresult=testFinally();System,out.rintln(result);)程序运行结果为:executefinally1从上面这个例子中可以看出,
37、在执行return前确实执行了finally中的代码。紧接者,在finally块里面放置一个return语句,例子(示例2)如下所示:publicclassTestpublicstaticinttestFinally()try(return1;catch(Exceptione)return0;finallySystem,out.PrintIn(executefinally*);return3;)publicstaticvoidmain(Stringargs)intresult=testEinally():System,out.println(result);)程序运行结果为:executefi
38、nally3从以上运行结果可以看出,当finally块中有return语句时,将会覆盖函数中其他return语句。此外,由于在一个方法内部定义的变量都存储在栈中,当这个函数结束后,其对应的栈就会被回收,此时在其方法体中定义的变量将不存在,因此return在返回的时候不是直接返回变量的值,而是复制一份,然后返回。因此,对于基本类型的数据,在finally块中改变retum的值时返回值没有任何影响,而对于引用类型的数据,就有影响。下面通过一个例子(示例3)来说明这个问题。publicclassTestpublicstaticintIestFinallyl()intresult=l;try(resu
39、lt=2;returnresult:catch(Exceptione)return0;finallyresult=3;System,out.PrintIn(executefinalIylw);)pubicstaticStringBuffertestFinally2()StringBuffers=11ewSlringBufferCHello);try(returns;catch(Exceptione)returnnull:finallys.append(Wor1c);System,out.println(*executefinaUy2*);)publicstaticvoidmain(String
40、args)i11tresultVal=testFinallyl();System.out.println(resultVal);StringBufferresultRef=testFinally2();System,out.println(resultRef);)程序运行结果为:executefinallyl2executefinally2HelloWorld程序在执行到return的时候会首先将返回值存储在一个指定的位置,然后去执行finally代码块,然后再返回。在方法IestFinallyl中调用return前首先把result的值1存储在一个指定的位置,然后再去执行finally块中的
41、代码,此时修改result的值将不会影响到程序的返回结果OtCSlFinalIy2中,在调用return前首先把S存储到一个指定的位置,由于S为引用类型,因此在finally块中修改S将会修改程序的返回结果。10. switch使用时有哪些注意事项?正确答案:在使用s%itch(expr)的时候,expr只能是一个枚举常量(内部也是由整型或字符类型实现)或一个整数点达式,其中整数表达式可以是基本类型int或其对应的包装类Integer,当然也包括不同的长度整型,例如ShortO由于byte、short和char都能够被隐式地转换为ini类型,因此这些类型以及它们对应的包装类型都可以作为SWit
42、Ch的表达式O但是,long、float、double、String类型由于不能够隐式地转换为int类型,因此它们不能被用作switch的表达式。如果一定要使用long、float或double作为SWiICh的参数,必须将其强制转换为int型才可以。例如以下使用就是非法的:floata=0.123;SWiICh(八)错误!a不是整型或字符类型变量)另外,与SWilCh对应的是CaSe语句,case语句之后可以是直接的常量数值,例如1、2,也可以是一个常量计算式,例如1+2等,还可以是final型的变量(final变量必须是编译时的常量),例如finalinta=0,但不能是变量或带有变量的表
43、达式,例如i*2等。当然更不能是浮点型数,例如1.1,或1.2/2等。switch(formWay)(case2-1:正确* break;casea-2:错误* break;case 2: 0:错误break;)随着JaVa语言的发展,在Java7中,switch开始支持String类型。以下是一段支持string类型的示例代码。publicclassTestublicvoidtest(Stringstr)(switch(str)(caseone”:System,out.println(*Thisis1);break;case*two*:System.out.printInCThisis2);
44、break;case“three”:System.out.println(*Thisis3);break;default:System,out.Println(default);)从本质上来讲,SWitCh对字符串的支持,其实是int类型值的匹配。它的实现原理如下:通过对CaSe后面的String对象调用hashCode0方法,得到一个int类型的hash值,然后用这个hash值来唯一标识这个case。那么当匹配的时候,首先调用这个字符串的hashCode()方法,获取一个hash值(int类型),用这个hash值来匹配所有的case,如果没有匹配成功,说明不存在:如果匹配成功,接着会调用字符
45、串的SIring.equals。方法进行匹配。由此可以看出String变量不能为null,同时switch的CaSe子句中使用的字符串也不能为nulIo在使用switch的时候需要注意的另外一个问题是:一般必须在CaSe语句结尾添加break语句。因为一旦通过SWitCh语句确定了入口点,就会顺序执行后面的代码,直到遇到关键字break。否则,会执行满足这个CaSe之后的其他CaSe的语句而不管CaSe是否匹配,宜到SwitCh结束或者遇到break为止。如果在SWitCh中省略/break语句,那么匹配的case值后的所有情况(包括default)都会被执行。如下例所示:publicclassTestpublicstaticvoidmain(Stringargs)(intx=4;switch(x)(case1:System,out.println(x);case2:System,out.println(x):case 3:System,out.println(x):case 4:System,out.println(x);case