【Java面试考点汇集 二】基本运算与流程处理
#基本运算
##运算符
java中只有整型能使用的运算符为%
可以看出来,虽然能用,都是结果不一定是正确的,也就是说编译可以通过,但实际用起来并没有什么用,得不到正确结果,所以求余运算%只能整形使用
###三目运算符("?:" )是右结合的!
boolean b=true?false:true==true?false:true;
System.out.println(b);
== 优先级高于 三目运算符,先判断 true == true,此时返回为 true,
这时表达式为 boolean b = true?false:true?false:true
此时三目运算符从右向左执行,true?false:true,返回false
这时表达式为 boolean b = true?false:false;
结果为:boolean b = false ;
###位移运算符
java中有三种移位运算符
<< : 左移运算符,num<< 1,相当于num乘以2
>> : 右移运算符,num>> 1,相当于num除以2
>>> : 无符号右移,忽略符号位,空位都以0补齐
###短路运算符
String s=null;
下列哪些代码会引发空指针异常:
if((s!=null)&(s.length()>0))//会,前一个false,后一个还会执行
if((s!=null)&&(s.length()>0))//不会,前一个false,后一个不会执行
if((s==null)|(s.length()<mark>0))//会,前一个true,后一个还会执行
if((s</mark>null)||(s.length()==0))//不会,前一个true,后一个不会执行
引发空指针异常的是后半句(s.length()==0)而**&&和||是短路运算符吗,前一个执行符合条件了,后一个就不会再执行了。**
###自增运算符
1,例题1
public class Test{
static{
int x=5; //这里是局部变量,对之后的x没什么影响,障眼法
}
static int x,y;
public static void main(String args[]){
x--; //此时x为-1
myMethod( );
System.out.println(x+y+ ++x);//此时左边第一项值为1,第二项为0,第三项开始运算,值为2,x为2,三项的和为3
}
public static void myMethod( ){
y=x++ + ++x; //首先执行x++,此时右边值为-1,x为0,然后执行++x,此时右边第二项值为1,x为1,两项结合为0,所以y为0,x为1.
}
}
注意: ++ 和 – 运算符 的优先级大于 算数运算符+
静态代码块变量分析
1,如果是以下这种情况就是局部变量,出了静态代码块就没用
public class Test {
static {
int x = 5;
}
static int x, y;
public static void main(String args[]) {
x--;
System.out.println(x);
}
}
运行结果为-1
2,如果是以下这种情况就是全局变量
public class Test {
static {
x = 5;
}
static int x, y;
public static void main(String args[]) {
x--;
System.out.println(x);
}
}
运行结果为4
例题2
public class Test{
private static int i=1;
public int getNext(){
return i++;
}
public static void main(String [] args){
Test test=new Test();
Test testObject=new Test();
test.getNext();
testObject.getNext();
System.out.println(testObject.getNext());
}
}
return i++, 先返回i,然后i+1;
第一次调用getNext()方法时,返回的是1,但此时i=2;
第二次调用getNext()方法时,返回的是2,但此时i=3;
第三次调用getNext()方法时,返回的是3,但此时i=4;
return的时候要看i++还是++i亦或是return i=i+1;,如果是i++注意只返回i的值,其它两种情况都是返回运算后的值
##类型转换
###数据类型
###一般转换
1,下面哪些赋值语句是正确的()
long test=012(8进制int型赋给long型的,不加l可以)
float f=-412(int型赋给float型的,不加f可以,但如果是412.0则必须加)
int other =(int)true (错误,布尔型不能和其它任何转换)
double d=0x12345678(16进制int型赋给double型的)
byte b=128(错误)
2,下列代码片段中,存在编辑错误的语句是()
byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7;
b3=(b1+b2); /语句1/
b6=b4+b5; /语句2/
b8=(b1+b4); /语句3/
b7=(b2+b5); /语句4/
System.out.println(b3+b6);
解析:
1、所有的byte,short,char型的值将被提升为int型;
2、如果有一个操作数是long型,计算结果是long型;
3、如果有一个操作数是float型,计算结果是float型;
4、如果有一个操作数是double型,计算结果是double型;
5、被fianl修饰的变量不会自动改变类型,当2个final修饰相操作时,结果会根据左边变量的类型而转化。
--------------解析--------------
语句1错误:b3=(b1+b2);自动转为int,所以正确写法为b3=(byte)(b1+b2);或者将b3定义为int;
语句2正确:b6=b4+b5;b4、b5为final类型,不会自动提升,所以和的类型视左边变量类型而定,即b6可以是任意数值类型;
语句3错误:b8=(b1+b4);虽然b4不会自动提升,但b1仍会自动提升,所以结果需要强转,b8=(byte)(b1+b4);
语句4错误:b7=(b2+b5); 同上。同时注意b7是final修饰,即只可赋值一次,便不可再改变。
被fianl修饰的变量不会自动改变类型
##常见进制
010 八进制 --8 0后边跟的数字不能超过7
0x8 十六进制 8 0x后边跟的数字不能超过F,F表示15
##原码,反码,补码
###定义
1,对于正数,原码和反码,补码都是一样的,都是正数本身.
2,对于负数
原码是符号位为1,数值部分取X绝对值的二进制.
反码是符号位为1,其它位是原码取反.
补码是符号位为1,其它位是原码取反,未位加1.
也就是说,负数的补码是其反码未位加1.
###补码加减法公式
1):补码加法公式
[X+Y]补 = [X]补 + [Y]补
2):补码减法公式
[X-Y]补 = [X]补-[Y]补 = [X]补 + [-Y]补
已知[+Y]补求[-Y]补的规则是全部位(含符号位)按位取反后再加1
###负数由补码求原码
1.如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码.不重点考虑。
2,如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1;其余各位取反,然后再整个数加1.
3,如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:补码整体减1得到反码;反码符号位不变,其余取反(反码按位取反=该负数绝对值)
例子:
以8位二进制操作为例,其运算取值范围是-128~127.
那么综上所述,我们可以得到-126-100,可以看成(-126)+(-100),目的是使减法操作变为加法在计算机中,实际上只有加法运算,减法运算也要转换为加法运算,
-126 -> 1111 1110 ->反 1000 0001 ->补 1000 0010
100 -> 0110 0100 -> 负数求补 1001 1011+1 -> 负补 1001 1100
做补码相加得 -126补+(-100) 补-> 1000 0010补 + 1001 1100补 ->1 0001 1110补 ->自然丢弃超出 0001 1110补
由补求原得到 0001 1110补 -> 0001 1110原
得到的结果为00011110,如果两个负数相加如果溢出,那么结果一定是正数,由此可知计算结果溢出.
##位运算
注意在计算机中数都是用补码的形式存储,计算都是用补码形式计算
1,经过强制类型转换以后,变量a,b的值分别为多少?
short a =128;
byte b =(byte) a;
解析:
1,int占4个字节,32位。byte占1个字节,8位。所以强转时会截断前24位
2,在内存中表示形式( 注意java中是以补码表示一个数,所以表示形式是补码,不是原码! ):
int a = 3 , 00000000 00000000 00000000 00000011补 (强转byte时前面24个0被截断)
byte b = 3 , 00000011补
int a = -3, 11111111 11111111 11111111 11111101补 (强转byte时前面24个1被截断)
byte b = -3 11111101补
首先 java中 是以补码表示一个数,short 占两个字节 ,128 换成二进制的形式 是 00000000 10000000,byte 占用一个字节,short 强转为byte前面八位 截掉,变成 10000000,这是补码,特殊的:即1个负数的补码是10000000,且是8位,则这个负数为-128
2,变量a是一个64位有符号的整数,初始值用16进制表示为:0Xf000000000000000;
变量b是一个64位有符号的整数,初始值用16进制表示为:0x7FFFFFFFFFFFFFFF。
则a-b的结果用10进制表示为多少?()
解析:
0Xf000000000000000补码为1111+60个0
0x7FFFFFFFFFFFFFFF补码为0111+60个1
a-b=a+(-b)= 注意:已知[+Y]补求[-Y]补的规则是全部位(含符号位)按位取反后再加1
(1111+60个0)+(1000+56个0+0001)=
10111000000000000000000000000000000000000000000000000000000000001(高位溢出舍去),则结果为
0111000000000000000000000000000000000000000000000000000000000001=
262+261+2^60+1
##数学运算相关函数
1,Math.floor() 表示向下取整,返回double类型 (floor—地板)
2,Math.ceil() 表示向上取整,返回double类型 (ceil—天花板)
double d1=-0.5;
System.out.println("Ceil d1="+Math.ceil(d1)); //-0.0
System.out.println("floor d1="+Math.floor(d1));//-1.0
double a = Math.floor(-9.0);
System.out.println(a); //-9.0,向下取整的话,如果自己是整数,取自己就可以
double a = Math.ceil(-9.0);
System.out.println(a); //-9.0,向上取整的话,如果自己是整数,取自己就可以
3,round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整**(可以看做先+0.5再做floor运算)**,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。返回int类型
如果参数是 NaN、无穷、正 0、负 0,那么结果的正负符号与参数相同,如果是 -0.0,那么其结果是 -0.0
4,Math.pow(i,3)表示i的三次方
5, Math.cos为计算弧度的余弦值,Math.toRadians函数将角度转换为弧度
Math.toDegrees()是将弧度转换为角度
#分支语句
##if
Boolean flag = false;
if (flag = true)
{
System.out.println(“true”);
}
else
{
System.out.println(“false”);
}
Boolean修饰的变量为包装类型,初始化值为false,进行赋值时会调用Boolean.valueOf(boolean b)方法自动拆箱为基本数据类型,因此赋值后flag值为true,输出文本true。 如果使用==比较,则输出文本false。if的语句比较,除boolean外的其他类型都不能使用赋值语句,否则会提示无法转成布尔值这一点和c大为不同。
例如:
public class IfTest{
public static void main(string[]args){
int x=3;
int y=1;
if(x=y)
System.out.println(“Not equal”);
else
System.out.println(“Equal”);
}
}
C语言中 当if语句中的条件为赋值语句时,实际上是将赋值后的结果与0进行比较【左值】if(1) 由于1>0 所以认为是true。 java语言中,Java中,赋值是有返回值的 ,赋什么值,就返回什么值。比如这题,x=y,返回y的值,所以括号里的值是1。虽然也用了左值,但是不再与0比较,而是直接将1放入if()中但是int类型,不能转换为boolean,所以会报错:“ Type mismatch: cannot convert from int to boolean”
##switch
###switch对于String的支持
在Java7之前,switch只能支持 byte、short、char、int或者其对应的封装类以及Enum类型作为条件。在Java7中,呼吁很久的String支持也终于被加上了。
public class StringForSwitch {
public void test_string_switch() {
String result="";
switch ("doctor") {
case "doctor":
result = "doctor";
break;
default:
break;
}
}
}
反编译后的,还原成大致的Java的代码如下:
public class StringForSwitch {
public StringForSwitch() {
}
public void test_string_switch() {
String result = "";
String var2 = "doctor";
switch("doctor".hashCode()) {
case -1326477025:
if(var2.equals("doctor")) {
result = "doctor";
}
default:
break;
}
}
}
可以看出,字符串类型在switch语句中利用hashcode的值与字符串内容的比较来实现的;但是在case字句中对应的语句块中仍然需要使用String的equals方法来进一步比较字符串的内容,这是因为哈希函数在映射的时候可能存在冲突。
###switch的基本原则
1,在switch语句中,表达式的值不能是null,否则会在运行时抛出NullPointerException。在case子句中也不能使用null,否则会出现编译错误。
2,case字句的值是不能重复的。对于字符串类型的也一样,但是字符串中可以包含Unicode转义字符。重复值的检查是在Java编译器对Java源代码进行相关的词法转换之后才进行的。也就是说,有些case字句的值虽然在源代码中看起来是不同的,但是经词法转换之后是一样的,就会在成编译错误。比如:**“男”和“\u7537”**就是一个意思。
#循环语句
##for循环语句
1,以下语句的输出结果是:
public class Print{
static boolean out(char c){
System.out.println(c);
return true;
}
public static void main(String[] argv){
int i = 0;
for(out('A');out('B') && (i<2);out('C')){
i++;
out('D');
}
}
}
ABDC BDCB
for循环的执行顺序用如下表达式:
for(expression1;expression2;expression3){
expression4;
}
执行的顺序应该是:
1)第一次循环,即初始化循环。
首先执行表达式expression1(一般为初始化语句);再执行expression2(一般为条件判断语句),判断expression1是否符合expression2的条件;如果符合,则执行expression4,否则,停止执行;最后执行expression3。
2)第N(N>=2)次循环
首先执行expression2,判断是否符合expression2要求;如果符合,则继续执行在expression4,否则,停止执行。最后执行在expression3。如此往复,直至expression3不满足在expression2条件是为止。
总结: 总的来说,执行的顺序是一致的。先条件判断(expression2),再函数体执行(expression4),最后for执行(expression3)。往复…区别在于,条件判断的对象。第一次判断时,对象为初始化语句(expression1),后续的判断对象为执行后的结果(expression3)。
2,如何跳出Array的forEach循环?
使用break.
#正则表达式
例题:java中用正则表达式截取字符串中第一个出现的英文左括号之前的字符串。比如:北京市(海淀区)(朝阳区)(西城区),截取结果为:北京市。正则表达式为(".*?(?=\()")
解析:
1.什么是正则表达式的贪婪与非贪婪匹配
如:String str=“abcaxc”;
Patter p="abc";
贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc(abc)。
非贪婪匹配:就是匹配到结果就好,就少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到:abc(ab*c)。
2.编程中如何区分两种模式
默认是贪婪模式;在量词后面直接加上一个问号?就是非贪婪模式。
量词:{m,n}:m到n个
:任意多个
+:一个到多个
?:0或一个
.表示除\n之外的任意字符
表示匹配0-无穷
+表示匹配1-无穷
(?=Expression) 顺序环视,(?=\()就是匹配正括号
".?(?=\()"中后面的(?=\()它是(?=assert)的形式,叫做顺序环视,也就是前面.?匹配到的字符后面必须要紧接着有assrt中声明的值,也就是左括号(其中\都是转义字符),但是匹配的到的串是不包含assrt中声明的内容的。
懒惰模式正则:
src=".*?
(?=\())
"
结果:北京市
因为匹配到第一个"就结束了一次匹配。不会继续向后匹配。因为他懒惰嘛。
#lamda表达式
下面哪些写法能在 java8 中编译执行()
A dir.listFiles((file f)->f.getName().endsWith(“.Java”));
B dir.listFiles((file f)=>f.getName().endsWith(“.Java”));
C dir.listFiles((_.getName().endsWith(“.Java”)));
D dir.listFiles( f->f.getName().endsWith(“.Java”));
答案为A, D
#json格式
JSON语法可以表示以下三种类型的值:
1.简单值:使用与JavaScript 相同的语法,可以在JSON中表示字符串,数值,布尔值和null。 {“company”:{“name”:4399}}
2.对象:对象作为一种复杂数据类型,表示的是一组有序的键值对。而每组键值对中的值可以是简单值,也可以是复杂数据类型的值。 {“company”:{“name”:[4399,4399,4399]}}
3.数组:数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型–简单值,对象或数组。{“company”:[4399,4399,4399]}