表达式和流程控制
1.实例变量和局部变量
程序的基本功能是处理数据,程序中需要使用变量来接收并表示数据。
程序中的变量必须先定义之后才能使用。
定义变量包括定义变量的"类型"以及变量的"名字"。
例如: int a; Student s;
程序中的变量分为实例变量和局部变量。
1)实例变量(又称属性、全局变量、成员变量)
位置:
直接定义在中类,属于类中的一种成员(成员变量/成员方法)。
例如:
public class Student{
public String name;
}
作用范围:
是指变量定义之后,都在哪些地方可以被访问到。
由于实例变量是直接定义在类中的,所以在定义的时候可以使用修饰符进行修饰。
例如:这四种修饰符的作用之后会介绍到
public class Student{
public String name1;
protected String name2;
String name3;
private String name4;
}
以上是使用了四种访问权限控制修饰符来修饰了这四个变量。
但是不管是哪种修饰符情况,实例变量再当前类中的每一个方法都是可以被访问到的(static修饰的静态方法除外)。
public class Student{
public String name1;
protected String name2;
String name3;
private String name4;
//类中的方法里面可以直接访问实例变量
public void run(){
System.out.println(name1);
System.out.println(name2);
System.out.println(name3);
System.out.println(name4);
}
}
默认值:
类的中实例变量声明后,如果我们没有显式赋值的话,每种实例变量其实都是有自己的默认值的。
实例变量的赋值分为隐式赋值和显式赋值
隐式赋值就是JVM给它赋的值(就是说的默认值)
显式赋值就是我们主动给它赋的值
例如:
public class Student{
public int a;
public float f;
public char c;
public boolean b;
public String str;
public void println(){
System.out.println(a);
System.out.println(f);
System.out.println(c);
System.out.println(b);
System.out.println(str);
}
}
基本类型的实例变量:
整型 :默认值为 0
浮点型 :默认值为 0.0
布尔型 :默认值为 false
字符型 :默认值为 0 或者 '\u0000'
引用类型的实例变量:
默认值都是 null
生命周期:
实例变量是属于对象的,一个对象被创建出来的时候,这个对象中的实例变量就有了,直到这个对象被GC当做垃圾回收之后,这个实例变量也就没有了。
1)局部变量
位置:
定义在方法的代码块中或者方法的参数列表中
例如:a b c d四个都是局部变量
public void test(int a){
int b;
{
int c;
}
if(true){
int d;
}
}
作用范围:
1)如果是定义在方法的参数列表中,那么在当前方法的任何位置都可以访问该局部变量
例如:
public void test(int a){
System.out.println(a);
{
System.out.println(a);
}
if(true){
System.out.println(a);
}
}
2)如果是定义在方法中,那么就要看这个局部变量是"直接"位于哪一对大口号内
例如:
public void test(){
int a;
{
int b;
}
if(true){
int c;
}
}
观察局部变量a/b/c三个分别是"直接"位于哪一对大括号内,那么这个局部变量的作用范围就在那一对大括号内.
如果访问的地方出了这个范围,那么是访问不到这个局部变量的。
默认值:
局部变量是"没有"默认值的,我们只能显式的赋值之后才能使用该变量,否则会编译报错.
例如:
//编译通过
//只定义了变量但是没有使用
public void test(){
int a;
}
//编译报错
//因为在使用局部变量之前没有赋值
public void test(){
int a;
System.out.println("a = "+a);
}
//编译通过
//只有在使用之前赋值就可以了
//int a = 1;
//当然声明的同时就赋值也是可以的
public void test(){
int a;
a = 1;
System.out.println("a = "+a);
}
声明周期:
当方法被调用,代码执行到局部变量的声明这一刻开始,这个局部变量就出现了,直到局部变量"直接"位于的大括号内中的代码执行结束的时候,该变量在内存中也就释放消失了。
例如:
//test方法执行完,变量a就没有了
public void test(){
int a;
}
//if代码块执行完,变量b就没有了
public void test(){
if(true){
int b;
}
//这里是访问不到变量b的,编译报错
System.out.println("b = "+b);
}
2.java中的操作符(operator)
1)赋值操作符:
= 例如: int x=0,i=1,j=1;
= 例如: a=b 等价于 a=a*b
/= 例如: a/=b 等价于 a=a/b;
%= 例如: a%=b 等价于 a=a%b;
+= 例如: a+=b 等价于 a=a+b;
-= 例如: a-=b 等价于 a=a-b;
其他的都是类似情况
a+=1; a++
特殊情况:i++ 和 ++i
i++表示先使用i的值,然后再让i自增1。
++i表示先让i的值自增1,然后再使用i的值。
例如:
int a = 1;
System.out.println(a++);//1
System.out.println(a);//2
---------------------------------
int b = 1;
System.out.println(++b);//2
System.out.println(b);//2
类似的i-- 和 --i也是一样的区别
2)比较操作符
> : 大于
>= : 大于等于
< : 小于
<= : 小于等于
注意:以上操作符只适用于整数类型和浮点数类型;
int a=1,b=1;
double d=1.0;
System.out.println(a>b);//false
System.out.println(a<b);//false
System.out.println(a>=d);//true
System.out.println(a<=b);//true
instanceof: 判断一个引用类型变量所指向的对象是不是属于某个类型。
Student s = new Student();
System.out.println(s instanceof Object);//true
System.out.println(s instanceof Student);//true
//编译报错,因为Student类型和String没有任何子父类关系
System.out.println(s instanceof String);
注意:最终判断的是s所指向对象的类型是不是属于某类型,而不是判断变量s的类型是不是属于某个类型.
例如:
Object o = new Student();
变量o的类型是Object,但是o指向的对象类是Studnet.可以这样写的原因是因为Object是Studnet的父类.这是java的高级特性"多态"的一种表现方式。
3)相等操作符
== : 判断俩个数据 是否 等于
!= : 判断俩个数据 是否 不等于
既可以应用在基本类型的比较,也可以应用在引用类型的比较
a.基本类型:
int a=1,b=1;
float c=1.0f;
double d=1.0;
//比较的是俩个基本类型数据的值是否相等
System.out.println(a==b); //输出true;
System.out.println(a==c); //输出true;
System.out.println(a==d); //输出true;
System.out.println(c==d); //输出true;
b.引用类型:
这两个引用变量必须都引用同一个对象,结果才为true.
Student s1 = new Student("zs",25,100);
Student s2 = new Student("zs",25,100);
//s1中存储的对象内存地址赋给变量s3
Student s3 = s1;
//比较俩个引用所指向对象的堆区内存地址是否一样
//俩个对象的内存地址一样相比较才会是true
System.out.println(s1 == s2); //输出false;
System.out.println(s1 == s3); //输出true;
4)相加操作符
+ : 数据类型值相加或字符串连接
a.数据类型值相加
int a=1+2; //a值为3;
double b=1+2; //b值为3.0;
double b=1+2.0; //c值为3.0;
b.字符串连接
System.out.println(1+2+"a"); //输出3a
System.out.println(1+2.0+"a");//输出3.0a
System.out.println(1+2.0+"a"+true);//输出3.0atrue
System.out.println("a"+1+2); //输出a12
System.out.println(1+"a"+2); //输出1a2
/ : 整除, 如操作数均为整数,运算结果为商的整数部分
int a1=12/5; //2
int a2=13/5; //2
int a3=-12/5; //-2
int a4=-13/5; //-2
int a5=1/5; //0
double a6=12/5; //2.0
double a7=12/5.0; //2.4
% : 取模操作符, 如操作数均为整数,运算结果为商的整数部分
int a1=1%5; //1
int a2=13%5; //3
double a3=1%5; //1.0
double a4=12%5.1; //1.8000000000000007
5)移位操作符
>> : 算术右移位运算,也称做带符号右移位运算。
注意:正数取反加1得到其对应的负数,负数取反加1得到其对应的正数
int a1 = 12 >> 1; //6;
0000 1100 12
-----------
0000 110 >>1
-----------
0000 0110 补位 因为是正数所以补0 结果为6
int a2 = 128 >> 2;//32;
int a3 = 129 >> 2;//32;
int a5 = -12 >> 1;//-6;
0000 1100 12
---------
1111 0011 取反
---------
1111 0100 +1 这个就是-12的二进制形式
----------
1111 010 >>1
1111 1010 补位 因为是负数所以补1 这个负数就是最终结果
---------
0000 0101 取反
---------
0000 0110 +1 结果为6 所以上面的最终结果是 -6
int a6 = -12 >> 2;//-3;
0000 1100 12
---------
1111 0011 取反
---------
1111 0100 +1 这个就是-12的二进制形式
----------
1111 01 >>2
1111 1101 补位 因为是负数所以补1 这个负数就是最终结果
---------
0000 0010 取反
---------
0000 0011 +1 结果为3 所以上面的最终结果是 -3
>>> : 逻辑右移位运算,也称为不带符号右移位运算。
int a1 = 12 >>> 1;//6;
int a2 = -12 >>> 2;//1073741821;
注:
a. 对12逻辑右移一位的过程为:舍弃二进制数的最后一位,在二进制数的开头增加一个0;
b. 对-12逻辑右移二位的过程为:舍弃二进制数的最后二位,在二进制数的开头增加二个0;
<< : 左移位运算,也称为不带符号左移位运算。
int a1 = 12 << 1;//24;
int a2 = -12 << 2;//-48;
int a3 = 128 << 2;//512;
int a4 = 129 << 2;//516;
注:
a. 对12左移一位的过程为:舍弃二进制数的开头一位,在二进制数的尾部增加一个0;
b. 对-12左移二位的过程为:舍弃二进制数的开头二位,在二进制数的尾部增加二个0;
6)位运算操作符
& 与运算
1&1->1, 1&0->0, 0&1->0, 0&0->0;
| 或运算
1|1->1, 1|0->1, 0|1->1, 0|0->0;
^ 异或运算
1^1->0, 0^0->0,1^0->1, 0^1->1;
相同为0 不同为1
运算特点: a^0=a; a^a=0;
~ 取反运算
~1->0, ~0->1;
7)逻辑操作符
短路操作符,如果能根据操作左边的布尔表达式就能推算出整个表达式的布尔值,将不执行操作符右边的布尔表达式;
短路与
&& 左边的布尔表达式的值为false, 整个表达式值肯定为false, 此时会忽略执行右边的布尔表达式。
false&&true
int a = 1;
int b = 2;
int c = 3;
a>b&&c>b
//没有短路功能
a>b&c>b
短路或
|| 左边的布尔表达式的值为true, 整个表达式值肯定为true, 此时会忽略执行右边的布尔表达式。
注意:&和&&的区别是什么? |和||的区别是什么?
8)三目运算
形式:
布尔表达式 ? 表达式1 : 表达式2;
如果上面布尔表达式的值为true, 就返回表达式1的值, 否则返回表达式2的值。
例如:
int score = 61;
String result = (score>=60?"及格":"不及格");
3.类型转换
1)基本类型之间的转换
隐式转换(自动转换)
byte a = 1;
//a是byte类型(8位),b是int类型的(32)
//编译通过,类型自动转换(隐式转换)
int b = a;
特点:小的可以自动转换(隐式转换)为大的,因为无非就是在前面多补几个0而已,不会影响数据值
显式转换
//编译报错,32位的值给8位的变量
int a = 100;
byte b = a;
//编译通过
//这时候需要类型强制转换(俗称强转,也就是显式转换)
int a = 100;
byte b = (byte)a;
特点:大的值给小的变量,需要强制转换,但是转换后的结果JVM不会保证还是正确的,因为这是程序员自己的个人行为.
2)引用类型之间的转换
隐式转换
//编译通过,类型自动转换(隐式转换)
Student s = new Student();
Object o = s;
特点:子类类型的变量可以自动转换(隐式转换)为父类类型
显式转换
//编译通过,运行后也不报错
//因为引用o本来指向的就是Student对象
Object o = new Student();
Student s = (Student)o;
//编译通过,运行后报错
//因为o本来指向的时候Teacher对象
//而Teacher类型对象和Student类型没有任何关系
Object o = new Teacher();
Student s = (Student)o;
4.流程控制-if
程序中if语句的代码块只有满足特定条件的情况下才会被执行.
1)if语句
if(true|false) {
//执行代码
}
2)if-else语句
if(true|false){
//执行代码1
}else{
//执行代码2
}
注意:if和else是一组的,二者有且只有一个会执行
3)if-elseif-else
if(true|false){
//执行代码1
}
else if(true|false){
//执行代码2
}
....
else{
//执行代码3
}
注意:以上三个代码块也是一组的,有且只有一个会执行
4)简写形式
不管是if还是elseif还是else,只要其后面执行的代码"只有一句",那么就可以把大括号去掉,执行效果也是一样的。
例如:
public void test(int x) {
if(x>10)
System.out.println("参数大于10");
else if(x>5)
System.out.println("参数大于5");
else if(x>0)
System.out.println("参数大于0");
else
System.out.println("参数小于等于0");
}
5)相关例子
写一个方法实现分时问侯, 如是8点至12点,返回"上午好", 12点至14点,返回"中午好",14点至18点,返回"下午好", 其它时间返回"晚上好"。
注:方法中使用return可以把数据返回给方法的调用者
public String sayHello(int hour) {
String msg;
if(hour >=8 && hour < 12)
msg = "上午好";
else if(hour>=12 && hour <14)
msg = "中午好";
else if(hour>=14 && hour <18)
msg = "下午好";
else
msg = "晚上好";
return msg;
}
写一个方法判断某一年是否为闰年
标准:能被4整除,但不能被100整除;或者能被400整除
//返回true表示是闰年,false表示不是闰年
public boolean isLeapYear(int year) {
if((year%4==0 && year%100!=0) || (year%400==0))
return true;
else
return false;
}
5.流程控制-switch
使用switch语句完成的功能,使用if语句同样也能完成。但是使用if语句完成的功能,使用switch语句却不一定能完成。不过在某些特定的情况下,switch还是有着自己的独特之处。
1)语法
注意:break关键字表示直接退出整个switch代码块
switch(变量) {
case value1:
//执行代码1;
break;
...
case valueN
//执行代码n;
break;
default:
//执行代码;
break;
}
注:switch只能接收byte, short, char或者int类型的变量,如果是JKD1.7那么也可以接收String类型的变量
例如:
int day = 4;
String result;
switch(day) {
case 0:
result = "星期天";
break;
case 1:
result = "星期一";
break;
case 2:
result = "星期二";
break;
case 3:
result = "星期三";
break;
case 4:
result = "星期四";
break;
case 5:
result = "星期五";
break;
case 6:
result = "星期六";
break;
default:
result = "参数有误";
break;
}
System.out.println(day+" : "+result);
2)特殊情况
如果switch的变量与某个case的值匹配,那么就从这个case中的代码开始执行。假如遇到break,就退出整个switch语句,否则依次执行switch语句中后续的case子句,而且不再检查case的值。
例如:写一个方法,返回指定月份有多少天
public int getLastDay(int year, int month) {
int day = 30;
switch(month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day=31;
break;
case 2:
day = getLeapYear(year)? 29:28;
}
return day;
}
注意:此处调用的getLeapYear方法就是上面if语句的例子所写的判断一个年份是否是闰年的方法.(在同一个类中,方法之间可以直接调用)
6.循环-for
语法:
for(<初始化>; <条件表达式>; <增量>) {
//要循环执行的代码
}
直到某一次增量执行后,条件表达式的值为false则循环结束
执行步骤:
1.初始化
2.条件表达式
2.1 false则退出循环
2.2 true则执行循环代码
2.3 执行增量变化
2.4 判断条件表达式
false则退出循环
true则执行循环代码
....
例如:
使用循环打印10次hello world
for(int i=0;i<10;i++){
System.out.println("hello world");
}
例如:
写一个方法,完成计算从1加到100的和
public int sum() {
int result = 0;
for(int i=1;i<=100;i++) {
//result = result + i;
result+=i;
}
return result;
}
例如:
写一个方法,完成计算从1加到n的和
public int sum(int n) {
int result = 0;
for(int i=1;i<=n;i++) {
result = result + i;
}
return result;
}
注意:for语句一般用在循环次数事先可确定的情况下
7.循环-while
while
语法:
while(循环条件) {
循环体
}
当循环条件为true时,就执行循环代码,否则终止循环;
例如:
用while循环完成计算从1加到n的和
public int sum(int n) {
int result = 0;
int i=1;
while(i<=n) {
result = result + i;
i++;
}
return result;
}
do-while
和while非常类似,只不过先执行循环体,然后再判断循环条件.
语法:
do{
循环体
} while(循环条件);
例如:
用do-while循环完成计算从1加到n的和
public int sum(int n) {
int result = 0;
int i = 1;
do {
result = result + i;
i++;
} while(i<=n)
return result;
}
注意:while和do-while循环用在循环次数事先不可确定的情况下
8.循环的嵌套
例如:打印出五行每行十个☆
//这个循环可以打出五个换行
for(int i=0;i<5;i++){
System.out.println();
}
//这个循环可以连着打印出10个☆
//但是不会换行
//注意print方法和println方法的区别
for(int j=0;j<10;j++){
System.out.print("☆");
}
那么把俩个循环嵌套在一起即可完成功能
for(int i=0;i<5;i++){
for(int j=0;j<10;j++){
System.out.print("☆");
}
System.out.println();
}
例如:
往控制台上输出以下内容:
*
**
***
****
*****
******
*******
public void print(int n){
for(int i=0;i<n;i++){
for(int j=0;j<i+1;j++){
System.out.print("*");
}
System.out.println();
}
}
9.break和continue
注:break和continue一般都是要结合循环使用的(for/while/do-while)
break
终止当前或指定循环
for(int i=0;i<10;i++){
if(i==3){
break;
}
System.out.println("i = "+i);
}
输出结果:
i = 0
i = 1
i = 2
continue
跳过本次循环,执行下一次循环
for(int i=0;i<10;i++){
if(i==3){
continue;
}
System.out.println("i = "+i);
}
输出结果:
i = 0
i = 1
i = 2
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
10.label标签
在循环嵌套的时候,使用label可以让break或者continue作用到指定的循环上,否则break或者continue只会默认作用到当前所处的循环上。
例如: 这个break跳出的是当前循环(也就是这里的内循环)
for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
if(j==3){
break;
}
System.out.println("j = "+j);
}
}
输出结果:
j = 0
j = 1
j = 2
j = 0
j = 1
j = 2
j = 0
j = 1
j = 2
例如:这个break跳出的是外循环(因为使用了label)
f1:for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
if(j==3){
break f1;
}
System.out.println("j = "+j);
}
}
输出结果:
j = 0
j = 1
j = 2