黑马程序员_毕向东_Java基础_DAY02学习笔记

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

/*

黑马程序员_毕向东_Java基础视频教程——

0201-标识符.avi
0202-常量.avi
0203-进制的特点.avi
0204-进制转换(十进制和二进制).avi
0205-进制转换(八进制和十六进制).avi
0206-进制转换(负数二进制).avi
0207-变量.avi
0208-类型转换.avi
0209-算术运算符.avi
0210-转义字符.avi
0211-赋值和比较运算符.avi
0212-逻辑运算符.avi
0213-位运算符(左移右移).avi
0214-位运算符(与-或-异或).avi
0215-位运算符(练习).avi
0216-位运算符(练习2&三元运算符).avi
0217-语句(if).avi
0218-语句(if练习).avi
0219-语句(Switch).avi
0220-语句(Switch练习).avi

DAY02的学习中的主要包括java基础中的标识符、常量与变量、基本数据类型与类型转换、进制转换、各种运算符、选择分支语句等
 */


一、标识符


【java命名规则】必须遵守

Java语言规定标识符可以由字母、数字、下划线_、美元符号$组成,不能使用java关键字,首字母不能是数字,并且大小写敏感。
需要注意的是,其中的字母不仅仅指26个英文字母及其大小写,同时还包括韩文、日文、罗马字母等其他国家语言符号甚至汉字。但java命名规范中不建议使用英文字母之外的其他字母来作为标识符,以防止出现一些可避免的诡异的问题。

关键字:被java语言赋予了特殊含义的单词。
main不是关键字,但是会被虚拟机特别对待。

【java命名规范】java程序员的共识、约定

三种标记方法:


骆驼标记法:aGoodDog

Pascal标记法:AGoodDog
匈牙利标记法:strAGoodDog

命名规范:
包名:全小写。
类与接口名:首字母大写,骆驼表示法(小写、使用_或$也可以执行)
变量与函数名:首字母小写,骆驼表示法
常量名:全大写,单词连接使用下划线

二、数据类型、常量、变量


【变量与数据类型】:

java是一种强类型语言:必须为每个变量声明一种类型。其中包括:

基本数据类型:8种

在java中一切都是对象,但是基本数据类型是特例。它们并非如同对象一样,使用new操作符创建并存储在堆中,而是直接创造一个存储值的非引用变量,存放在堆栈中,因此比存储在堆中更加高效。

4种整型:byte short int long   1字节(-128~127) 、2字节(-32168~32167)、4字节(正负21亿多)、8字节(正负922亿亿多)

2种浮点型:float double  4字节(6~7位有效数字、3.40E38F、不推荐使用、精度不够) 8字节(15位有效数字、1.79E308)

字符型: char   2字节,在java中,char类型用UTF-16编码描述一个代码单元,不推荐使用(现阶段unicode编码已超过65536,因此对于某些辅助字符需要2个代码单元表示)

char c = '\n';        // ok
char c1 = '你';  // ok

转义字符:
\n 换行
\t 制表
\b 退格
\r 回车

char型可强制转换为除boolean外的所有基本数据类型。事实上,只有向byte和short需要强制类型转换,其他都可以进行自动类型转换。
4种整型和char不可进行逻辑运算,其他运算皆可。
2种浮点型也不可进行逻辑运算,同时也不可进行位逻辑运算和移位运算。

布尔型:boolean  大小没有指明,只规定了可以取字面值true或false。
boolean型不允许进行强制类型转换,也不允许其他基本类型转为boolean型。
布尔型只接受相等性判断、逻辑运算、位逻辑(~除外)、赋值操作。
                 
在java中,boolean型中的true或false与整型的1或0没有对应关系,不能进行类型转换,这与C++中不同。也因此,在java中不会出现if(i=0)恒为false之类的错误。



