Java基础语法
Java代码有一定规范,需要注意关键字和命名规范。
Java关键字
Java自己使用的,有特殊含义的字符,编码时不能使用关键字命名变量,方法和类,Java中有53个关键字,其中goto和const为保留字,现在都没有使用,其有如下特点:
(1)完全是小写字母
(2)在IDE或者notepad++中会显示颜色
标识符
标识符是在Java程序中自己定义的内容,如类的名字,方法的名字和变量的名字等,它有如下规范:
(1)类名规范:首字母大写,采用驼峰命名方式,如HelloWorld
(2)变量名规范:首字母小写,后面的每个首字母大写,如helloWorld
(3)方法名规范:同变量名规范
标识符不能使用关键字,不能以数字开头,可以包含英文字符,数字,$符号和下划线,一般尽量不使用$符号。
驼峰命名法
(1)类名/接口名:如果名字是多个单词组成,每个单词的首字母都需要大写,只有一个单词首字母也大写,如Demo,HelloWorld。
(2)变量名/方法名:如果名字是多个单词组成,第一个单词的首字母小写,其余的单词首字母大写,只有一个单词首字母小写,如demo,helloWorld。
(3)常量名,无论几个单词组成,所有字母大写,多个字母用下划线隔开,如HELLO_WORLD,DEMO。
(4)包名:所有字母小写,如果有多个单词,使用点隔开,如com.boe.exer。
注释
注释有如下几种,个人第一种和第二种比较熟悉了,第三种以前没注意可以提取形成文档。
(1)单行注释 //注释内容
(2)多行注释 /*注释内容*/
(3)文档注释 /**注释内容*/ 文档注释的内容可以提取出来形成文档,使用JDK的工具javadoc命令来执行。
发现使用命令javadoc -d ./ Demo.java后,会在当前文件夹下生成很多html文件,打开index.html,就会发现跟API文档很像。
index.html文档打开后,test方法的注释也会出现在文档里。
字面量
常量是程序运行期间固定不变的量,有如下几种:
(1)字符串常量,用双引号括起来,如"你好","Hello World"
(2)整数常量,就是数字,没有小数点,如100,200
(3)浮点数常量,包含小数点的数字,如1.23
(4)字符常量,用单引号括起来的字符,如'A','B',不能写2个字符以上,或者空的,如''和'AB'会导致编译错误。
(5)布尔常量,值有true和false
(6)空常量,为null,代表没有任何数据,不能用于打印输出,也不能在后面使用String的API
数据类型分类
包含基本数据类型和引用数据类型
基本数据类型,细分的话一共有8种:
(1)整数型,包含byte(1字节),short(2字节),int(4字节)和long(8字节),默认是int类型,如果要区分long型,需要在数字后面加L,如long a=123L,其中a就是long型
byte 字节型,范围-2^7~2^7-1,-128到127;
short 短整形,范围-2^15~2^15-1,-32768到32767;
int 整形,范围-2^31~2^31-1,java中整数默认是整形。
long 长整形,范围-2^63~2^63-1,主要表示长整型需要加L后缀。
从JDK1.7开始可以使用分位符号_的方式表示一个整形。
1 public class test1{ 2 public static void main(String[] args){ 3 //测试分位,在JDK1.7后才出现的表达方式 4 int i=1_234_567; 5 System.out.println(i); 6 } 7 }
(2)浮点型,包含float(4字节,可以精确到小数点后38位)和double(8字节,可以精确到小数点后308位),不论是单精度还是双精度都只是一个近似值,在程序中默认是double类型,如果要区分是float类型,需要在数字后面加上字符f,如float a=3.14f,这个a就是float类型了。
float 单精度类型 范围-10^38~10^38
double 双精度类型 范围-10^308~10^308
另外还有如下方法表示一个double类型,参考代码。
1 public class test1{ 2 public static void main(String[] args){ 3 //测试分位,在JDK1.7后才出现的表达方式 4 int i=1_234_567; 5 System.out.println(i); 6 //测试科学计数法 7 double d1=4e4;//4*10^4 8 System.out.println(d1); 9 //测试十六进制的科学计数法 10 double d2=0x4p4;//4*2^4 11 System.out.println(d2); 12 } 13 }
测试结果如下。
(3)字符型,包含char(2字节,可以表示中文字符),范围0~65535,默认为UTF-16编码体系。关于编码有如下几种常见的格式:
ISO-8859-1:西欧码表,一个字节一个字符,向下兼容ASCII,主要区别是ISO-8859-1使用了8位,而ASCII只使用了7位。无论是哪张码表都需要兼容西欧码表,即前面256个字符都是一样的。
gb2312:国标码,类似gbk,二个字节一个字符,收录了绝大部分的简体汉字和部分繁体字
unicode编码体系:常见的有utf-8和utf-16,其中utf-8是变长字节编码,可以参考自己的博客https://www.cnblogs.com/youngchaolin/p/10463887.html,utf-16用在char类型,常用2个字节表示一个字符。在英文的世界里utf-8是比较省空间的,而中文的话utf-16比较合适。
参考:https://www.jianshu.com/p/eb68e3298b0b
1 public class test1{ 2 public static void main(String[] args){ 3 //测试分位,在JDK1.7后才出现的表达方式 4 int i=1_234_567; 5 System.out.println(i); 6 //测试科学计数法 7 double d1=4e4;//4*10^4 8 System.out.println(d1); 9 //测试十六进制的科学计数法 10 double d2=0x4p4;//4*2^4 11 System.out.println(d2); 12 //测试char类型utf-16的书写方式 13 char c='\u9633'; 14 System.out.println(c); 15 } 16 }
如上面例子char类型使用utf-16表示,输出结果为'阳'。
转义字符:用键盘无法输出的字符,如制表符'\t'、回车'\r'、换行'\n'、反斜杠'\\'、单引号'\''、双引号'\"'。
(4)布尔型:boolean(一般1字节)
引用数据类型:
(1)字符串
(2)数组
(3)类
(4)接口
(5)Lambda
变量
程序在运行过程中内容可以改变的量,成为变量,它有两种赋值方式,第一种是先定义变量后赋值,第二种是定义变量的同时赋值。其使用过程中需要注意的事项:
(1)定义多个变量,名称不能重复
(2)float和long类型,最后建议使用F和L结尾
(3)使用byte类型或者short类型,变量右边的数据值范围不能超过左边的类型范围
(4)没有赋值的变量不能直接使用,需要赋值后才能使用
(5)变量使用不能超过作用域的范围,作用域就是一对大括号包裹的范围
(6)可以通过一个语句定义多个变量,但是不建议这么写
数据类型转换
当数据类型不一致时,会发生数据类型转换,有自动类型转换(隐式)和强制类型转换(显示)两种。
自动类型转换
只能从数据范围小的往数据范围大的转换。
1 package com.boe; 2 3 /** 4 * 数据类型转换,隐式类型转换,数据范围从小到大转换 5 */ 6 public class VariableChange { 7 8 public static void main(String[] args) { 9 //1 int类型到long类型转换,从小到大的转换原则 10 long num1 = 100; 11 System.out.println(num1); 12 //2 float类型转换为double类型,从小到大的转换原则 13 double num2 = 3.5F; 14 System.out.println(num2); 15 //3 long类型转换为float类型,其实float类型范围还是比long大,虽然float类型只有4个字节,long类型有8个字节 16 float num3 = 300L; 17 System.out.println(num3); 18 } 19 }
数据类型转换有如下几个规律,具体参考代码注释。最后一个需要注意,short类型和char类型无法通过最后一种方式进行相互转换,编译期就开始报错,但是使用字面量(固定的常量值)就可以编译运行通过。原因是因为short类型和char类型两者虽然都是2个字节,但是两者只是交集,因此使用字面量的情况下,可以在编译期就确定是否可以转换,但是如果使用最后一种方式,c2变成了一个变量,编译期无法确定它的范围,因此编译不通过。
1 public class TypeChange{ 2 3 public static void main(String[] args){ 4 //数据类型自动转换规律1:小类型可以自动转换为大类型,如byte→short→int→long→float→long 5 //整数类型转换浮点类型时,可能存在精度损失 6 byte b=10; 7 short s=b; 8 System.out.println(s); 9 10 short s1=32767; 11 int i=s1; 12 System.out.println(s1); 13 14 //int范围大概在21亿 15 int i1=2000000000; 16 long l=i1; 17 System.out.println(l); 18 19 //int超过范围,需用long类型并添加后缀L 20 //int i2=20000000000; 21 long l1=20000000000L; 22 System.out.println(l1); 23 24 //数据类型自动转换规律2 整数int可以自动转换为小数,可能存在进度损失 25 int i2=2000; 26 float f=i2; 27 System.out.println(f); 28 29 int i3=123456789; 30 float f1=i3; 31 System.out.println(f1);//存在精度损失 32 33 //数据类型自动转换规律3 char类型可以自动转换为int类型 34 char c='A'; 35 int i4=c; 36 System.out.println(i4); 37 38 //char类型能否和short类型相互自动转化? 39 char c1=97; 40 short s2='a'; 41 System.out.println(c1);//a 42 System.out.println(s2);//97 43 44 //以上可以自动转换,如下方式可以继续测试 45 //char c2='a'; 46 //short s3=c2; 47 //System.out.println(s3);//编译不通过 48 } 49 }
最后一段代码导致编译报错。
在注释掉最后一段代码后,执行结果如下。
强制类型转换
从数据范围大的往小的转换,需要考虑数据溢出,并添加强制转换后的数据类型 (强制转换数据类型)数据,才可以转。
1 package com.boe; 2 3 /** 4 * 数据类型转换,强制类型转换,可能会造成精度丢失,和数据溢出 5 */ 6 public class VariableChangeAdd { 7 8 public static void main(String[] args) { 9 //1 long转换为int类型 10 int num1 = (int) 1000L;//没有超出int类型数据的范围 11 System.out.println(num1); //1000 12 //2 long转换为int类型,long范围超出范围时 13 int num2 = (int) 100000000000000L; 14 System.out.println(num2); //276447232 15 //3 double类型转换为int类型 16 int num3 = (int) 3.9999; 17 System.out.println(num3); //3 18 //4 byte,short和char执行简单数学运算时,会先向上转换为int类型后才计算 19 char charter = 'A'; 20 System.out.println(charter + 1); //66 21 //5 byte和byte执行加法 22 byte num5 = 20; 23 byte num6 = 30; 24 byte num7 = (byte) (num5 + num6);//计算后,结果为int类型,然后int类型向下转型为byte类型 25 System.out.println(num7); 26 //6 数据溢出 27 byte num8 = 100; 28 byte num9 = 120; 29 byte num10 = (byte) (num8 + num9);//计算后数据为220,超出byte数据范围 30 System.out.println(num10); //-36,数据溢出 31 32 } 33 }
可以看出上面220转换为byte时,会发生精度损失,为什么会显示-36呢?可以先看220,其为int类型一共32位,因此表示为二进制就是00000000 00000000 00000000 11011100,当转换为byte类型时将高位24个0全部截取,剩下为11011100,然后byte类型高位1代表负数,使用互补对称公式计算-n=~n+1,-n=001000011+1,即-n=36因此n=-36。
注意事项:
(1)不推荐使用强制类型转换,可能会发生精度损失,数据溢出
(2)byte/short/char这三种类型都可以发生数学运算,例如加法'+',这三种类型在进行运算的时候,首先会被提升为int类型,然后再进行计算。
(3)boolean类型数据,不能做数据类型转换。
编码初识
美国人刚开始使用计算机采用ASCII(American Standard Code for Information Interchange)编码规范,使用8位即1个字节来表示一个字符或者字母,已经可以满足他们的需要。其中编码有一定的规律,主要记住以下几个:
(1)ASCII 48→ 数字 0
(2)ASCII 65→ 字符 'A'
(3)ASCII 97→ 字符 'a'
如果使用中文,ASCII不能满足需要,后面首先诞生了Unicode万国码,这样中文就可以用Unicode来表示了,底层依然是二进制数字,最后都可以转换为int类型的数字。
1 package com.boe; 2 3 /** 4 * 字符转化为数字,复习编码知识 5 */ 6 public class VariableChar2Number { 7 8 public static void main(String[] args) { 9 //char类型转换为数字 10 char charter='1'; 11 System.out.println(charter+0); //49 12 13 char charter1='b'; 14 System.out.println(charter1+0); //98 15 16 char charter2='C'; 17 System.out.println(charter2+0); //67 18 19 //自动类型转换,char类型转换为int类型 20 int num='C'; 21 System.out.println(num); //67 22 23 //中文字符 24 char charter3='阳'; 25 System.out.println(charter3+0); //38451 这是字符'阳'对应unicode编码所对应的十进制数字,ASCII里无法表示 26 } 27 }
运算符
(1)算数运算符
a byte/short/char类型在参与运算时自动提升为int类型
b 运算中如果有不同类型的数据,结果将按照数据类型大的返回,如int和double,最后运算结果为double
c 同一类型运算结果是同一类型
d 小数运算不保证精确性
e 注意除法运算分母为0的情况
1 public class Operation{ 2 public static void main(String[] args){ 3 //算术运算 4 short s1=1; 5 short s2=2; 6 int i=(int)(s1+s2);//自动向上转换为int 7 System.out.println(i); 8 9 //字面量可以,java为了提高运行效率,直接编译时计算得到8,然后赋值给short类型 10 short s3=3+5; 11 System.out.println(s3); 12 13 //同类型计算计算返回同类型 14 int i1=4500; 15 int i2=i1/1000*1000; 16 System.out.println(i2); 17 18 //小类型和大类型计算,结果一定是大类型 19 int i3=4500; 20 double i4=i3/1000.0*1000; 21 System.out.println(i4); 22 23 //小数运算不保证精确性 24 double d1=2.88888; 25 double d2=1.11111; 26 System.out.println(d1-d2); 27 28 //非零整数/0 29 //System.out.println(5/0); 30 //报异常 ArithmeticException: / by zero 31 32 //非零小数/0 33 //System.out.println(5.0/0); 34 //报异常 Infinity 35 36 //非0数字/0.0 37 //System.out.println(5/0.0); 38 //报异常 Infinity 如果是非0负数,则报-Infinity 39 40 41 //0/0.0 0.0/0 0.0/0.0 42 //System.out.println(0/0.0);//NaN 43 //System.out.println(0.0/0);//NaN 44 System.out.println(0.0/0.0);//NaN 45 46 } 47 }
运行结果如下。
另外还有取模运算,可以参考如下代码,计算结果的符号跟%左边的符号一样。
1 public class Module{ 2 public static void main(String[] args){ 3 //取模运算,类似数学中的取余数,计算机中计算结果会有不同 4 System.out.println(87%5);//2 5 System.out.println(-87%5);//-2 6 System.out.println(87%-5);//2 7 System.out.println(-87%-5);//-2 8 9 /* 10 取模运算的结果和%左边的数字符号有关,计算时先依据绝对值先计算得到结果,然后通过%左边数字符号得到结果符号 11 */ 12 13 //小数也可以进行取模运算 14 System.out.println(4.5%2);//0.5 15 System.out.println(4.5%2.5);//2.0 16 System.out.println(4.5%2.1);//0.3 17 System.out.println(5%2.1);//0.8 18 19 } 20 }
控制台输出结果,虽然有精度损失,但是结果是没问题的。
另外还有自增和自减运算,其使用时byte/short/char会自动进行类型转换为int进行计算,然后再强制转换为对应类型。
1 public class operatorDemo{ 2 3 public static void main(String[] args){ 4 //测试自增自减类型转换 5 byte b=20; 6 //b+=1;//这样写没问题 7 //b=b+1;//这样写编译不通过 8 b++;//这样写没问题 9 System.out.println(b); 10 } 11 12 }
使用javap -v -s -p 类名 命令可以查看内存中情况,如下先将20的数字push到byte变量中,然后执行储存加载常量化操作就前缀变成了i,代表int类型,最后执行自增后有一个i2b,代表int向下强制转换为byte,自增自减运算其底层执行了类型转换。
(2)赋值运算符
赋值运算符一般有=、+=、-=、*=、/=、%=等,除了=外,其他几个赋值运算符意思都是在这个变量本身的基础上进行计算,需注意赋值运算符的连等运算。
1 public class Operator{ 2 public static void main(String[] args){ 3 //测试赋值运算符 4 byte b=120; 5 b+=5; 6 System.out.println(b);//125 7 8 byte b1=120; 9 b1+=55; 10 System.out.println(b1);//-81 11 12 //int i,j=5;//编译错误,提示i未初始化,java中不支持连等定义 13 // System.out.println(i); 14 // System.out.println(j); 15 16 //赋值运算符的连等运算,编译从左往右,运算从右向左 17 int i=5; 18 i+=i-=5; 19 //i=5+(5-5) 20 System.out.println(i);//5 21 22 int j=5; 23 j+=j-=j/=5; 24 //j=5+(5-(5/5)) 25 System.out.println(j);//9 26 27 int k=5; 28 k-=k*=k++; 29 //k=5-(5*5),这里会先执行k=5*5后再k自增为6,但是最后又执行k=5-(5*5)最后又覆盖6 30 System.out.println(k);//-20 31 32 int a=5; 33 a=a++;//赋值运算比自增运算靠后,即先取出5准备好用于赋值,发现有自增先将a自增为6,然后再进行赋值运算a又变成5 34 System.out.println(a);//5 35 36 } 37 }
控制台结果。
(3)位运算符
参考博客:https://www.cnblogs.com/youngchaolin/p/11291809.html
(4)比较运算符
比较运算有==、!=、>、<、>=、<=。
(5)逻辑运算符,注意&&和||的短路逻辑运算符
a 与(and)或(or)非(not) --> &、|、!
b 异或(xor)、短路与、短路或 -->^、&&、||,其中异或本人比较少用已经忘记差不多了,可以参考同极相斥异极相吸来理解,true^true为false,false^false为false,true^false为true,false^true为true。另外如果同时存在短路与和短路或,有如下规则:
&&在||前面,不能将||短路掉: 意思是&&左边为false,还不能判断整个结果为false,继续往后执行看||右边的结果
||在&&前面,可以将&&短路掉: 意思是||左边为true,就能确定整个结果为true,就算右边有&&也无需判断结果
(6)三元运算符
三元运算符必须返回结果被使用,并且=号左右数据类型需一致。语法形式为 返回值类型 返回值=逻辑判断?表达式1:表达式2,逻辑判断为true取表达式1的值,否则取表达式2的值。
1 import java.util.Scanner; 2 public class OperatorTriple{ 3 public static void main(String[] args){ 4 //三目运算符 5 //判断一个数是奇数还是偶数 6 Scanner scan=new Scanner(System.in); 7 System.out.println("请输入一个整数"); 8 int i=scan.nextInt(); 9 //String result=i%2==1?"奇数":"偶数"; 10 //使用按位与运算 奇数&1=1,偶数&1=0 11 String result=(i&1)==1?"奇数":"偶数"; 12 System.out.println(result); 13 14 //根据分数等级判断学生成绩区间 15 System.out.println("请输入一个分数"); 16 int score=scan.nextInt(); 17 char rank=score>90?'A':(score>80?'B':(score>70?'C':(score>60?'D':'E'))); 18 System.out.println(rank); 19 } 20 }
控制台结果
整体参考如下代码
1 package com.boe; 2 3 /** 4 * 运算符:赋值,比较,逻辑,三元,前面的自增自减,四则运算和取模等略去 5 */ 6 public class OperationCharacter { 7 8 public static void main(String[] args) { 9 //赋值运算符: 10 //复合赋值运算符,常量不能用于赋值运算符,即常量不能写在运算符的左边 11 int a = 10; 12 a += 5; 13 System.out.println(a); //15 14 15 int b = 10; 16 b %= 3; 17 System.out.println(b); //1 18 //复合赋值运算会隐含强制类型转换 19 short c = 10; 20 c += 5;//执行时,会执行short+int,结果为int,然后再将int强制类型转换为short 21 System.out.println(c); 22 23 //比较运算符: 24 System.out.println(10 > 5); 25 System.out.println(10 < 5); 26 System.out.println(10 == 9); 27 System.out.println(10 != 9); 28 29 //逻辑运算符:与或非 30 //与&&和或||的短路逻辑,如果可以根据左边得到判断的结果,则右边的代码将不再执行,可以节省部分性能 31 int m = 10; 32 int n = 5; 33 int l = 1; 34 if (m > 20 && (++n) > 1) { 35 l++; 36 } 37 System.out.println(m + ":" + n + ":" + l);//10:5:1,说明m>20判断完后就不再执行后面的判断 38 if (m < 20 || (++n) > 1) { 39 l++; 40 } 41 System.out.println(m + ":" + n + ":" + l); //10:5:2,说明判断完m<20后就不再执行后面的判断 42 43 //三元运算符,需要三个数据才能操作的运算符 44 int x = 10; 45 int y = 5; 46 int z = x > y ? x : y; 47 System.out.println(z); //10 48 49 //必须同时保证等号左侧数据类型和右侧运算的数据类型一致 50 //int num=3>4?2.5:10; 编译不通过 51 52 //三元的运算结果必须被使用 53 //x>y?x:y; 编译不通过 54 55 56 } 57 }
运算符优先级
关于这一块,参考自己博客:https://www.cnblogs.com/youngchaolin/p/11294056.html
方法
方法定义里面不能嵌套定义方法。
1 package com.boe; 2 3 /** 4 * 方法,方法里不能再定义方法 5 */ 6 public class Method { 7 8 public static void main(String[] args) { 9 int myMoney = 10000; 10 int myHouseCount = 0; 11 //方法调用 12 marry(myMoney, myHouseCount); 13 14 } 15 16 //自定义一个方法,方法名使用小驼峰命名规则 17 public static void marry(int money, int housecount) { 18 if (money >= 1000000 || housecount >= 1) { 19 System.out.println("可以继续谈"); 20 } else { 21 System.out.println("分手吧!"); 22 } 23 } 24 25 }
Java9的Jshell
Java9中添加了Jshell的功能,可以在终端像python一样,一句一句的写代码并执行,这个是针对轻量级的代码使用的,不需要建类就可以运行得到结果,会比较方便。
1 package com.boe; 2 3 public class JShell { 4 /** 5 * Java 9中添加了Jshell的功能,类似于python的解释器,可以一句一句的执行代码,可以在终端写java代码直接运行 6 * 另外java中编译器有两点优化: 7 * (1)byte,char,short在赋值时,如果右侧值没有超过范围,会自动在值前面加(byte),(char),(short)进行强转, 8 * 如果右侧超过了左侧的范围,编译器直接报错 9 * (2)byte,char,short类型变量右侧赋值如果全是常量,那么会将常量的计算结果直接赋值给左侧变量,如果右侧有变量则编译不通过,因为 10 * byte,char和short三者进行运算都会自动向上转型为int。 11 */ 12 13 public static void main(String[] args) { 14 byte a=10; //自动在10前面加上了(byte)10 15 byte b=10; 16 17 //byte d=128; 128超过了byte范围,直接编译报错 18 19 char chacter=97; //97没有超过char的范围,会自动在前面加上(char)97,对应字母a 20 System.out.println(chacter); //a 21 22 //byte c=a+b; 编译不通过,a+b的结果为int,而数据类型为byte,因此报错。 23 //但是下面的情况却可以计算,这是一种优化 24 byte c=10+10; 25 System.out.println(c);// 20 如果右侧是常量,则结果不报错,如果右侧全是常量,则编译器会直接计算出值,并将右侧常量的值赋值给左侧变量 26 27 28 } 29 }
条件语句
条件语句中如果代码块只有一句,大括号可以省略不写。
1 package day03; 2 3 import java.util.Scanner; 4 5 public class IFElse { 6 7 public static void main(String[] args) { 8 /*if语句*/ 9 //step1:定义两个变量 10 int getOn=0;//上车人数=10人 11 int getOff=0;//下车人数=5人 12 //Step2:火车开过来了 13 System.out.println("火车开过来了:呼呼呼呼呼..."); 14 //Step3:只要遇到条件判断,就使用if结构 15 //如果(上车人数>0或者下车人数>0){ 则停车...} 16 if(getOn>0||getOff<0){ 17 System.out.println("火车停车→上下乘客→再开车"); 18 } 19 System.out.println("火车开走了"); 20 21 /*多分支:if-else*/ 22 //step1:定义两个变量 23 boolean hg=false;//有黄瓜 24 boolean hlb=false;//有胡萝卜 25 //step2:判断 26 //如果有黄瓜,就输出“黄瓜沙拉” 27 if(hg){ 28 System.out.println("黄瓜沙拉"); 29 } 30 //否者 31 else{ 32 //如果有胡萝卜,就输出“胡萝卜沙拉” 33 if(hlb){ 34 System.out.println("胡萝卜"); 35 } 36 //否者,就输出“不吃了“ 37 else{ 38 System.out.println("不吃了"); 39 } 40 } 41 42 /*多分支:else-if语句*/ 43 //step1:声明成绩变量int score=0; 44 int score=0; 45 //step2:获得用户输入的成绩 46 Scanner sc=new Scanner(System.in); 47 System.out.println("请输入成绩:"); 48 score=sc.nextInt(); 49 //step3:根据用户输入的成绩,输出对应等级:A,B,C,D 50 //第一个判断条件 51 //step3.1如果成绩小于0或者大于100,直接输出"成绩无效" 52 if(score<0||score>100){ 53 System.out.println("成绩无效"); 54 } 55 //step3.2 :否则,如果成绩>=90,输出A 56 /* 否则,如果成绩>=80,输出B 57 * 否则,如果成绩>=60,输出C 58 * 否则,所有条件都不满足,就输出D 59 */ 60 else if(score>=90){ 61 System.out.println("A"); 62 } 63 else if(score>=80){ 64 System.out.println("B"); 65 } 66 else if(score>=60){ 67 System.out.println("C"); 68 } 69 else{ 70 System.out.println("D"); 71 } 72 73 /*多分支:switch-case*/ 74 //switch语句可以根据一个整数表达式的不同值,选择不同的程序入口 75 //只能对整数和字符串进行判断 76 //step1:定:1个变量,保存变量 77 char L='B';//char类型,本质上是一个整数 78 switch(L){//L的整数值是65 79 case 'A'://如果等于'A' 80 //就输出"出众" 81 System.out.println("出众"); 82 break; 83 case 'B'://如果等于'B' 84 //就输出"优秀" 85 System.out.println("优秀"); 86 break; 87 case 'C'://如果等于'C' 88 //就输出"及格" 89 System.out.println("及格"); 90 break; 91 case 'D'://如果是'D' 92 //就输出"不及格" 93 System.out.println("不及格"); 94 break; 95 //使用break后才能真正实现分支 96 } 97 } 98 99 }
循环结构
while循环,do-while循环:
1 package day04; 2 3 import java.util.Scanner; 4 5 public class Loop { 6 7 public static void main(String[] args) { 8 /*while循环:第一次循环就需要判断条件时使用*/ 9 //step1:初始化循环变量 10 int round=0;//用一个变量记录转的圈数 11 double money=0;//用一个变量记录转的圈数 12 //step2:定义循环条件:必须交一块钱,圈数<3,就继续,否则就退出 13 while(money==1&&round<3){ 14 //step3:循环体 15 System.out.println("转一圈"); 16 //step4:循环变量都要朝着退出循环的趋势不断变化 17 round++; 18 if(round==2){ 19 System.out.println("停电了"); 20 break;//中断并退出循环 21 } 22 } 23 System.out.println("去玩别的了"); 24 /*break用于循环中退出当前循环*/ 25 26 /*猜数字*/ 27 //1.定义循环变量 28 int num=(int)(Math.random()*10+1);//保存程序随机生成的一个整数 29 //范围为1<=num<11;因此可以取到1到10,但是取不到11,因为范围小于11 30 /*如何获得一个随机的整数 31 * 使用Math.random(),返回0<=x<1; 32 * 方法返回任意min~max之间 33 * (int)(Math.random()*(max-min+1)+min) 34 */ 35 int guess=-1;//保存用户输入的整数 36 //只要获得用户输入的数据,就使用Scanner 37 Scanner sc=new Scanner(System.in); 38 //2.Process阶段 39 //用让用户反复玩游戏,不确定次数,就得使用while循环 40 //2.1循环变量:num保存随机数,guess保存用户输入 41 //2.2循环条件: 42 //退出的情况:guess==0或则用户猜对了guess==num 43 //相反,循环的条件为:guess!=0,并且guess!=num 44 while(guess!=0&&guess!=num){ 45 //2.3循环体 46 //先获得用户输入的整数 47 System.out.println("请输入一个整数:"); 48 guess=sc.nextInt(); 49 //然后比较guess和num,使用三目运算 50 /* 51 *如果guess==0,就返回"下次再来" 52 *如果guess>num,就返回"大了" 53 *如果guess<num,就返回"小了" 54 *否则 猜对了 55 */ 56 System.out.println( 57 guess==0?"下次再来": 58 guess>num?"大了": 59 guess<num?"小了": 60 "猜对了!!"); 61 } 62 63 /*do-while循环:不管条件是否成立,至少要执行一次循环时使用*/ 64 //step1:初始化循环变量 65 int round1=0;//用一个变量记录转的圈数 66 double money1=1;//用一个变量记录转的圈数 67 //step2:定义循环条件:必须交一块钱,圈数<3,就继续,否则就退出 68 do{ 69 //step3:循环体 70 System.out.println("转一圈"); 71 round1++; 72 }while(money1==1&&round1<3); 73 //如果第一次判断的结果为true,do-while和while没有差别 74 //用do-while循环实现猜数字游戏 75 int num1=(int)(Math.random()*10+1);//保存程序随机生成的一个整数 76 int guess1=-1;//保存用户输入的整数 77 do{ 78 //1.定义循环变量 79 Scanner sc1=new Scanner(System.in); 80 //先获得用户输入的整数 81 System.out.println("请输入一个整数:"); 82 guess1=sc1.nextInt(); 83 System.out.println( 84 guess1==0?"下次再来": 85 guess1>num1?"大了": 86 guess1<num1?"小了": 87 "猜对了!!"); 88 }while(guess1!=0&&guess1!=num1); 89 } 90 }
for循环:
1 package day04; 2 3 public class Loop1 { 4 5 public static void main(String[] args) { 6 /*for循环:只要变化的规律固定,优先使用for循环*/ 7 //计算从1加到100 8 //I.定义输入变量 9 int sum=0;//保存累加后的结果 10 int i; 11 int max=4000;//保存累加的上限,如果突破上限就退出循环 12 //P:每次得到一个整数,反复累加到变量上 13 //循环三要素 14 /*1.循环变量:整数i,i从1开始,每次累加1 15 * 2.循环条件:i<100; 16 * 3.循环体:sum+=i; 17 * 4.迭代循环变量:i++ 18 * */ 19 for(i=1,sum=0;i<=100;i++){ 20 sum+=i; 21 //如果累加结果sum已经超过max的上限,则退出循环 22 /*if(sum>=4000){ 23 break; //用break终止循环,简单粗暴 24 }**/ 25 } 26 System.out.println(sum); 27 //作用域:限定一个变量的可用范围,就是这个变量的作用域 28 //当进入一个变量的作用域时,创建变量,退出一个变量的作用域时,销毁变量 29 //for语句和其所属大括号属于同一作用域 30 31 /*循环变量中使用continue语句*/ 32 //跳过本轮循环,直接进入下一轮循环 33 //1.定义变量bao,保存包扔在哪个格子中 34 int bao=5; 35 //2.从1开始,循环跳每个格子,但是要跳过包所在的格子 36 for(int n=1;n<=10;n++){ 37 if(n==bao){ 38 continue;//跳过本轮循环,直接进入下一轮 39 } 40 System.out.println("跳到"+n); 41 42 } 43 44 } 45 46 }
另外if、switch-case、while和for循环详细内容可以参考博客:https://www.cnblogs.com/youngchaolin/p/11297402.html
方法重载
方法的重载,就是为业务功能类似,参数列表不一样的情况下使用的,具体参考下面代码。
1 package com.boe; 2 3 /** 4 * 如果方法的功能类似,只是参数列表不一样,这样没必要为不同的参数的列表写不同的方法名,会显得麻烦,这样方法的重载应用而生。 5 * 方法重载(overload),方法名称一样,只是方法参数列表不一样,这样就是方法的重载。 6 * 方法签名:方法名和方法参数。程序选择方法运行时,会根据参数的不同,选择不同的方法签名对应的方法来执行 7 * 方法重载与下面的因素有关: 8 * (1)参数个数 9 * (2)参数类型 10 * (3)参数的多类型顺序不一样 11 * 方法重载与下面的因素无关: 12 * (1)参数名 13 * (2)方法的返回值 14 */ 15 public class MethodOverload { 16 17 public static void main(String[] args) { 18 //测试方法重载 19 System.out.println(sum(1,2)); 20 System.out.println(sum(1,2,3)); 21 System.out.println(sum(1,2,3,4)); 22 23 } 24 //计算两个数的和 25 public static int sum(int a,int b){ 26 return a+b; 27 } 28 //计算三个数的和 29 public static int sum(int a,int b,int c){ 30 return a+b+c; 31 } 32 //计算四个数的和 33 public static int sum(int a,int b,int c,int d){ 34 return a+b+c+d; 35 } 36 //以上三个是方法的重载,下面的方法测试是否为方法重载,看编译是否通过 37 public static int sum(int a,double b){ 38 return (int)(a+b); 39 } 40 public static int sum(double a,int b){ 41 return (int)(a+b); 42 } 43 //跟参数名称无关 44 /*public static int sum(int c,int d){ 45 return (int)(c+d); 46 }*/ 47 //跟方法返回值无关 48 /*public static double sum(int a,double b){ 49 return a+b; 50 }*/ 51 52 }
数组
数组相关内容如下,还有几个关于数组的应用,如查找数组中最值,排序,二分查找等知识,参考博文:https://www.cnblogs.com/youngchaolin/p/11390935.html
(1)数组的初始化
1 package com.boe; 2 3 /** 4 * 数组是一种容器,可以存放多个同类型的数据 5 * 特点: 6 * (1)数组是一种引用数据类型 7 * (2)数组当中的多个数据,类型必须统一 8 * (3)数组的长度在程序运行期间不可以改变 9 * 10 * 两种常用的初始化方式: 11 * (1)动态初始化(指定数组的长度)数据类型[] 数组名称=new 数据类型[数组长度] 12 * (2)静态初始化(指定数组的内容) 13 * 常规写法:数据类型[] 数组名称=new 数据类型[]{元素1,元素2,...} 14 * 省略写法:数据类型[] 数组名称={元素1,元素2,...} 15 * 16 * 动态初始化和静态初始化可以拆分成两步初始化,第一步先定义一个数组,第二步就是给这个数组赋值,但是省略写法不能分两步来走 17 * 18 * 使用建议: 19 * (1)不确定数组元素的具体内容,用动态初始化,确定数组内容就用静态 20 */ 21 public class ArrayBase { 22 23 public static void main(String[] args) { 24 //动态初始化 25 //创建一个数组,里面存放300个数据 26 int[] array1 = new int[300]; 27 28 //静态初始化 29 int[] array2 = new int[]{1, 2, 3, 4}; 30 String[] array3=new String[]{"hello world","hello linux","hello python"}; 31 int[] array4={1,2,3,4}; 32 33 //测试两步写 34 int[] array5; 35 array5=new int[10]; 36 37 int[] array6; 38 array6=new int[]{1,2,3,4}; 39 40 //以下编译会报错,省略写法不能分两步来写。 41 /*int[] array7; 42 array7={1,2,3,4};*/ 43 44 45 } 46 47 }
(2)数组创建后的默认值,根据数据类型,有不同的初始值。
1 package com.boe; 2 3 /** 4 * 直接打印数组,得到的结果是数组对应的内存地址哈希值 5 * <p> 6 * 数组中的索引值,是从0开始,到(数组长度-1)为止 7 * <p> 8 * 使用动态初始化创建创组时,其中的元素会默认拥有一个初始值,有如下规则。 9 * 如果是基本数据类型: 10 * (1)4种整数类型,默认为0 11 * (2)2种浮点类型,默认为0.0 12 * (3)1种字符类型,默认为'\u0000' 13 * (4)布尔类型,默认为false 14 * 注意:其实静态初始化创建数组,数组元素也有默认值,只是随后马上被大括号中的值给覆盖了 15 */ 16 public class ArrayBaseOne { 17 18 public static void main(String[] args) { 19 //静态初始化 20 int[] array1 = new int[]{1, 2, 3}; 21 System.out.println(array1); //[I@61bbe9ba [代表数组,I代表整数类型,@后面的数组是十六进制数值 22 23 double[] array2 = new double[]{12.0, 13.0}; 24 System.out.println(array2); //[D@610455d6 25 26 //访问数组元素 27 System.out.println(array1[0]); //1 28 29 //动态初始化 30 int[] array3 = new int[4]; 31 System.out.println(array3[0]);//0 32 System.out.println(array3[1]);//0 33 System.out.println(array3[2]);//0 34 System.out.println(array3[3]);//0 35 //以上动态初始化后,得到的初始值默认是0 36 37 double[] array4 = new double[2]; 38 System.out.println(array4[0]);//0.0 39 40 boolean[] array5 = new boolean[2]; 41 System.out.println(array5[0]); //false 42 43 char[] array6 = new char[2]; 44 System.out.println(array6[0]);// 45 } 46 }
(3)数组的长度,数组的遍历,数组的比较,数组的反转等
1 package com.boe; 2 3 /** 4 * 获取数组的长度,数组名称.length,得到数组的长度 5 * 数组一旦创建,程序运行期间,长度不可以改变 6 * 数组的遍历 7 */ 8 public class ArrayBaseThree { 9 10 public static void main(String[] args) { 11 //获取数组的长度 12 int[] array = new int[]{1, 4, 56, 7, 6, 89, 5, 6, 3, 5, 6, 7}; 13 int length = array.length; 14 System.out.println("数组的长度为:" + length); 15 16 //数组长度在程序运行期间不可以改变 17 int[] array1 = new int[3]; 18 System.out.println(array1.length);//3 19 array1 = new int[5]; 20 System.out.println(array1.length);//5 21 /** 22 * 打印结果看好像数组的长度发生了改变,其实是数组的内存地址发生了改变,所指向的数组不一样, 23 * 但实现上,在堆内存中开辟的两个数组的长度是不变的,一个为3一个为5 24 */ 25 26 //数组遍历,使用for循环,IDE快捷生成方式array.fori 27 for (int i = 0; i < array.length; i++) { 28 System.out.println(array[i]); 29 } 30 31 //如何求出一个数组中的最大值 32 int max = array[0]; 33 for (int i = 0; i < array.length; i++) { 34 if (array[i] > max) { 35 max = array[i]; 36 } 37 } 38 //比较完后打印 39 System.out.println("数组的最大值为:" + max); 40 41 //数组元素的反转,就是将数组原封不动的颠倒过来 42 System.out.println("=======创建新数组======="); 43 int[] newArray = new int[array.length];//创建一个新数组 44 for (int i = 0; i < array.length; i++) { 45 newArray[newArray.length - 1 - i] = array[i];//利用下标之和为数组长度-1 46 } 47 //打印反转前后的数组 48 for (int i = 0; i < array.length; i++) { 49 System.out.print(array[i] + " "); 50 } 51 System.out.println();//换行 52 for (int i = 0; i < newArray.length; i++) { 53 System.out.print(newArray[i] + " "); 54 } 55 56 //同样数组反转,不创建新数组,只准使用原来数组的情况 57 System.out.println(); 58 System.out.println("=======不创建新数组======="); 59 //反转前打印 60 for (int i = 0; i < array.length; i++) { 61 System.out.print(array[i] + " "); 62 } 63 System.out.println(); 64 //反转 65 for (int i = 0; i < array.length; i++) { 66 //终止循环条件,考虑到了数组长度奇数偶数的情况 67 /*if (array.length % 2 == 0) { 68 if (i == array.length / 2) { 69 break; 70 } 71 } else { 72 if (i == (array.length - 1) / 2) { 73 break; 74 } 75 }*/ 76 //另外一种判断是,当左边索引小于右边就可以更换,否则终止 77 if (i >= array.length - 1 - i) { 78 break; 79 } 80 //调换array[i]和array[array.length-1-i]的元素 81 int buf; 82 buf = array[i]; 83 array[i] = array[array.length - 1 - i]; 84 array[array.length - 1 - i] = buf; 85 } 86 //反转完后打印 87 for (int i = 0; i < array.length; i++) { 88 System.out.print(array[i] + " "); 89 } 90 91 System.out.println(); 92 System.out.println("=======不创建数组,更加简洁的写法======="); 93 //反转前打印 94 for (int i = 0; i < array.length; i++) { 95 System.out.print(array[i] + " "); 96 } 97 System.out.println(); 98 //反转 99 for (int minIndex = 0, maxIndex = array.length - 1; minIndex < maxIndex; minIndex++, maxIndex--) { 100 int buf; 101 buf = array[minIndex]; 102 array[minIndex] = array[maxIndex]; 103 array[maxIndex] = buf; 104 } 105 //反转后打印 106 for (int i = 0; i < array.length; i++) { 107 System.out.print(array[i] + " "); 108 } 109 } 110 }
控制台输出数组反转结果:
(4)数组作为方法参数,传递的是内存地址值。
1 package com.boe; 2 3 /** 4 * 数组作为方法中的参数,传递的其实是数组的内存地址值 5 */ 6 public class ArrayBaseFour { 7 8 public static void main(String[] args) { 9 10 int[] arr = new int[]{30, 40, 1000}; 11 System.out.println(arr);//main方法中打印数组内存地址哈希值 12 printArray(arr); 13 14 } 15 16 //自定义方法,打印输出数组 17 public static void printArray(int[] array) { 18 System.out.println(array);//自定义方法中打印数组的内存地址哈希值 19 for (int i = 0; i < array.length; i++) { 20 System.out.println(array[i]); 21 } 22 } 23 24 /** 25 * 执行后发现,main方法中打印的内存地址和方法中打印的一样,说明数组作为参数,传递的其实不是值,而是内存地址值 26 */ 27 }
控制台输出结果,其中"["代表数组,"I"代表数据类型为Int,@跟邮箱类似,代表后面是地址,最后@后面的数值为数组内存地址哈希值。
(5)数组作为方法返回值,传递的也是数组的内存地址值。
1 package com.boe; 2 3 /** 4 * 数组作为方法返回值,返回的也是数组的内存地址值 5 */ 6 public class ArrayBaseFive { 7 8 public static void main(String[] args) { 9 int[] mainArray=getCalculate(1,2,4); 10 System.out.println("main方法中数组的内存地址哈希值:"+mainArray); 11 12 } 13 //自定义一个方法,返回一个数组 14 public static int[] getCalculate(int a,int b,int c){ 15 //计算和并返回 16 int sum=a+b+c; 17 //计算乘积并返回 18 int product=a*b*c; 19 //当需要返回两个值得时候,可以使用数组装载返回 20 int[] array=new int[2]; 21 System.out.println("方法中数组的内存地址哈希值:"+array); 22 array[0]=sum; 23 array[1]=product; 24 //返回 25 return array; 26 27 } 28 }
控制台输出结果:
(6)数组与内存
1 package com.boe; 2 3 public class Memory { 4 /** 5 * 内存的划分 6 * (1)栈(stack):存放的都是方法中的局部变量,局部变量常见的有方法中的参数,方法体{}中的变量,一旦超出作用域就会从栈内存中消失 7 * (2)堆(heap):凡是new出来的东西,如对象,就保存在堆中,堆内存中的东西都有一个地址值,为16进制,堆内存中的数据,都有默认值。 8 * (3)方法区(method area):存储编译后的.class文件,其中包含方法相关的信息,今后学习的反射就会调用方法区中的信息 9 * (4)本地方法栈(native method stack):与操作系统相关 10 * (5)寄存器(pc register):与CPU相关 11 */ 12 13 public static void main(String[] args) { 14 int[] array=new int[3]; 15 System.out.println(array); 16 System.out.println(array[0]); 17 System.out.println(array[1]); 18 19 //对数组中的元素重新进行赋值 20 array[0]=13; 21 array[1]=14; 22 //重新打印 23 System.out.println(array); 24 System.out.println(array[0]); 25 System.out.println(array[1]); 26 } 27 /** 28 * 执行完上述方法后发现,数组的内存地址没变化,只是数组内容发生了变化,执行这个方法的过程中内存中发生了什么呢? 29 * 1 首先需要在内存中开辟栈堆和方法区三块区域,为方法执行做准备 30 * 2 java代码编译后都是.class文件,其中包含代码方法的关键信息会存在方法区,如上面例子中public static void main(String[] args)这个头会保存在方法区 31 * 里面包含方法的关键信息,如方法名,参数类型,返回值类型等。 32 * 3 程序运行都是从main方法开始进入的,所以会从方法区寻找方法名为main的,找到后将关键信息main(String[] args)加载到栈内存中,并为其开辟一块区域执行方法,这个 33 * 过程就是进栈。 34 * 4 main方法执行后,发现需要创建一个int[]数组,int[] array为局部变量保存在栈内存中,右边new方法创建的是对象,保存到堆内存中,其根据数组大小开辟了一块内存区域, 35 * 这块内存区域有一个内存地址,这个内存地址,就保存在了array局部变量里。 36 * 5 想打印数组元素,会先通过数组的内存地址,找到堆中对应的对象,然后通过数组索引来找到对应的值 37 * 6 如果对数组中的值进行了改变,只是改变了堆中数组元素的值,但是不会改变数组对象的内存地址 38 * 7 因此最后再次打印时,内存地址还是原来的内存地址,但是对应的数组元素值却发生了变化。 39 */ 40 }