文章目录
这个学习过程,说实话很艰辛,工作之余抽时间,看视频,整理笔记,还得应付日常的开发工作,真的挺累的,导致更新的速度比较慢,幸好跌跌撞撞的把这些写完了。后续会继续补充面向对象的学习笔记。
变量与运算符
关键字和保留字
关键字的定义和特点
- 定义: 被java语言赋予了特殊含义
- 特点: 关键字中所有字母都为小写
标识符
标识符的使用:
- 标识符: 凡是自己可以起名字的地方都叫标识符比如:类名、变量名、方法名、接口名、包名
- 标识符的命名规则:26个英文字母0-9,_或$,数组不可以开头,不能使用关键字保留字,严格区分大小写,长度无限制,标识符不能带空格
- java中的命名规范:
- 包名: 多单词组成所有字母都用小写
- 类名接口名:多单词组成时,所有单词首字母大写 - 变量名、方法名: 多单词组成时,第一个单词首字母小写,第二个大写
- 常量名: 所有字母都大写
变量
变量的概念:
- 内存中的一个存储区域
- 该区域的数据可以再同一类型范围内不断变化
- 变量是程序中最基本的存储单元。包含变量类型、变量名和存储的值
变量的作用:
- 用于在内存中保存数据
使用变量注意:
- java中每个变量必须先声明,后使用
- 使用变量名来访问这块区域的数据
- 变量的作用域: 其定义所在的一对{}内
- 变量只有在其作用域内才有效
- 同一个作用域内,不能定义重名的变量
/*
变量的使用
1. java定义变量的格式: 数据类型 变量名 = 变量值;
2. 变量必须先声明后使用
3. 变量都定义在其作用域内。在作用域内他是有效的。换句话说,出了
作用域,就失效了
4. 同一个作用域内,不能重名定义
*/
class VariableTest {
public static void main(String[] args){
// 变量的定义
int myAage = 12;
// 变量的使用
System.out.println(myAge);
// 变量的声明
int myNumber;
// 变量的赋值
myNumber = 1001;
// 变量的使用
System.out.println(myAge);
}
}
数据类型
基本数据类型(primitive type):整数类型(byte,short,int,long)、浮点类型(float、double)、字符型(char)、布尔(boolean)
引用数据类型: 类(class)、接口(interface)、数组([])
需要注意的是: 字符串(String)是一个类他是一个引用类型
/*
Java定义的数据类型
个人补充一下字节的概念,比如我们有一段可以用来存储的空间,里面单独
拿出来一个格子我们默认这个格子只能存放0和1 1一个字节我们规定的是
8个bit其实代表的是就是这样8个格子,那如果我们这个格子只放0和1能有
多少种组合范围呢? 答案是2的8次方,也就是256,可是这样如果我们只用
来表示0-256负数怎么办,所以我们把其中一半 也就是2的7次方的数用来表
示负数,另外一半2的7次方用来表示正数,但是中间还有一个零,所以1字节
的表数范围就是-2^7~2^7-1
一、变量按照数据类型来分:
基本数据类型:
整型: byte(1字节)\short(2字节)\int(4字节)\long(8字节)
浮点型: float\double
字符型: char
布尔型: boolean
引用数据类型:
类(class)
接口(interface)
数组(array)
*/
class CariableTest1 {
public static void main(String[] args){
// byte(1字节=8bit)
// byte范围: -128~127
byte b1 = 12;
byte b2 = -128;
// b2 = 128; 编译不通过
System.out.println(b1);
System.out.println(b2);
// 声明long型变量,必须以'l'或者'L'结尾
short s1 = 128;
int i1 = 1234;
long l1 = 34134134L;
System.out.println(l1);
// float(4字节)\double(8字节)
// 定义float类型变量时,变量要以f或者F结尾
float f1 = 12.3F;
double d1 = 123.3;
System.out.println(d1+1);
System.out.println(f1);
// 字符类型: char(1字符=2字节)
// 定义char型变量,通常使用一对''
// 只能写一个字符
char c1 = 'a';
c1 = 'A';
System.out.println(c1);
// 布尔类型: boolean 只能取两个值之一: true false
// 常常在条件判断、循环结构中使用
boolean bb1 = true;
boolean isMarried = true;
if(isMarried){
System.out.println("你结婚了");
}else{
System.out.println("单身狗");
}
}
}
自动类型提升
注意类型转换的时候是讲8种基本数据类型中的布尔型给剔除掉了
/*
基本数据类型之间的运算规则:
前提: 这里套路的只是7中基本数据类型变量间的运算,不包含Boolean类型
*/
class VariableTest2{
public static void main(String[] args){
byte b1 =2;
int i2 = 12;
// 编译不通过。会报错,不兼容的类型,从int转换到byte可能会有损失
//byte b2 = b1 + i1;
long l1 = b1 + i1
int i2 = b1 + i1;
float f = b1 + i1;
System.out.println(l2);
System.out.println(i2);
System.out.println(f);
// ********************
char c1 = 'a'; //97
int i3 = 10;
int i4 = c1 + i3;
System.out.prinln(i4);
short s2 = 10;
//char c2 = c1 + s2;// 编译不通过 提示从int转换到char可能会有损失
// 其实到这里我们就可以猜测,char + short 得到的结果是int 而char c2 = 的这个动作就在做把int转换的动作
byte b2 = 10;
// char c3 = c1 + b2; // 同样的报错,从int转换到char可能会有损失
// 所以可以知道 char + byte的结果是int
//short s3 = b2 + s2; // 报错 从int转换到short可能会有损失
// 所以 byte + short 结果是int
}
}
以上代码得出结论:当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的类型 (我这里说的容量指的是表示数字的范围,不是说的字节数 注意嗷!),特别的,byte、char、short三种类型的变量做运算时,结果为int类型
byte、char、short —> short —> int —> long —> float —> double
特别的: java在做运算的时候如果操作数均在int范围内,那么一律在int的空间内运算
强制类型转换
可以说是自动类型转换的逆运算
/*
强制类型转换: 自动类型提升运算的逆运算。
1. 需要使用强转符: ()
2. 注意点: 强制类型转换,可能会导致精度损失
*/
class VariableTest3 {
public static void mian(String[] args){
double d1 = 12.3;
//int i1 = d1; 自然的会报错,从double转换到int可能会有损失
//所以我们会采用以下这种方式去强制转换类型
int i1 = (int)d1;
System.out.println(i1);// 得到结果12,注意计算d1是12.9那也是12
// 这个强转是一个截断的操作
// 没有精度损失
long l1 = 123;
short s2 = (short)l1;
int i2 = 123;
byte b = (byte)i2;
System.out.println(b);//结果是-128,这个要解释就得用到二进制去解说了
}
}
编码的一些特殊情况
class VariableTest4 {
public static void main (String[] args) {
// 1.编码情况:注意我下面这个long型变量没有以l或者L结尾,属于是把一个int提升为了long自动类型提升了
long l = 123213;
// long l1 = 222222222222222;可以看到这个数没有超过long的区间,但是会报错过大的整数,因为你没写l默认先是int
// 后做类型提升,显然这个数对于int来讲 太大了。
System.out.println(l)
// *******
float f1 = 12.3;
// 注意12.3如果不带这个f 它默认是double型
}
}
class VariableTest5 {
public static void main(String[] args){
byte b = 12;
byte b1 = b + 1;// 报错: int不能转换成byte
// 因为这里相当于是byte+int 由上文的自动类型提升可知结果
// 根据上面f1的案例 可知:
// 整型常量,默认类型为int型
// 浮点型常量,默认类型为double型
}
}
字符串类型: String
- String 不是基本数据类型,属于引用数据类型
- 使用方式与基本数据类型一致。例如: String str = “abc”;
- 一个字符串可以串接另外一个字符串,也可以直接串接其他类型数据。
- String 可以和八种数据类型做运算,且运算只能是连接运算:+ 运算的结果也是String
str = str + "xyz";
int n = 100;
str str + n;
- String 不是基本数据类型,属于引用数据类型
- 使用方式与基本数据类型一致。例如: String str = "abc";
- 一个字符串可以串接另外一个字符串,也可以直接串接其他类型数据。
- String 可以和八种数据类型做运算,且运算只能是连接运算:+ 运算的结果也是String
char c = 'a';//97 A:86
int num = 10;
String str = "hello";
System.out.println(c + num + str);//107hello
System.out.println(c + str + num);//ahello10
System.out.println(c + (num + str));//a10hello
System.out.println((c + num) + str);//107hello
System.out.println(str + num + c);// hello10a
System.out.println("* *");// * *
System.out.println('*' + '\t' + '*');//93
System.out.println('*' + "\t" + '*');//* *
System.out.println('*' + '\t' + "*");//51*
System.out.println('*' + ('\t' + "*"));//* *
进制与进制间的转换
-
所有数字在计算机底层都以二进制形式存在
-
对于整数, 有四种表示方式:
二进制:0,1 满2 进1以0b或0B开头
十进制: 0-9,满10进1
八进制: 0-7 满8进1以数字0开头
十六进制: 0-9及A-F,满16进1,以0x或者0X开头表示。此处A-F不区分大小写
如: 0x21AF + 1 = 0x21B0
class BinaryTest {
public static void main(String[] args){
int num1 = 0b110;
int num2 = 110;
int num3 = 0127;
int num4 = 0x110A;
// 输出会以10进制输出
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
System.out.println("num3 = " + num3);
System.out.println("num4 = " + num4);
}
}
-
java 整数常量默认是int类型,当用二进制定义整数时,其中第32位是符号位,
当是long 类型时,二进制默认占64位,第64是符号位
-
二进制的整数有如下三种形式:
- 原码: 直接将一个数值换成二进制,最高位是符号位
- 负数的反码: 对原码取反,最高位确定为1
- 负数的补码: 其反码加1
-
计算机以二进制补码的形式保存所有整数
- 正数的原码、反码、补码都相同
- 负数的补码是反码+1
toBinaryString(int i) ---> 2进制
toHexString(int i) ---> 16进制
toOctalString(int i) ---> 8进制
每日一考
-
标识符的命名规则有哪些
-
标识符的命名规范有哪些
包名: xxxyyyzzz
类名、接口名: XxxYyyZzz
变量名、方法名: xxxYyyZzz
常量名: XXX_YYY_ZZZ
-
java变量按照数据类型怎么划分?并指出java的数据类型有哪几种,并指出各自占用空间的大小
基本数据类型:
byte short int long
char
float double
boolean
引用数据类型: 类、接口、数组
-
说明基本数据类型变量之间自动类型提升的运算规则
byte、short、char —> int —> long —> float —> double
-
说明基本数据类型变量之间强制类型转换的使用规则和强制可能出现的问题
容量大-》容量小 (上面的东西反过来)
需要使用强制转换符
精度损失
运算符
class AriTest {
public static void main(String[] args){
// 除号: /
int num1 = 12;
int num2 = 5;
int result1 = num1 / num2;
System.out.println(result1);//2
int result2 = num1 / num2 * num2;
System.out.println(result2);// 10
double result3 = num1 / num2;
System.out.println(result3);// 2.0
double result4 = num1 / (num2 + 0.0);
System.out.println(result5);
// 取余运算
int m4 = 12;
int n4 = 5;
System.out.println("m4 % n4 = " + m4%n4);
// (前) + +
// (后) + +
int a1 = 10;
int b1 = ++a1;
System.out.println("a1 = " + a1 + "b1 = " + b1);//a1 = 11,b1=11
int a2 = 10;
int b2 = a2++;
System.out.println("a2 = " + a2 + "b2 = " + b2);//a2 = 11,b2 = 10
// 注意点:
short s1 = 10;
//s1 = s1 + 1;// 编译失败
s1 = (short)(s1 + 1);//正确
s1++;//自增1不会改变本身变量的数据类型
System.out.println(s1);
//问题:
byte bb1 = 127;
bb1++;
System.out.println("bb1 = " + bb1);//-128
}
}
ps: 说点真心话,自增自减这一块的东西我自己是在js和c中都有接触过的,所以没有花太多时间在这个上面,如果是真的有人看我这个笔记学习的,请多花一点时间在这个运算符的练习题上。
/*
练习: 随意给出一个整数,打印显示个十百位数的值
*/
class AriExer{
public static void main(String[] args) {
int num = 187;
int bai = num / 100;
int shi = num % 100 / 10;
int ge = num % 10;
System.out.println("个位数:" + ge);
System.out.println("十位数:" + shi);
System.out.println("百位数:" + bai );
}
}
赋值运算符
- 符号: =
- 当 “=”两侧数据类型不一致时,可以使用自动类型转换或者强制类型转换进行处理
- 支持连续赋值
- 扩展赋值运算符: +=,-=*=./=.%=
class SetVauleTest {
public static void main(String[] args) {
// 赋值符号: =
int i1 = 10;
int j1 = 10;
int i2,j2;
// 连续赋值
i2 = j2 = 10;
int i3 = 10,j3 = 20;
//*************
int num1 = 10;
num1 += 2;// num1 = num1 +2
System.out.println(num1);// 12
// 同样的 以上的扩展赋值运算符都是表示这个用法
// 特殊的
short s1 = 10;
// s1 = s1 + 2;这个肯定编译失败,short型加int变成了整型,整型变量不做强转直接赋值给short
s1 += 2;// 但是这个是可行的,还记得上文提到的 ++的用法吗,同理。不会改变数据本身的数据类型
System.out.println(s1);
}
}
练习题:
int i = 1;
i *= 0.1
System.out.println(i);//0
i++
System.out.println(i);//1
int m = 2;
int n = 3;
n *= m++;
System.out.println("m=" + m);//3
System.out.println("n=" + n);//6
int n = 10;
n += (n++) + (++n);// n = n + (n++) + (++n) / n = 10 + 10 + 12
System.out.println(n);//32
比较运算符
相等于(==) 不等于(!=) 小于(<) 大于(>) 小于等于(<=)大于等于(>=) instanceof检查是否是类对象
比较运算符结果都是boolean,也就是要么是true,要么是false 注意比较运算符的“==”别误写成赋值运算符的“=”
class CompareTest {
public static void main(String[] args) {
int i = 10;
int j = 20;
System.out.println( i == j);//false
System.out.println( i = j);//20
// 其他的我就不写了。
}
}
逻辑运算符
& — 逻辑与 | — 逻辑或 ! — 逻辑非 &&—短路与 || — 短路或 ^—逻辑异或
class LogicTest {
public static void mian(String[] args) {
//区分 & 与 &&
// 相同点1: & 与 &&的运算结果相同
// 相同点2: 当符号左边是true,二者都会执行符号右边的运算
// 不同点: 当符号左边是false, & 会继续执行符号右边,&& 不在执行符号右边
boolean b1 = true;
int num1 = 10;
if(b1 & (num1++ > 0)) {
System.out.println("我在上海");
} else {
System.out.println("我在北京");
}
boolean b2 = true;
int num2 = 10;
if (b2 && (num2 > 0)){
System.out.println("我在北京");
} else {
System.out.prinln("我在上海");
}
// | 与 || 同理
}
}
位运算符
<< 左移 3< < 2 = 12 = ⇒ 3 * 2 * 2 = 12
> > 右移 3>>1 = 1 =⇒ 3/2 = 1
> > > 无符号右移 3 >>> 1 =⇒ 3/2 = 1
& 与 6&3 = 2
| 或运算 6|3 = 7
^ 异或运算 6^ 3 = 5
~ 取反 ~6 = -7
位运算是直接对整数的二进制的运算
三元运算符
- 格式:
- 条件表达式 ? 表达式1 : 表达式2
- 表达式1与表达式2为同类型
- 三元可以简化if- else语句
- 三元运算符必须返回一个结果
这个没啥好讲的
每日一考
- “&&” 和 “&”的异同:
相同点1: & 与 &&的运算结果相同
相同点2: 当符号左边是true,二者都会执行符号右边的运算
不同点: 当符号左边是false, & 会继续执行符号右边,&& 不在执行符号右边
- 程序输出
class OperatorTest {
public static void main(String[] args) {
boolean x = true;
boolean y = false;
short z = 40;
// z == 40 ==>true==> z = 40 + 1
// y = true
// 执行循环
if((z++ == 40) && (y = true)) {
// z = 41 + 1
z++;
}
// x = false
// z = 42 + 1
// z = 43
if((x = false) || (++z == 43)) {
// z = 43 + 1
z++;
}
System.out.println("z = " + z);
// z = 44
}
}
结果为:
- 定义3个int型变量并且赋值,使用三元运算符或者if-else获取这三个数中较大数的实现:
int num1 = 10,num2 = 21,num3 = -21;
int max;
if (num1 >= num2 && num1 >= num3){
max = num1;
}else if(num2 >= num1 && num2 >= num3){
max = num2;
}else{
max = num3;
}
- 编写程序,声明2个double型变量并且赋值。判断第一个数大于10.0,且第二个数小于20.0,打印两数之和。否则,打印两数的乘积
double d1 = 12.3;
double d2 = 32.1;
if (d1 > 10.0 && d2 < 20.0){
System.out.println(d1 + d2);
}else{
System.out.println(d1 * d2);
}
- 交换两个变量值的代码实现
String s1 = "北京";
String s2 = "南京";
String temp = s1;
s1 = s2;
s2 = temp;
程序流程控制
分支语句1(if-else):
if-else的三种格式:
/*
// 1
if(条件表达式){
执行代码块;
}
// 2
if(条件表达式){
执行代码块1;
}
else{
执行代码块2;
}
// 3
if(条件表达式1){
执行代码块1;
}
else if(条件表达式2){
执行代码块2;
}
...
else{
执行代码块n;
}
*/
class IfTest {
public static void main(String[] args) {
//举例1
int heartBeats = 79;
if (heartBeats < 60 || heartBeats > 100){
System.out.println("你指定有点什么毛病");
}
System.out.println("检查结束");
// 举例2
int age = 23;
if(age < 18){
System.out.println("你只能看动画片");
} else {
System.out.println("你可以看看成人电影了");
}
// 举例3
if(age < 0){
System.out.println("非法输入");
}else if(age < 18){
System.out.println("青少年时期");
}else if(age < 35){
System.out.println("青壮年时期");
}else if(age < 60){
System.out.println("中年时期");
}else if(age < 120){
System.out.println("老年时期");
}else{
System.out.println("老仙儿~")
}
}
}
if 语句例题
张黎婕参加python考试,和他父亲张熊达成承诺:
如果:
成绩为100分,奖励一辆BMW;
成绩为(80-90],奖励一台iphone xs max;
当成绩为[60-80]时,奖励一个ipad
其他时,什么奖励都无,
请从键盘输入张黎婕的期末成绩,并加以判断
下面有个问题,如何从键盘获取不同类型的变量
/*
需要使用Scanner
具体实现步骤
1. 导包: import java.util.Scanner;
2.Scaner的实例化(先会用,后面面向对象的时候再细说)
3.调用Scanner类的相关方法,来获取指定类型的变量
String --- next()
其他的 基本都是nextxxx()
*/
import java.util.Scanner;
class ScannerTest{
public static void mian(String[] args){
Scanner scan = new Scanner(System.in);
int num = scan.nextInt();
System.out.println(num);
System.out.println("请输入你的名字:");
String name = scan.next();
System.out.println(name);
System.out.println("请输入你的年龄:");
int age = scan.nextInt();
System.out.println(age);
System.out.println("请输入你的体重");
double weight = scan.nextDouble();
System.out.println(weight);
System.out.println("你是男的还是女的?(true(男)/false(女))")
boolen isLove = scan.nextBoolean();
// 对于char类型的获取,Scanner没有提供相关的方法,只能获取一个字符串
// 但是String提供了charAt()的方法供String提取成字符
// String s = "张熊"; char c = s.charAt(0); System.out.println(c)==> 张
}
}
需要注意的时Scanner在调用相应方法来获取屏幕上的值的时候,需要输入的类型与你调用的方法类型一致。如果输入数据类型与要求类型不匹配时,会报异常: InputMisMatchException导致程序终止。
回到张黎婕的题目:
import java.util.Scanner;
class IfTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入张黎婕期末成绩: (0-100)");
int score = scan.nextInt();
if (score == 100){
System.out.println("奖励一辆BMW");
}else if(score > 80 && score <=99){
System.out.println("奖励一台iphone xs max");
}else if(score >= 60 && score <= 80){
System.out.println("奖励一个ipad");
}else{
System.out.println("什么奖励也没有");
}
}
}
留几个题目,自己去写吧:
- 编写程序: 由键盘输入三个整数分别存入变量num1、num2、num3,对他们进行排序(使用if-else if-else),并且从小到大输出。
- 输出题:
class IfExer {
public static void main(String[] args) {
int x = 4;
int y = 1;
if (x > 2)
if (y > 2)
System.out.println(x + y);
else
System.out.println("x is" + x);
}
}
考虑一下else的就近原则
- 输出题:
boolean b = true;
// 如果写成if(b=false)能编译通过吗? 如果能,结果是?
if (b == false)
System.out.println("a");
else if(b)
System.out.println("b");
else if(!b)
System.out.println("c");
else
System.out.println("d");
-
编写程序,声明2个int变量赋值。判断两数和,如果大于50,打印helloworld
-
如果狗前两年每年相当于人类的10.5岁,之后没增加一年就等同于增加4岁,那么现在5岁的狗相当于人类多少年龄呢?(编写程序,屏幕输入狗子年纪,负数提示报错)
-
彩票游戏,程序随机产生一个两位数的彩票,提示用户输入一个两位数,按如下规则去判定用户是否赢钱
-
用户输入数字对,顺序对,奖励10 000
-
数字对,顺序不对,奖励3 000
-
数字对一个,且顺序对位,奖励1 000
-
数字对一个,顺序不对, 奖励500
-
数字都不对,彩票作废
提示: 使用(int)(Math.random()*90 + 10) 产生随机数
/*
获取随机数
*/
double value = Math.random() * 100; //获取的是[0.0,1.0)区间内的数字
分支语句2(switch-case结构)
switch语句的基本使用格式:
switch(表达式){
case 常量1:
语句1;
//break;
case 常量2:
语句2;
//break;
... ...
case 常量N:
语句Nl;
//break;
default:
语句;
//break;
}
大概的执行顺序是,如果根据表达式匹配到常量1.那就执行语句1,如果常量1-常量N都没有匹配到,则其他情况都会被默认成default的情况,执行default下的语句。如果语句1执行完之后,写了break则不再执行后续内容,直接结束整个switch语句,如果没有写break,则会沿着代码顺序一直运行至default下的语句。
总结如下:
① 根据switch表达式中的值,依次匹配各个case中的常量。一旦匹配成功,则进入相应case结构中,调用其执行语句。当调用完执行语句后,则任然继续向下执行其他case结构中的执行语句,直到遇到break关键字或此switch-case结构末尾结束为止。
② break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构。
③ switch结构中的表达式,只能是如下6种数据类型之一: byte、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)
④ case之后只能声明常量,不能声明范围。
int age = 10;
switch(age):
// 错误
case age>18:
System.out.prinln("成年了");
default:
System.out.prinln("未成年");
⑤ break关键字是可选的
⑥ default: 相当于if-else结构中的else,位置灵活
int age = 10;
switch(age):
// 虽然可以这么写,但是这可读性太差了 别这么写 别这么写 别这么写
default:
System.out.prinln("未成年");
case 18:
System.out.prinln("成年了");
例题:
-
使用switch把小写的char转换成大写。只转换a,b,c,d,e其他输出other(整个题目的难点在怎么从屏幕获取一个char,如果上文看了应该知道,scan方法没有专门为char提供next方法,需要获取字符串,然后通过字符串.charAt(N),来获取字符串中第N位的字符)
int score = 78; switch(score / 10){ case 0: case 1: case 2: case 3: case 4: case 5: System.out.println("不及格"); break; case 6: case 7: case 8: case 9: case 10: System.out.println("不及格"); break; } // 特意把这题写一下说一下,可以这么写,把多种情况合并一下 这并不是这道题的最优解
-
输入学生成绩,大于60输出"合格", 低于"60"输出“不合格”
-
根据用于指定月份,打印月份季节(345春,678夏,9,10,11 秋, 12 ,1 ,2 冬季)
-
编写程序: 从键盘上输入2020年的"month"和"day",要求通过程序输出输入的日期为2020年的第几天
说明:
- 凡是可以使用switch-case的结构,都可以转换为if-else。反之,不成立。
- 当我们写分支结构时,当发现既可以使用switch-case,(同时,switch中表达式不多的取值情况不太多)又可以使用if-else时,我们优先选择使用switch-case。原因: switch-case执行效率稍高
循环结构
在某些条件满足的情况下,反复执行特定代码的功能
循环语句分类:
- for 循环
- while 循环
- do-while循环
循环语句的四个组成部分:
- 初始化部分
- 循环条件部分 — 》 boolean类型
- 循环体部分
- 迭代部分
for循环的结构:
for(①; ②; ④){
③;
}
// 执行过程① --> ② --> ③ --> ④ --> ② --> ③ --> ④ ... --> ② --> ③ --> ④
/*
如果 要草这个人的妈十次
*/
class ForTest {
public static void main(String[] args) {
// 没学for循环前的我
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
System.out.println("我草泥马");
// 就很累
// 学了for循环的我
for(int i = 1; i <= 10; i++){
System.out.println("我草泥马");
}
// 轻松 而且优雅
}
}
反人类练习
int num = 1;
// 注意println和print的差别,一个换行输出,一个不换
for(System.out.print("a"); num <= 3; System.out.print('c'), num++){
// 注意上面那个逗号 ',' 是这么写的 不会报错。
System.out.print('b');
}
// 输出结果: abcbcbc
接下来要说一个问题,for循环的i只在for循环内部有效,出了for循环就失效了。
-
遍历100以内的偶数,且输出偶数的和
// 遍历100以内的偶数 for(int i = 1; i <= 100; i++){ if (i % 2 == 0){ System.out.println(i); } } //遍历100以内的偶数,且输出偶数的和 int sum = 0; for(int i = 1; i <= 100; i++){ if (i % 2 == 0){ System.out.println(i); sum += i; } } System.out.println("总和为:" + sum); // 思考题: 去记录偶数的个数
每日一考
-
switch后面使用的表达式可以是哪些数据类型的
-
使用switch语句改写下列if语句
int a = 3; int x = 100; if (a == 1) x += 5; else if(a == 2) x += 10; else if(a == 3) x += 16; else x += 34;
-
谈谈你对三元运算符、if-else和switch-case结构使用场景的理解
-
如何从控制台获取String和int型的变量,并输出? 使用代码实现
-
使用for循环遍历100以内的奇数,并计算所有奇数和并输出。
-
while循环的使用
回顾一下循环的4个要素
① 初始条件
② 循环条件
③ 循环体
④ 迭代条件
那么while循环中,这四个要素是怎么起作用的呢
①
while(②){
③;
④;
}
知道了基本的用法,我们来看看实际例题
/*
遍历100以内的所有偶数
*/
class WhileTest{
public static void mian(String[] args) {
// 遍历100以内的所有偶数
int i = 1;
while(i <= 100){
if(i % 2 == 0){
System.out.println(i);
}
//迭代条件,不写意味着死循环 ,i永远小于一
i++;
}
// 注意哦! 这里的i和for循环的i不同,你是定义在循环体外部的所有出了循环之后,依旧是可以使用的
System.out.println(i);// 101
}
}
好的! 学会了以上的用法,基本上就懂了while循环的使用了,接下来说几个需要注意的点:
- 写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!
- 避免出现死循环
- for循环和while循环是可以相互替换的!
知道了以上几点,有的人可能会疑虑,那么while循环的执行顺序是怎么样的呢:
① —> ② —> ③ —> ④ —> ② —> ③ —> ④…
do-while循环
①;
do{
③;
④;
}while(②);
执行顺序:① —> ③ —> ④ —> ② —> ③ —> ④ —> ②;
意思就是不管你符不符合这个②的条件,程序在从上至下执行的过程中,会先走一次①③④再去判断这个是否满足②的条件。
while(true)死循环的特殊用法
/*
从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为0时结束程序
*/
import java.util.Scanner
class ForWhileTest{
public static void mian(String[] args) {
Scanner scan = new Scanner(System.in);
int positiveNumber = 0;// 记录正数的个数
int negativeNumber = 0;// 记录负数的个数
while(true){
// for(;;){ 这种写法也是等于死循环的
int number = scan.nextInt();
// 判断number的正负情况
if(number > 0){
positiveNumber++;
} else if (number < 0) {
negativeNumber++;
} else {
// 一旦执行就跳出循环
break;
}
}
System.out.println("输入的正数个数为: " + positiveNumber);
System.out.println("输入的正数个数为: " + negativeNumber);
}
}
嵌套循环
主要是有些同学,嵌套的层数多了就容易迷糊,所以专门拿出来说一下
嵌套循环: 将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环
经典例题: 输出九九乘法表
/*
九九乘法表
1 * 1 = 1
2 * 1 = 2 2 * 2 = 4
...
9 * 1 = 9 ......... 9 * 9 = 81
*/
class NineNineTable {
public static void main (String[] args) {
for (int i = 1; i <= 9; i++){
for (int j = 1; j <= i; j++){
// 注意这里不换行
System.out.print(i + "*" + j + " = " + (i * j)+ " ");
}
// 换行
System.out.println();
}
}
}
思考题: 输出100 以内所有质数(也叫素数,只能被一和它本身整除的自然数)
public PrimeNumberTest {
public static void main(String[] args) {
boolean isFlag = true;// 标识i是否被j除净,一旦除净 倒旗
for(int i = 2; i <= 100; i++){
for(int j = 2; j < i; j++){
if(i % j == 0){ // i被j除尽
isFlag = false;
}
}
}
}
}
特殊的关键字使用
break与continue
这个没啥好特殊说明的记住一句话,然后看代码演示
break 跳出所有循环,continue跳出当前循环
class BreakContinueTest {
public static void main(String[] args){
for(int i = 1; i <= 10; i++){
if(i % 4 == 0){
break;// 会输出123
//continue;// 会输出123567910
// System.out.println("我是你ge");这里写了就报错,关键字后面不允许饥接这个。
}
System.out.println(i);
}
}
}
带标签的break和continue的使用
class BreakContinueTest {
public static void main(String[] args){
label:for(int i = 1;i < 4; i++){
for(int j = 1;j <= 10; j++){
if(i % 4 == 0){
continue;// 默认是跳出此关键字最近的一层循环
continue label;// 结束指定的label标识的循环
}
}
}
}
}
案例整合
以上知识点我们在这里通过一个案例来整合一下,案例需求如下:
模拟实现一个基于文本界面的<记账软件>
主要涉及以下知识点:
变量的定义
基本数据类型的使用
循环语句
分支语句
方法声明、调用和返回值接收
简单的屏幕输出格式控制
大概的用户展示界面如下
-
-
-
-
-
- 家庭收支记账软件 - - - - - -
-
-
-
-
- 收支明细
- 登记收入
- 登记支出
- 退出
具体代码附上git地址,关于git使用移步至
java项目的项目结构
一般不管用什么开发工具,我们习惯先建一个java工程(java project),此处我是使用的idea,大部分java入门的是采用eclipse,但是我懒得去下了,这本来就是平时开发工作中用的比较多的一个开发工具。以下是具体的使用步骤。
安装好软件之后,打开idea按如下步骤操作
选择好你电脑上配置好的java环境的jdk,然后点击next
按步骤点击之后,在新的窗口或者原窗口展示
在src目录下
基本数据类型和引用数据类型的区别
基本数据类型:
- 整型变量:
long、int、short、byte
- 浮点型:
float、double
- 字符类型:
char
- 布尔类型:
boolean
引用数据类型
所有非基本数据类型的数据都算是引用数据类型,大致包括(类、 接口类型、 数组类型、 枚举类型、 注解类型、 字符串型)
当然,这些不能作为区分基本数据类型和引用数据类型的标准,其具体的区别在于在内存中的存放形式,聊这个之前先要了解堆和栈的概念
数组
这里说以下,因为我是从python转到java来的,这个数组这个数据结构再python中也有类似的,但是python中称为列表,如果同样有这种基础的同学,方便你的后续学习内容的理解
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据统一管理。粗略的文字说明可能不太形象,大家不知道对数学中的"集合"的概念还有没有印象,比如我现在有很多数字 1, 2, 3, 4,我可以说他是有理数集合中的元素,那在编程中,也有类似的‘集合’我们称之为数组,当然他们是有很多区别的,后续我们慢慢说。java中,把这些数用一个符号标注起来使他成为这期我们要学的数组[1,2,3,4,5]
。现在我们思考一个问题这些数这些数为什么被划分到有理数集合中,本质是因为1,2,3,4这些数都是有理数,所以同样的,java中把这种有相同数据类型的变量,统一放入一个容器中,这个容器就叫做数组
数组的特点:
-
数组我们可以把它看成是一个只能装某一个种数据类型的容器,数组本身是一个引用数据类型,区别于基本数据类型(byte,short,int,long,char,float,double,boolean)其内的元素可以是基本数据类型也可以是引用数据类型(String)
-
创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这一块连续空间的首地址
-
数组的长度一旦被确定,就不能修改
我们可以通过下标或索引的形式去获取元素,速度很快。
一维数组的使用
- 一维数组的声明和初始化
- 如何调用数组的指定位置的元素
- 如何获取数组的长度
- 如何遍历数组
- 数组元素的默认初始化值
- 数组的内存解析
public class ArrayTest {
public static void main(String[] args){
// 一维数组的声明
int num;// 声明
num = 10;// 初始化
int num = 10;
int[] ids;// 声明变量
// 1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
ids = new int[]{1001,1002,1003,1004};
// 1.2 动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[] names = new String[5];
// 总结: 数组一旦初始化完成,其长度就确定了,为啥要确定呢,你不确定电脑怎么给你分配确定空间的内存呢
// 如何调用指定位置的元素: 通过角标的方式
name[0] = "小张";
name[1] = "小周";
name[2] = "小虎";
name[3] = "小龙";
name[4] = "小朱";
// 语法上这里都是可以过的,但是运行的时候,正真把数据加载到内存中后,会报
// ArrayIndexOutOfBoundsException
//name[5] = "小王";
// 如何获取数组的长度
// 属性: length
System.out.println(name.length);//5
System.out.println(ids.length);
// 如何遍历数组
for(int i = 0; i < names.length; i++){
System.out.println(names[i]);
}
// 数组元素的默认初始化:整型
int[] arr = new int[4];
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
// 会输出四个0
}
// 整型: 0
short[] arr1 = new short[4];
for(int i = 0; i < arr1.length; i++){
System.out.println(arr1[i]);
}
//浮点型: 0.0
//字符类型: assci码的0 或者说是'\u0000' 输出出来是一个空格的效果,注意不是空格,只是空格的效果
//布尔类型: false
// 除了基本数据类型,还有引用数据类型 null
String[] arr5 = new String[5];
System.out.println(arr5[0]);
// 内存解析:
// 见上方的 基本数据类型和引用数据类型中提到的内容,这一块对于新手来说,已经不是文字这么好解释的了
// 建议去看看具体的视频,新手推荐尚硅谷的https://www.bilibili.com/video/BV1Kb411W75N?p=146,其中P145-P146
// 其中还有一个知识点,对于String[] arr1 = new String[4] String 本身是在常量区中的,对于这种
// 数组,堆中的list的内存空间只是持有常量区的引用。但是在JDK8以后,把常量池放到了堆里面,取消了方法区。
}
}
多维数组的使用
多维数组本身不叫多维数组,它形似[[“张熊”,“743146159”],[“熊”,“123498765”]]最外层的数组的每一项代表对内层数组的引用
对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在
- 二维数组的声明和初始化
- 如何调用数组的指定位置的元素
- 如何获取数组的长度
- 如何遍历数组
- 数组元素的默认初始化值
- 数组的内存解析
public class ArrayTest2 {
public static void main(String[] args) {
// 静态初始化
int[][] arr1 = new int[][]{{1,2,3},{2,3,4},{4,5,6}};
// 动态初始化
String[][] arr2 = new String[3][2];
// 这样也行
int[] arr3[] = new int[][]{{1,2,3},{1,2,3}};
int[] arr5[] = {{11,1,2},{2,2,2},{3,4,4}}
// 调用
System.out.println(arr1[0][1]);
// 获取数组长度
System.out.println(arr1.length);//3
// 如何遍历 for循环嵌套 偷懒不想写了,大概理解一下吧
//二维数组的使用
int[][] arr = new int[4][3];
System.out.println(arr[0]);// 输出arr[0]对应的这个数组的地址值
System.out.println(arr[0][0]);// 0 其他类型参照一维数组
}
}
每日一考
- 写出一维数组初始化的两种方式
- 写出二维数组初始化的两种方式
- 如何遍历如下的二维数组
- 不同类型的一维数组元素默认初始化值各是多少
数组的赋值
如果有一个数组arry1 = new int[]{2,3,5,7,11,13,17,19}; 如果arry2 = arry1,此时如果对arry2进行修改,那arry1会不会有影响呢?因为在堆空间中,实际只有一个数组,但是arry1与arry2两个变量在栈空间中,此时的赋值操作,只是把这两个变量都指向了同一个引用
Arrays工具类的使用
binarySearch(char[] a,char key)二分查找返回结果这个key首次出现的索引位置
equals(int[] a,int[] b)判断两个数组是否相等,返回布尔值
toString(int[] a)输出数组信息,返回值是一个String
fill(int[] a,int val)将指定值填充到数组中
sort(int[] a)对数组排序
public class ArraysTest {
public static void main(String[] args) {
// 1.boolean equals(int[] a,int[] b)
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = new int[]{1,3,2,4};
boolean isEquals = Arrays.equals(arr1,arr2);
System.out.println(isEquals);
// 原码里面,校验了四个方面,两个数组地址值是否相等(a == a1),两个是否为null(a == null || a1 == null),长度是否相等,以及最后内部元素是否相等
//2.String toString(int[] a)
System.out.println(Arrays.toString(arr1));//"[1,2,3,4]"
//3.void fill(int[] a,int val)
Arrays.fill(arr1,10);
System.out.prinln(Arrays.toString(arr1));//[10,10,10,10],就是把原来的值全部替换
//4.void sort(int[] a)
Arrays.sort(arr2);// 底层用了一个快排的类
System.out.println(Arrays.toString(arr2));
//5. int binarySearch(int[] a,int key)
// 就二分法查找 没找到返回一个负数
}
}
几个比较常见的异常: 越界(ArrayIndexOutOfBoundsExcetion)、空指针(NullPointerException)