java在赋值操作时,会检验是否会发生丢失精度的现象,并在编译时进行提醒。但是在运算过程中即使丢失精度,无论在编译时还是运行时都不会受到任何提示,如:

int i,j,k;

k = (i=10000000) * (j = 10000000);    //k = 276447232 ,丢失了精度。

JAVA中还有一种空类型: void


引用数据类型有三种:

接口
数组


【变量的初始化】:

方法中定义的局部变量必须初始化。而类中的类变量会被赋予默认值。


/* 这个程序说明了main方法不能直接调用本类的类变量,类变量的调用需要有对象存在。
 * 类变量可以不用初始化,但是局部变量必须初始化。
 * 类变量在对象创建时先初始化为默认值,整型->0, 浮点型->0.0 char型
 */

class Demo{
public static void main(String[] args){
System.out.println(new Demo().i);
}
int i;
}/* output:
0
*///:~


【常量】:

对于数值常量,日常生活中的表示形式并不足以向计算机说明究竟指代的是4种整型中的哪一种,可通过添加后缀字符来指明其具体数据类型,通过添加前缀的方式指明是几进制数。

对于十进制数:

1000   ----->  无后缀,默认为int型,但在赋值时如果符合取值范围,也可以赋值给较低数据类型,如1000可赋值给short,但不可以直接赋值给byte。
1000L  ----->  带L或l后缀,说明是long型,可大写也可小写,但一般用大写,防止小写l与数字1混淆。在明确指明类型之后,即使符合取值范围,也不可以直接赋值给较低数据类型,会出现编译错误:可能损失精度。
1.0    ----->  无后缀,默认为double型,也可以明确标记为1.0D,但不标记也可。无论是否标记都不可直接赋值给float变量
1.0f   ----->  标记为float型,同样可大写可小写。


对于十六进制数:

以0x或0X前缀来标识。十六进制数与十进制类似,如不标明即为int型,符合取值范围可赋值给更小的数据类型,超出范围时报错。标注为long型之后,即使符合范围也不可赋值给更小的数据类型。


对于八进制数:

在数字前面加0指明是八进制。但是由于容易混淆所以不推荐使用。


对于二进制数:

在C、C++、java中,对于二进制数都没有直接常量表示方法。但可以通过Integer或Long类的静态方法toBinaryString()来显示数据的二进制形式。对于较小的数据类型也可以使用Integer类的静态方法来显示二进制形式,该方法可以自动将较小类型转换为int。

Integer.toBinaryString(60);   将十进制的60转换为2进制的字符串形式。


JAVA的指数计数法:

1.3E-43代表1.3乘以10的-43次方,这是一个double型常量,如果要指定为float型,要加f后缀:1.3E-43f。

空常量:null

【数制转换】:

十进制转二进制: 整数部分除2取余下到上,小数部分乘2取整上到下。
二进制转十进制:按权值相加。
二进制转八、十六进制: 3、4个一组,进行转换。

负数的二进制,取反加1(补码),负数的二进制的第一位都是1.


三、数据类型转换


数据类型转换分为2种,一种是自动类型转换,在进行向上转型时发生,通常不会损失精度。另一种是强制类型转换,在进行窄化转型时发生,需要强制今夕,并且可能会损失精度。
在可以自动类型转换的情况下,也可以“画蛇添足”地进行强制类型转换,如long lng = (long)100;即使不使用强制转换,也是可以的,但是添加了强制转换,可以使代码变得更清晰。

自动类型转换

在以下情况下,都有可能发生自动类型转换:

1.赋值 : 将一个窄类型赋值给一个宽类型引用时。

2.参数传递: 将一个窄类型实参传递给一个宽类型形参时。

3.方法返回值: 将一个窄类型return给声明的宽返回值类型时。

4.数值运算: 不同类型运算取大的,有浮点取浮点,有int以下的类型一律提升为int。

对于最后一条需特别注意,如:
char + char = int
byte + byte = int


在表达式中如仅包含int常量的,那么结果值如符合范围,可以直接赋给byte。
而如果表达式中包含变量的,即使结果值符合范围,也不可将其赋给byte和short(需要byte,发现int),即:
byte b1 = 1, b2 = 2, b3;
b3 = b1 + b2;                  //error: 需要byte,找到int,可能损失精度。
b3 = 1 + 2;                      //ok.

强制类型转换(可能损失精度)

特别注意:
char与short之间,虽然都是2字节,但是需要使用强制转换
long向浮点型的转换,虽然long的精度比浮点型高,long的占用内存大小也比float高,但不需要使用强制转换。

浮点型向整型进行强制转换时,使用的是截尾方式,即直接舍去小数部分,而非四舍五入。如要四舍五入,可使用java.long.Math类中的round()方法。

实验:

int i = 3, j = 3;

byte b1 = 10;                             //ok
// byte b2 = 130;                       //error:找到int,需要byte,可能损失精度
// byte b3 = 100 * 100;             //error:找到int,需要byte,可能损失精度
byte b4 = 0x1A;                         //ok
byte b6 = 3 + 3;                        //ok
// byte b7 = i + j;                        //error:找到int,需要byte,可能损失精度
// byte b8 = (byte)i + (byte)j;    //error:找到int,需要byte,可能损失精度
// byte b9 = b1 + b1;                 //error:找到int,需要byte,可能损失精度

int a1 = 10000000; 
// int a2 = 10000000L;                         //error:找到long,需要int,可能损失精度
int a2 = 10000000;
// int a3 = 1000000000000;               //error:过大的整数
int a4 = a1 * a2;                                    //ok,但结果不正确
int a5 = 10000000 * 10000000;        //ok,但结果不正确
int a6 = 0x989680 * 0x989680;         //ok,但结果不正确
int a7 = b1; //ok
// int a8 = 100 + (long)100; //error:找到long,需要int,可能损失精度

// long l1 = 1000000000000;            //error:过大的整数
long l2 = 1000000000000L;            //ok
// long l3 = 0xE8D4A51000;             //error:过大的整数
long l4 = 0xE8D4A51000L;            //ok

// float f1 = 1.0;                                   //error:找到double,需要float,可能损失精度
float f2 = 1.0f;                                    //ok
float f3 = 1.0f + 1.0f
float f4 = f2 + f2;

byte b = 1;
short sh = 2;
int i = 3;
long lng = 4;
float f = 5.0f;
double d = 6.0;
char ch = 7;

// sh = 32768;                  //error:找到int,需要short,可能损失精度 --- short正最大为32767
// ch = -1;                          //error:找到int,需要char,可能损失精度----char不能取负值。
ch = 65535;                     //ok: 虽然同为2字节,但char的正整数范围是到65535。
// sh = ch; //error:找到char,需要short,可能损失精度 --- char正值范围大
// ch = sh;                        //error:找到short,需要char,可能损失精度 --- ch无负值。

lng = ch;                          //ok
f = ch;                              //ok
d = ch; //ok

f = i;                                //ok: int转float,自动转换,但是可能损失精度: 10位有效数字:6~7位
d = i;                              //ok:int转double,自动转换,不损失精度:10位:15位
f = lng;                           //ok: long转float,自动转换,但是可能损失精度:19位:6~7位
d = lng;                          //ok:long转double,自动转换,但是可能损失精度:19位 :15位

//:之所以19位的long可以自动转换为低精度的float和double,是因为float与double的数值表示范围都比long大得多。



四、操作符


一元操作符
算术操作符
赋值操作符
比较操作符
逻辑操作符
位操作符
三元操作符

【操作符的作用、特点】


操作符作用于操作数,操作数与操作符一起组成了表达式,表达式本身代表着一个新值。

操作数主要包括常量、变量、表达式。其中的常量、变量绝大多数是基本数据类型,仅仅有3个例外:= == !=。此外,还有Java中唯一被重载的操作符‘+’‘+=’,它们被用于字符串连接。

绝大多数的操作符不会改变操作数本身,只有++、-- 、各种赋值操作符可以改变操作数,这称之为“副作用”。带有“副作用”的操作符的主要用途就是利用其“副作用”。

操作符其实和方法很类似,接受1、2、3个参数(分别称之为一元操作符、二元操作符、三元操作符),然后通过一定的处理方式得出一个结果,只是提供参数的形式与方法有些不同而已。

【结合性与优先级】

表达式中可包含表达式,当一个表达式中含有多个操作符时,由操作符的结合性与优先级来决定各部分的计算顺序。

程序员很可能会遗忘各种操作符的优先级规则,所以即使你清楚的知道某些地方不需要额外添加括号,也应用括号明确的把计算顺序标示出来。这种“画蛇添足”更有利于提高程序的可读性与可维护性,也会避免自己把自己搞糊涂,避免一些乱七八糟的bug发生。

1. 结合性:

从右向左:

(1)所有一元操作符 (!~ ++ -- + -  强制类型转换 new)
(2)三元条件运算符?:
(3)所有赋值操作符(= += -= *= /= %= &= |= ^= <<= >>= >>>=,普通一个,算术5个,位逻辑3个,移位3个,共12个)

其他所有操作符均为从左向右。

总结:一元、三元、赋值操作符为右向左,其他全为左向右。很好记。

2. 优先级:

最高:          [] . 方法调用

一元运算符      !~(位非) ++ -- + -(正负)强制类型转换 new

算术运算符      *  /  %
                +  -

移位运算符      >>>  >>  <<

关系运算符      >  <  >=  <=  instanceof
                ==  !=

位逻辑运算符     &    
                ^
               |

逻辑运算符       &&
                ||

三元运算符       ?:

赋值运算符      =  +=  -=  *=  /=  %=  >>>=  >>=  <<=  &=  ^=  |=

总结记忆方法:共9分类。 中括号与方法调用最高,这个平时很少用到。其他8项中,一元最高、赋值最低,三元倒数第二低。再来从上到下是,先算术操作符(先乘除取余,后加减),接着是和算术运算相关的移位操作符,还差3个。一个是比较操作符,用于产生逻辑值。往下是位逻辑,再往下是逻辑。关系操作符中,比大小高于相等性比较,instanceof高于== !=。逻辑中与操作高于或操作,位逻辑中异或在与、或中间。


3. 括号

圆括号可强制改变表达式中运算符的优先级与结合性,优先执行所有带括号的表达式,括号可嵌套,嵌套时从内向外依次执行。


4. 表达式

表达式确定好结合性和优先级之后,从左向右将变量转换为字面值。

表达式本身相当于一个直接常量。因此表达式不能作为“副作用”的作用对象,即++ --操作符不可用于直接常量,因此也不可用于表达式。


【操作符详解】


【算术运算符】

* / %
+ -

5/2 == 2   //: int / int ,结果为int,直接截尾操作。
5/0 == error
5.0/0 == 无限大/NaN

-1%5 == -1    1%-5 == 1 , // 只看被模数。

乘除法的妙用:

double d = 3.1415926;
double d1 = (int)(d * 100) / 100.0; //d1 = 3.14, 保留了2位小数

疑问:浮点运算的误差问题

另:
+是java中仅有的两个被重载的操作符之一(另一个是+=),被用来进行字符串连接。
如果用+连接的表达式以一个字符串起头,那么虚拟机会自动将这个字符串后面的所有操作数转换为字符串型(通过toString方法)。

例:
//test: 测试字符串连接符的使用
int a = 1, b = 2, c = 3, d = 4;
System.out.println(a + b + "" + c + d);

//Output: 334,""前面的a + b执行的是普通的加操作,后面的c + d被转换为了字符串


【自增自减运算符】

前缀是先变再产生表达式的值,后缀是先产生表达式的值,再变。
在上面过程之后在计算最后总表达式的值。

先后顺序记住那个C++的笑话就OK了。

例:
int i = 3;
i = i++;  // output: 3

i++是一个自增表达式,i = i++整体是一个赋值表达式,后++先产生一个表达式的值,总表达式变为 i = 3然后再自增,自增后i = 4,之后再执行i = 3的赋值操作,i又变回了3。


// 说明变量的变化过程

class Demo{
public static void main(String[] args){
int a = 1, b = a++;
System.out.println(a + "\n" + b);          //注意不能是'\n'
}
}/* output: 
2
1
*///:~


实验:

//这个程序用于学习自增自减运算符的结合性、优先级,以及在赋值表达式中的值变化情况。

public class Test{
public static void main(String[] args){
int a = 0, b = 0, c = 1, j = 0, k = 0, m = 0;
j = j+++j;
k = (k++)+k;
m = m+(++m);
a += ++a;
b = b + b++;
//! c = (-c)--;
c = -c--;

System.out.println("a等于多少?"+a);
System.out.println("j等于多少?"+j);
System.out.println("k等于多少?"+k);
System.out.println("m等于多少?"+m);
System.out.println("b等于多少?"+b);
System.out.println("c等于多少?"+c);
}
}/* Output:
a等于多少?1
j等于多少?1
k等于多少?1
m等于多少?1
b等于多少?0
c等于多少?-1
*///:~

说明:

前++是先自增、再产生自增表达式的值、之后计算总表达式的值;
后++是先产生自增表达式的值、再自增、再计算总表达式的值;


自增、自减操作符只能作用于变量,不可作用于直接常量。如:
int i = 3++; //!error,3++不合法。


也不可作用于表达式,如:
int a = ++a++;  //! error,a++为表达式,表达式等同于一个直接常量,不可再进行自增运算。

int b = -b--;   //正确,右结合性,等同于 int b = -(b--);
int c = (-c)--; //! 错误,-c为表达式,不可再进行自增运算。

++ -- 可作用于除布尔型外的所有基本数据类型。

特别注意:
通常来说 i++;等于 i = i + 1;。但是对于char等小类型来说则不同。
char ch1 = 'a';
char ch2 = ++ch1;             //ok: ch2 == 'b',这里跟我的预想不一样,本以为++ch1会自动转成int型导致赋值失败的。
char ch3 = ch1 + 1;           //error: 需要char,找到int,可能损失精度

char ch4 = 65535;     //ok: 符合范围
for(int i = 0; i < 98; i++,ch4++); //65535又加了98次1,此时理论上应该是65633.
System.out.println(ch4);                 //output: a , 原因:超出了65536的范围,ch4 % 65536 = 97
System.out.println((int)ch4);           //output: 97

这种操作造成了本来符合范围的char变量值直接溢出了。

这种情况更类似于 ch += 1;

char ch4 = 'a';
ch4 = ch4 + 1;   //error
ch4 += 1;             //ok

++ --操作适用于除boolean之外的所有数据类型,但似乎如不小心都可能导致无任何编译运行提示的溢出。

【关系运算符】:

> < >= <= instanceof
== !=

关系操作符产生的是一个布尔值,它们计算的是操作数的值之间的关系。

== !=适用于所有基本数据类型,而> < >= <= 适用于除boolean之外的所有基本数据类型。

与此同时,== !=还适用于对象,但他们测试的是对象的引用而非对象的内容。两个对象引用指向同一个对象是才为true,否则不管对象的内容是否相同一律为false。
如果要比较两个对象的内容的相等性,需要使用equals方法,它可以比较对象的相等性。但equals方法是Object类中的方法,它的默认行为也是比较引用。所以即使对自定义的类使用equals方法,除非在类中覆盖重定义了正确的equals方法,否则依然会杯具。java类库中的大部分类都实现了equals方法。

需要注意的是,在对浮点数进行比较时,由于浮点数的不精确性,经常出现两个数因极小的差异导致相等性比较为false。

instanceof也是二元操作符,得到一个boolean值。它的左操作数通常是对象或对象的引用,右操作数为类,作用是判断左对象是否属于右类或右类的子类。


【逻辑运算符】:


&& 
||  

逻辑运算符只可应用于布尔值。 

注意:&&和||采用短路的方式进行运算。

布尔值在需要时可以自动转换为String字符串。


【位逻辑运算符】:

~
&
^
|  

位逻辑运算符除可应用于布尔型之外,还可应用于整型数据类型与char型。

在应用于布尔型时,与逻辑运算符的区别是并不按照短路的方式进行运算。

~ : 按位取反,不可应用于布尔型。

^异或:两边相同为假,两边相异为真。

异或的一个特性:一个数异或同一个数两次,结果还是那个数。(可用于加密,交换两个数)

int i = 3, j = 5;
i ^= j;
j ^= i;
i ^= j;  //完成交换两个数。

【移位运算符】:

<< 左移  8<<3 == 8 * 2的3次方
>> 右移补符号位  8>>3 == 8 / 2的3次方 
>>> 右移补零     

移位运算符可以应用于整型与char型。位操作是一种高效的运算方式。


在对byte、short、char进行移位运算时,在运算前会将它们转换为int型,得到的结果也为int。

对于byte、short、char、int,移位运算符的右操作数只有右侧低5位有效,即相当于对其进行模32操作,因为int只有32位。
对于long,移位运算符的右操作数只有右侧低6位有效,即相当于对其进行模64操作,因为long有64位。
在对byte、short、char进行移位运算时需要注意,因为会提升为int型,所以对负值进行>>>=操作时可能会产生错误结果。

byte b = -1;
b = b >>> 4;  //error: 需要byte,找到int
b >>>= 4;     //ok: 编译成功,但结果不正确,依然得-1。因为运算时将byte转为int,结果为int再截断为byte。

应用例子:
通过按位与运算、移位运算(>>>)获取一个二进制数的各个部分上的值(如将2进制数转换为16进制数)

【赋值运算符】:

 =  +=  -=  *=  /=  %=  >>>=  >>=  <<=  &=  ^=  |=

=是最基本的赋值操作符,它的作用是取右值,复制给左值。
右值可以是任何常量、变量或表达式,包括所有基本数据类型与对象。
左值必须是一个明确的、已命名的变量。即必须有一个物理空间可以存储用于存储右值。

int i = 0; //ok
0 = i; //error:左值永远不能为常数。

赋值语句是由一个赋值表达式和一个;组成的语句。

赋值表达式也是表达式,因此它本身也是代表一个直接常量,其值为赋值的结果。

int x;//声明变量
x = 100;//赋值语句,其中x = 100是一条赋值表达式
int x = 100;//赋值语句,声明变量并初始化。

if((a = 100)== 100);      //ok
if((a = 100;)== 100);     //error
if((int a = 100)== 100);  //error
if((int a = 100;)== 100); //error

给对象引用指定目标对象也是赋值表达式,其值为赋值的结果,即对象本身,如:


Date date;

String s = (date = new Date()).toString();
System.out.println(s);

new也是一元操作符,生成的也是表达式,值为创建的对象本身,如:
String s = new Date().toString();
System.out.println(s);

对于基本数据类型来说,赋值是直接存储的值。(存储在堆栈中而非堆中,这样也是为了提高效率)
如: 
int a = 4, b = 5;
a = b; //直接将b中的值赋值给a,a变量直接存储值而非引用,二者都变为5。
a = 6; //此时a变为6,但b依然为5。

在为对象赋值时,传递的其实是对象的引用而非对象本身。(老版本thinking in java将对象引用变量称为句柄)

例:
class Tank{int level;} //一个简陋的类,为了方便起见,无封装性

Tank t1 = new Tank{};
Tank t2 = new Tank{}; //创建了2个Tank对象,并令t1、t2分别指向它们
t1.level = 5;
t2.level = 0; //为2个类的成员变量赋值。
t2 = t1; //令t2指向t1所指变量,原来所指对象由于无句柄引用而将在下次垃圾清理是被垃圾回收器回收
t1.level = 1; //t1对象的类成员变量设为1,此时由于t2与t1指向同一个变量,t2.level也同时变为了1

这种问题称为“别名现象”。尤其是在方法参数传递时更需要注意这种现象所引发的问题。

+=  -=  *=  /=  %=  >>>=  >>=  <<=  &=  ^=  |=

二元运算符,将左操作数与有操作数进行运算后赋值给左操作数。只对二元操作符中的算术、移位、位逻辑有此简化操作

+=操作符也被重载用于字符串的链接。


一些示例:

short s = 4; //ok: 4虽然是int,但是符合范围,可直接赋值
s = 4 + 4; //ok:两个直接常量,且符合范围,可直接赋值
s = s + 5;       //error: 需要short,找到int
s += 5;           //ok: 一次运算没有中间过程。

int a, b, c;
a = b = c = 5;     //ok,右结合性

int i = j = k = 5; //error:找不到变量j、k

注意:
1、赋值运算符都为右结合性。
2、注意区分=、==。
3、+=等操作由于没有中间过程,可以运用于byte等比int小的类型的赋值操作。

【条件操作符】:

boolean-exp ? value1 : value0

条件操作符是一种三元操作符,它有三个操作数,尽管它看起来有些特殊,但它确实是一个操作符,生成的是一个条件表达式而非语句,条件表达式的值为后两个操作数中的一个,具体是哪个要看第一个操作数的逻辑判断结果。

条件操作符可以实现普通的if-else语句相同的效果,但三元操作符更加简洁。
需要注意的一点是,条件操作符的后两个操作数需要具有值,因此不能是语句只能是常量、变量或表达式。

例子:
int i = -1;
i = i < 0 ? System.out.println(-i); : System.out.println(i);;   //error: 选项值不可以是语句

int i = -1;
if(i < 0)
System.out.println(-i);
else
System.out.println(i);      //ok: 使用if-else可以实现此功能

int i = -1;
System.out.println(i = i < 0 ? i = -i : i);    //ok: 后两个操作数为值则可

---特别注意---

一个例子:
char ch = 'A';
ch = ch >=97 && ch <=122 ? ch - 32 : ch;
System.out.println(ch);
/* Output:
 * error,找到int,需要char,可能损失精度 
 * 'A'并不符合ch >=97 && ch <=122的条件,所以选择的应该是ch而非ch - 32,但是最终结果依旧转换为了int导致赋值失败。
 */

可以这样实现这个功能:
char ch = 'a';
System.out.println(ch >=97 && ch <=122 ? ch - 32 : ch); //Output: A

又一个例子:
int i = -1;
char ch1 = '+', ch2 = '-';
char ch3 = i>=0 ? ch1 : ch2;   //ok
// char ch3 = i>=0 ? 1 : ch2;    //ok
//! char ch3 = i>=0 ? ch1 + 1 : ch2;   //error
System.out.println(ch3);

总结:
  true ? char : 1   结果为char
true ?char : char 结果为char
true ? char : int 结果为int
true ? char  : char + 1 结果为int

char变量 + char变量 结果为int
char变量 + 1 结果为int
char变量 + int 结果为int
1 + 1 结果可赋值给char

又来了一个例子:
int i = 0;
int j = false ? ++i : ++i;
System.out.println("" + i + j); //Output: 11,说明未被选择的操作数被直接跳过根本不执行。

突然又想起了一个例子:

int i = 0;
true ? ++i : 0; //error: 不是语句,加上分号也白扯
System.out.println(i);

哪些操作符的处理结果可以直接加上分号当语句用呢?

除了空语句,貌似只有new、方法调用、赋值表达式,事实上,我也不知道new和方法调用的结果算不算表达式...


五、选择分支语句


【if语句】:

if语句的三种形式:

1)
if(boolean-exp)

statement;


2)
if(boolean-exp)
statement;
else
statement;

3)
if(boolean-exp)
statement;
else if(boolean-exp)
statement;
else if(boolean-exp)
statement;
else
statement;

boolean-exp部分可以是布尔常量、布尔变量或结果为布尔值的表达式。

statement可以是一条语句,也可以是一个含有多条语句的代码块。

else与上方距离最近的if配对,但下面这种情况不可配对:

if(boolean-exp)
statement;
statement;
else
statement;
在这里的else与if直接插入了一条普通语句,这样上面的if语句就结束了,会报错。


【关于块作用域、同名变量、声明顺序的问题】


块(block):用大括号括起来的若干语句,块确定了变量的作用域。块可以嵌套。
块作用域:同一个块中声明同名变量,也不能在嵌套的两个块中声明同名的变量。(后者在C++中允许)

{
int n;
...
    {
        int m,n;  //违法
    }
}

块语句(block statement):使用块语句可以在Java程序结构中原本只能放置一套简单语句的地方放置多条语句。
如 if (condition) statement --> 
if (condition) 
{
statement1
statement2
...
}

在同一个方法内部,同一片作用域中不能存在同名变量。
在不同的方法内部,可以存在同名变量,因为作用域不同。
在方法中如果出现与成员属性同名的变量,则方法内变量会屏蔽外部成员属性,如想引用外部成员属性可使用this.属性名。
同一个类中不能声明同名的成员属性,但在父类与子类中可以,子类中的属性会屏蔽父类属性,即可同时有2个属性,子类的属性属于子类,父类的属性属于父类。

在方法内部,语句严格按照从上到下的顺序执行,因此不可先使用后声明。
而在类内部方法外部,定义的顺序可随意排列。

对于用户提供的数据,可以先利用条件语句判断其是否符合要求,再进行常规流程对数据进行处理。

【switch语句】


switch(intgral-selector){
case integral-value1 : statement;break;
case integral-value2 : statement;break;
case integral-value3 : statement;break;
case integral-value4 : statement;break;
case integral-value5 : statement;break;
.
.
.
default : statement;break;
}

switch语句接受一个int型参数为选择条件,根据这个参数值选择对应的入口,找到入口后依次向下执行。如果没有找到匹配值,则选择default为入口,然后依次向下执行。
这个int型参数可以是结果为byte、short、int、char的表达式或直接常量、变量。(低类型可自动转换为int)
在jdk 5.0版本之后,添加枚举enum类型支持。
在jdk 7.0版本之后,添加字符串类型支持。

在依次向下执行的过程中,遇到break则推出结构体。如不写break,则继续向下执行。
最后一条语句可以不写break。
default语句不仅仅可以放在最后,也可以放在最前面或中间任意地方,不会影响入口的选择。
default语句不是必须的,可以不写,如果不写如果给定值全部不符合条件,则结束结构体,程序继续执行下面的语句。但建议添加default。

另外,要注意不要遗忘break。同时,如果出现多种值对应相同语句的情况下,可以把他们写在一起,并省略前面的break。


if与switch的选择问题:

if可判断boolean型、字符串等,而switch只能接受整型和字符型以及枚举类型。
if可判断区间值,而switch只能接受离散值。【重要】

switch适合确定的少量的离散选项值,效率稍高。if的使用范围更广。

switch 只接受整型中的byte、char、short、int,不接受long、float、double

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

你可能感兴趣的:(黑马自学课程)