1991年,James Gosling在SUN公司的工程师小组想要设计这样一种小型计算机语言。该语言主要用于像电视盒这样的消费类电子产品。另外,由于不同的厂商选择不同的CPU和操作系统,因此,要求该语言不能和特定的体系结构绑在一起,要求语言本身是中立的,也就是跨平台的。所以,将这个语言命名为“Green”,类似于绿色软件的意思。后来,改名为Oak,橡树的意思。改名后发现已经有一种语言叫这个名字了,再改名叫 Java。
1991年,SUN公司的Green项目,Oak
1995年,推出Java测试版
1996年,JDK1.0
1997年,JDK1.1
1998年,JDK1.2,大大改进了早期版本缺陷,是一个革命性的版本,更名为Java2。
2004年,J2SE 5.0 (1.5.0) Tiger老虎
2006年,J2SE 6.0 (1.6.0) Mustang野马
2011年,JavaSE7.0 Dolphin海豚
2014年,JavaSE8.0
2017年,JavaSE9.0
2018年,JavaSE10.0
JAVASE(Java Platform Standard Edition)标准版。
是为开发普通桌面和商务应用程序提供的解决方案
JAVAME(Java Platform To Micro Edition)小型版
是为开发电子消费产品和嵌入式设备提供的解决方案
JAVAEE(Java Platform To Enterprise Edition)企业版
是为开发企业环境下的应用程序提供的一套解决方案
跨平台 —— compile once,run anywhere
面向对象 解释型
健壮 动态
分布式 高效
多线程 结构中立(字节码)
开源
通过Java语言编写的应用程序在不同的系统 平台上都可以运行。
Java程序是在Java虚拟机上运行,而非直接运行于操作系统
JRE(JAVA Runtime Environment)
包括Java虚拟机,运行时核心类库(rt.jar),JRE主要是给已经写好的Java程序使用,换句话说Java程序要能在操作系统中运行,必须有JRE
JDK(JAVA Develop kit)
首先,JDK包含JRE,除此之外,JDK中还包含一些,供开发者使用的工具比如Javac,Javap等,仅仅只供开发者在开发阶段使用的工具。
JDK下载
JDK安装
建议JDK安装路径中不要有中文,同时当提示安装JRE时,可以选择不安装
path环境变量
告诉操作系统到哪里去找javac可执行程序配置
classpath环境变量
给jvm用,告诉jvm到哪里加载字节码文件配置
开发Java程序,可以使用的工具很多:
被Java语言赋予特殊含义的单词
组成关键字的字母全部小写
高级的编辑器或者专门的开发工具中,关键字会有高亮效果
goto和const作为保留字存在,目前并不使用
就是给类,接口,方法,变量等起名字时使用的字符序列
英文大小写字母
数字字符
$和_
英文大小写字母
数字字符
$和_
常见命名规则:驼峰命名
包命名
单级 一个全部小写的单词
多级包名 以域名反转的方式来命名,单词全部小写,单词之间以.分隔
类和接口命名
单个 首字母大写,其余字母全部小写
多个单词 每个单词首字母大写,其余字母全部小写
变量和方法的命名
单个 所有字母小写
多个单词 第一个单词首字母小写,从第二个单词开始,每个单词首字母大写
常量的命名
单个 单词的所有字母全部大写即可
多个单词 每个单词全部大写,单词之间以_来分隔
在实际开发当中,命名要遵循的一个核心原则:见名知意
用于解释说明的文字
Java语言的注释分类:
单行注释
格式
多行注释
格式 注释内容
文档注释
格式 文档注释内容
千万不要忽视注释的作用!!
写代码
项目维护,阅读代码
案例
类 型 | 占用存储空间 | 表数范围 |
---|---|---|
byte | 1字节 | -127~127 |
short | 2字节 | − 2 15 -2^{15} −215~ 2 15 − 1 2^{15}-1 215−1 |
int | 4字节 | − 2 31 -2^{31} −231 ~ 2 31 − 1 2^{31}-1 231−1 |
long | 8字节 | − 2 63 -2^{63} −263 ~ 2 63 − 1 2^{63}-1 263−1 |
float | 4字节 | -3.403E38 ~ 3.403E38 |
double | 8字节 | -1.798E308 ~ 1.798E308 |
boolean类型的值不能直接转化为其它数据类型的值
默认(自动)的转化规则
byte,short,char—>int—>long—>float—>double
byte,short,char相互之间不转换,他们参与运算首先转换为类型
强制转化
目标类型 变量名=(目标类型)(被转换的数据);
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | b=4; - b; | -4 |
+ | 加 | 5+5 | 10 |
- | 减 | 6-4 | 2 |
* | 乘 | 3*4 | 12 |
/ | 除 | 5/5 | 1 |
% | 取模 | 5%5 | 0 |
++ | 自增(前) | a=2; b=++a | a=3; b=3 |
++ | 自增(后) | a=2; b=a++ | a=3; b=2 |
– | 自减(前) | a=2; b=–a | a=1; b=1 |
– | 自减(后) | a=2; b=a– | a=1; b=2 |
+ | 字符串相加 | “He”+“llo” | “Hello” |
"+"三种用法
//1.加法
int a =1 ;
int b = 2;
System.out.println(a + b);
//2.表示正数的正号
a = +1;
//3.字符串拼接
//操作数1 + 操作数2 两个操作数中,只要至少有一个是字符串,+操作执行的就是字符串拼接
System.out.println("hello" + 'a' + 1);
System.out.println('a' + 1 + "hello");
System.out.println("5+5=" + 5 + 5);
System.out.println(5+5+"=5+5");
"/"用法
/: 除法运算
%: 求余数的操作
int a = 3;
int b = 2;
//当参与除法运算的除数和被除数,他们都是参数的时候,此时除法运算的结果
//会丢弃小数部分,只保留整数部分
int c = a / b;
System.out.println("c = " + c);
double d = a / b;
System.out.println("d = " + d);
//隐式类型转化
double e = 1.0 * a / b;
System.out.println("e = " + e);
"++"与"--"
//++
int a = 1;
a++;
System.out.println("a++ = " + a);
a = 1;
++a;
System.out.println("++a = " + a);
//--
int b = 2;
b--;
System.out.println("b-- = " + b);
b = 2;
--b;
System.out.println("--b = " + b);
//++在前和在后的区别
a = 1;
int result = a++ + 1;
//System.out.println(result);
//System.out.println(a);
a = 1;
result = ++a + 1;
//System.out.println(result);
//System.out.println(a);
//--
b = 2;
result = b-- - 1;
System.out.println(result);
System.out.println(b);
b = 2;
result = --b - 1;
System.out.println(result);
System.out.println(b);
//
a = 4;
// 4 + 6 + 60
b = (a++) + (++a) + (a * 10);
System.out.println(b);
= , +=, -=, *=, /=, %=,
其中 *=====* 为基本的赋值运算符,其他的为扩展的赋值运算符
+=, -=, *=, /=, %=: 复合赋值运算
a += 3 <-> a 执行相应运算,之后的结果在赋值给a
a = a + 3
int a = 1;
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
== | 相等于 | 4==3 | false |
!= | 不等于 | 4!=3 | true |
< | 小于 | 4 < 3 | false |
> | 大于 | 4 > 3 | true |
<= | 小于等于 | 4 <= 3 | false |
>= | 大于等于 | 4 >= 3 | true |
instanceof | 检查是否是类的对象 | “Hello” instanceof String | true |
关系运算符的结果只有两种 true or false
int a = 3;
int c = 4;
boolean b = a > c;
System.out.println(b);
&: true & false = false true & true = true false & true = false false & false = false
只要至少有一个操作数是false,结果就是false,只有当两个操作数都是true的时候,&运算的结果,才是true
|: true | false = true true | true = true false & true = true false | false = false
只要至少有一个操作数是true,结果就是true,只有当两个操作数都是false,|运算的结果,才是false
!: !true = false !false = true
注意事项:
单“&”与双“&&”的区别(短路)
&& VS & 都是与运算,他们有什么区别呢?
&& 与运算比较智能, 当它发现&&运算符的第一个操作数结果已经是false,
第二个操组数(对应的表达式)不去管他,直接得到结果&&的结果false
& 这种与运算,比较的死板,即使&第一个操作数,它已经是false,此时它仍然会计算第二个操作数(表达式),在把计算好的两个操作数的结果,做与运算,得到最终结果
&&: 有短路效果,当第一个操作数为false,直接得出与运算的结果
或运算符只要至少有一个操作数是true,结果就是true
==||==或运算比较智能,有短路效果
异或运算 ^ : 相同为false, 不同为true
true ^ true = false false ^ false = false
true ^ false = true false ^ true = true
int a = 2;
int b = 3;
boolean c = a > b & a++ == 0;
System.out.println(a);
a = 2;
//证明&& 操作符比较智能
c = a > b && a++ == 0;
System.out.println(a);
//证明||有短路效果
a = 2;
c = a < b || a++ == 0;
System.out.println(a);
//异或运算
c = true ^ false;
c = true ^ true;
System.out.println(c);
//表示一个范围
a = 3;
//判断a变量的值是否在[1,10) 1 <= a < 10
//c = 1 <= a < 10;
c = a >= 1 && a < 10; //判断变量a的值是否在[1,10)
位运算符 |
运算符 | 运算 | 范例 |
---|---|---|
<< | 左移 | 3<<2 = 12 --> |
>> | 右移 | 3>>1 = 1 --> |
>>> | 无符号右移 | 3>>>1 = 1 --> |
& | 与运算 | 6&3 =2 |
| | 或运算 | |
^ | 异或运算 | 6^3 = 5 |
~ | 按位取反 | ~6 = -7 |
位运算符的细节 |
<< | 空位补0,被移除的高位丢弃 |
---|---|
>> | 被移位的二进制最高位是0,右移后,空缺位补0; |
最高位是1,最高位补1。 | |
>>> | 被移位二进制最高位无论是0或者是1,空缺位都用0补。 |
& | 任何二进制位和0进行&运算,结果是0; |
和1进行&运算结果是原值。 | |
| | 任何二进制位和0进行 | 运算,结果是原值; |
和1进行 | 运算结果是1。 | |
^ | 任何相同二进制位进行 ^ 运算,结果是0; |
不相同二进制位 ^ 运算结果是1。 |
1.请用最有效率的方式写出计算2乘以8的结果 2.请自己实现两个整数变量的交换
2.请自己实现两个整数变量的交换
//1.
int a = 2 << 3;
System.out.println(a);
//2.请自己实现两个整数变量的交换(才是开发中常用的)
int a = 10;
int b = 200;
//两个变量的交换
int tmp = a;
a = b;
b = tmp;
System.out.println("a = " + a + "----- b = " + b);
//变量交换的实现方式2: //ctrl + alt + l
a = 10;
b = 200;
a = a + b;
b = a - b; // a + b - b = a
a = a - b; // a + b - a = b
System.out.println("a = " + a + "----- b = " + b);
//实现方式3:
a = 10;
b = 200;
a = a ^ b;
b = a ^ b;// a ^(b ^ b) = a
a = a ^ b;// a ^ b ^ a -> a ^ a ^ b
System.out.println("a = " + a + "----- b = " + b);
//实现方式4
a = 10;
b = 200;
// (a + b) - a = b
a = (a+b) - (b=a); //(b = a) 表达式的值是赋值之后的b的值
System.out.println("a = " + a + "----- b = " + b);
格式:
关系表达式 ?表达式1 : 表达式2
如果关系表达式结果为为true,运算后的结果是表达式1;
如果关系表达式结果为false,运算后的结果是表达式2;
public class Demo {
public static void main(String[] args) {
int a;
int b;
//使用键盘输入
Scanner sc = new Scanner(System.in);
a = sc.nextInt();
b = sc.nextInt();
//用关系表达式判断两数是否相同
String s = a == b ? "两数相等" : "两数不相等";
System.out.println(s);
// 3数取大
int c = 100;
//两数取大,第三个数和两数中的大者比较,取它们的大者就是最大值
int tmp = a > b ? a : b;
int result = tmp > c ? tmp : c;
System.out.println("最大的是: " + result);
//三目运算的,3数取大的嵌套形式
//int tmp = a > b ? a : b;
//int result = tmp > c ? tmp : c;
result = (a > b ? a : b) > c ? (a > b ? a : b) : c;
System.out.println("最大的是: " + result);
}
}
//导包语句(放到class定义的上面):
import java.util.Scanner;
//创建对象
Scanner sc = new Scanner(System.in);
//从键盘输入读取数据
int x = sc.nextInt();
键盘录入两个数据,并对这两个数据求和,输出其结果
键盘录入两个数据,获取这两个数据中的最大值
键盘录入三个数据,获取这三个数据中的最大值
键盘录入两个数据,比较这两个数据是否相等
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//键盘录入两个数据,并对这两个数据求和,输出其结果
System.out.print("请输入a:");
int a = in.nextInt();
System.out.print("请输入b:");
int b = in.nextInt();
System.out.println("a+b=" + (a + b));
//键盘录入两个数据,获取这两个数据中的最大值
System.out.print("请输入c:");
int c = in.nextInt();
System.out.print("请输入d:");
int d = in.nextInt();
System.out.println(c + "和" + d + "中最大的是:" + Math.max(c, d));
//键盘录入三个数据,获取这三个数据中的最大值
System.out.print("请输入e:");
int e = in.nextInt();
System.out.print("请输入f:");
int f = in.nextInt();
System.out.print("请输入g:");
int g = in.nextInt();
System.out.println(e +"、"+f+"和" + g + "中最大的是:" +Math.max(Math.max(e, f), g));
//键盘录入两个数据,比较这两个数据是否相等
System.out.print("请输入h:");
int h = in.nextInt();
System.out.print("请输入i:");
int i = in.nextInt();
String string = (h==i)?"相等":"不相等";
System.out.println(h + "和" + i + " " + string);
in.close();
}
}
一个Java程序,通常是由多条符合Java语法规则的语句组成的。
一个Java程序的执行,一定意味着多条Java语句的执行。
既然是多条Java语句的执行,执行的结果就一定与语句执行的顺序有关,同样的语句,不同的执行顺序,结果可能不同
int i = 1;
int b = 2;
选择结构中的代码顺序和顺序结构中代码的执行顺序有明显的不同:
选择结构有特定的语法规则,代码要执行具体的逻辑运算进行判断。
逻辑运算的结果有两个,所以产生选择,按照不同的选择执行不同的代码。
Java中,选择结构有2种实现形式,if语句 和switch语句
单分支的选择结构: 如果…就
判断提条件的结果只能是true or false
if(判断条件) {
//语句体
}
判断条件是由一个 关系表达式 来表示的
Scanner in = new Scanner(System.in);
int input = in.nextInt();
//单分支的 if 当用户输入的是正数就输出一下,否则什么都不做
if (input > 0) {
System.out.println("亲,您输入的是一个正数:" + input);
}
if (判断条件) {
} else {
}
Scanner in = new Scanner(System.in);
int input = in.nextInt();
//双分支 当用户输入正数的时候输出一下用户输入的正数,当用户输入了非正数提示一下,请用户输入正数
if (input > 0) {
System.out.println("亲,您输入的是一个正数:" + input);
} else {
System.out.println("亲,请重新输入一个正数");
}
if(判断条件1) {
条件1语句体
} else if (条件2) {
条件2语句体
}
...
else if (条件n) {
} else {
// 第n + 1种情况
//当else前都不满足条件的时候,就会执行else中的语句体
}
Scanner in = new Scanner(System.in);
int input = in.nextInt();
//多分支 当用户输入正数,0,负数
if (input > 0) {
System.out.println("亲,您输入的是一个正数:" + input);
} else if (input == 0) {
System.out.println("亲,您输入了一个0");
} else {
System.out.println("亲,请重新输入一个数字");
}
在绝大部分场景下,三目运算符和if双分支选择结构,都可以相互替代,
//关于双分支的if选择结构
// 实现两数取大
int a = 3;
int b = 10;
int max;
if (a > b) {
max = a;
} else {
max = b;
}
//可以用三目运算符来实现两数取大
max = a > b ? a : b;
但是,如果选择结构执行的仅仅只是一个操作,没有返回值,此时if双分支选择结构不可以和三目运算相互替代
//我们发现3目运算符的语义和if双支选择结构,语义几乎完全相同,
// 都是非此即彼,但是至少有一种情况,它们不能相互替代
if (a > b) {
System.out.println("大者是" + a);
} else {
System.out.println("大者是" + b);
}
//三目运算符的结果一定是一个值
//a > b ? System.out.println("大者是" + a) : System.out.println("大者是" + b);
小练习
1.键盘录入x的值,计算出y的并输出。
x和y的关系满足如下:
x>=3 y = 2x + 1;
-1<=x<3 y = 2x;
x<=-1 y = 2x – 1;
Scanner scanner = new Scanner(System.in);
int x = scanner.nextInt();
int y;
if ( x >= 3) {
y = 2 * x + 1;
} else if (x >= -1 && x < 3) {
y = 2 * x;
} else {
// x <= -1
y = 2 * x - 1;
}
System.out.println("x = " + x + "---- y = " + y);
2.键盘录入月份的值,输出对应的季节。
12 1 2 冬季
3 4 5 春季
6 7 8 夏季
9 10 11 秋季
if (x == 12 || x == 1 || x == 2) {
//冬季
System.out.println("冬季");
} else if ( x >= 3 && x <= 5) {
//春季
System.out.println("春季");
} else if ( x >= 6 && x <= 8 ) {
//夏季
System.out.println("夏季");
} else if ( x >= 9 && x <= 11) {
//秋季
System.out.println("秋季");
} else {
//应对用户错误的输入
System.out.println("亲,您输入了错误的月份");
}
3.获取三个数据中的最大值
int a = 10;
int b = 20;
int c = 15;
//if的嵌套来实现
//if (a > b) {
// // a大
// if(a > c) {
// // a 最大
// System.out.println("最大值是: " + a);
// } else {
// // c最大
// System.out.println("最大值是 " + c);
// }
//} else {
// // b大
// if (b > c) {
// System.out.println("最大值是: " + b);
// } else {
// System.out.println("最大值是: " + c);
// }
//}
//非嵌套方式
int tmp;
if ( a > b) {
tmp = a;
} else {
tmp = b;
}
if (tmp > c) {
System.out.println(tmp);
} else {
System.out.println(c);
}
switch语句格式:
switch(表达式) {
case 值1: //这个值,代表的一个特定分支
语句体1; //满足条件的分支执行的语句体
break;
case 值2:
语句体2;
break;
…
default:
语句体n+1;
break;
}
格式解释:
switch关键字:表示这是一个switch语句 switch后的表达式:表示选择条件 表达式。
case语句:每个case 语句表示一个分支 类比于if所表示的一个分支
break语句:表示结束switch语句
default语句:表示当所有其他的case的分支,都不能匹配switch后表达式的值的时候,此时就会执行default分支。 有点类似于 if-else多分支中最后的else
注意事项:
所谓的case穿越是指:
当匹配到switch语句的某个分支,当该分支中不包含break语句,swtich语句不会自动结束,紧接着执行,紧邻的下一个case的语句体,最终要么遇到别的分支中的break;结束,要么匹配到最后一个case,结束switch语句
语法上可以,一般建议不要省略,我们根据实际开发需要来决定
语法上没有问题,default分支可以放在switch的任意位置,注意default分支,如果不在最后,如果不加break,仍然会发生case穿越现象
小练习
模拟做单项选择题,根据你的选择,给出对应的答案。(表达式是字符的情况)
System.out.println("你的女神是?");
System.out.println("A.高圆圆");
System.out.println("B.云姐");
System.out.println("C.沈佳宜");
System.out.println("D.石原里美");
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
char c = s.charAt(0);
switch (c) {
case 'A' :
System.out.println("您的女神是:高圆圆");
break;
case 'B' :
System.out.println("您的女神是:云姐");
break;
case 'C' :
System.out.println("您的女神是:沈佳宜");
break;
case 'D' :
System.out.println("您的女神是:石原里美");
break;
}
键盘录入字符串,根据给定的字符串,来输出你选择的字符串是什么?(表达式是字符串的情况)
switch (s) {
case "A" :
System.out.println("您的女神是:高圆圆");
break;
case "B" :
System.out.println("您的女神是:云姐");
break;
case "C" :
System.out.println("您的女神是:沈佳宜");
break;
case "D" :
System.out.println("您的女神是:石原里美");
break;
}
用switch语句实现键盘录入月份,输出对应的季节
int month = sc.nextInt();
switch (month) {
case 12:
case 1:
case 2:
System.out.println("冬季");
break;
case 3:
case 4:
case 5:
System.out.println("春季");
break;
case 6:
case 7:
case 8:
System.out.println("夏季");
break;
case 9:
case 10:
case 11:
System.out.println("秋季");
break;
default:
System.out.println("您输入了错误的月份");
}
看程序写结果
//1.
int x = 2;
int y = 3;
switch(x){
default:
y++;
break;
case 3:
y++;
case 4:
y++;
}
System.out.println("y="+y);
y = 4;
int x = 2;
int y = 3;
switch(x){
default:
y++;
case 3:
y++;
case 4:
y++;
}
System.out.println("y="+y);
y = 6;
循环结构与顺序结构和选择结构不同,循环结构的主要功能是控制Java语句能够重复执行。
循环结构,从语法上来讲,有3中实现形式:
但是不管哪种实现形式,都由4部分组成:
基本格式:
for(初始化语句;判断条件语句;控制条件语句) {
循环体语句;
}
示例:
for(int i = 1; i <= 10; ++i) {
System.out.println("hello 你好 --- " + i);
}
注意事项:
1. 判断条件语句的结果的数据类型 只能是boolean
2. 循环体语句
练习:
请在控制台输出数据1-10
//请在控制台输出数据 1-10 第一个数1 最后一个数10
for (int i = 1; i <= 10; i++) {
System.out.print(i + "\t");
}
System.out.println();
请在控制台输出数据10-1
//请在控制台输出数据 1-10 第一个数10 最后一个数1
for (int i = 10; i >= 1; i--) {
System.out.print(i + "\t");
}
System.out.println();
求出1-10之间数据之和
//求1~10之间数据的和
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum = sum + i;
}
System.out.println("1~10之间数据的和为:" + sum);
求出1-100之间偶数和
//求 1~100之间所有偶数的和
sum = 0;
for (int i = 2; i <= 100; i = i + 2) {
sum = sum + i;
}
System.out.println(sum);
求5的阶乘
//求5 的阶乘
int multi = 1;
for (int i = 1; i <= 5; i++) {
multi = multi * i;
}
System.out.println(multi);
在控制台输出所有的”水仙花数”
//水仙花数
for (int i = 100; i <= 999; i++) {
//百位
int a = i / 100;
//十位
int b = i % 100 / 10;
//个位
int c = i % 10;
if (i == (a * a * a + b * b * b + c * c * c)) {
System.out.print(i + "\t");
}
}
统计”水仙花数”共有多少个
//水仙花数的个数
int count = 0;
for (int i = 100; i <= 999; i++) {
//百位
int a = i / 100;
//十位
int b = i % 100 / 10;
//个位
int c = i % 10;
if (i == (a * a * a + b * b * b + c * c * c)) {
// System.out.print(i + "\t");
count++;
}
}
System.out.println(count);
基本格式:
初始化语句;
while (条件判断语句) {
循环体语句;
}
联系:
for循环和while循环的联系:
for循环和while循环几乎可以在任何场景下,作等价替换
for循环和while循环的区别:
直观来说,for循环适合针对一个范围判断进行操作(循环次数比较明确),while循环适合判断次数不明确操作
练习:
我国最高山峰是珠穆朗玛峰:8848m,我现在有一张足够大的纸张,厚度为:0.01m。请问,我折叠多少次,就可以保证厚度不低于珠穆朗玛峰的高度?
//初始化语句 纸张的初始化高度
double height = 0.01;
int count = 0;
while (height < 8848) {
height *= 2;
count++;
}
System.out.println("次数是:" + count + "---- height " + height);
基本格式:
初始化语句;
do {
循环体语句(也包含条件控制语句);
} while (条件判断);
示例:
//先执行循环体,在判断
int i = 10;
do {
System.out.println(i);
i++;
} while (i > 11);
注意事项:
do while 的while语句最后有一个 ;
do…while执行流程和之前的for和while稍有不同:
3种循环中,for循环和while循环等价
do … while循环与其他两种循环结构相比,略有不同,因为do…while结构可保证循环体至少执行一次
注意事项:
实际使用时,只要达到预期的效果,用哪个都可以
如非特殊情况,要注意要规避死循环问题(无限循环),如:
for( ; ; ) 或 while(true)
死循环并非不能使用(学习多线程时解释)
1.请输出一个4行5列的星星(*)图案。
∗ ∗ ∗ ∗ ∗ ***** ∗∗∗∗∗
∗ ∗ ∗ ∗ ∗ ***** ∗∗∗∗∗
∗ ∗ ∗ ∗ ∗ ***** ∗∗∗∗∗
∗ ∗ ∗ ∗ ∗ ***** ∗∗∗∗∗
∗ ∗ ∗ ∗ ∗ ***** ∗∗∗∗∗
for(int i = 0; i < 4; i++) {
//重复输出每一行的 *
for (int j = 0; j < 5; j++) {
System.out.print("*");
}
//换行输出下一行
System.out.println();
}
2.请输出如下图形
∗ * ∗
∗ ∗ ** ∗∗
∗ ∗ ∗ *** ∗∗∗
∗ ∗ ∗ ∗ **** ∗∗∗∗
∗ ∗ ∗ ∗ ∗ ***** ∗∗∗∗∗
for (int i = 1; i <= 5; i++) {
//控制输出每一行的*
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
System.out.println();
}
3.在控制台输出九九乘法表。
for (int i = 1; i <= 9 ; i++) {
//控制每一行输出的表达式
for (int j = 1; j <= i ; j++) {
//内存循环中的每一次执行,输出的是一个表达式
System.out.print(j + "x" + i + "=" + j * i + " ");
}
//换行
System.out.println();
}
用法:
public class BreakDemo {
public static void main(String[] args) {
//break的基本功能,结束单重循环
for (int i = 1; i <= 10; i++) {
// 输出到5
System.out.println(i);
if(i == 5) {
break;
}
}
System.out.println("--------------------------------------------------------------------");
// 终止外层循环
outer: //给外层循环定义了个标签(标识符)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if( j == 2) {
break outer;
}
System.out.println("i = " + i + " -- " + "j = " + j);
}
}
System.out.println("--------------------------------------------------------------------");
//结束case的用法之前已经在switch用过,不在赘述
}
}
用法:
public class ContinueDemo {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if(i == 5) {
//终止,单重循环的一次循环过程
continue;
}
System.out.println(i);
}
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if( j == 1) {
continue outer;
//break;
}
System.out.println("i = " + i + " -- " + "j = " + j);
}
}
}
}
结束当前方法的执行,不仅可以跳出循环,return后面的语句也无法执行到。
方法就是完成特定功能的代码块(在有些其他语 言中,也被成为函数function)
修饰符 方法返回值类型 方法名(参数1类型 参数1名称,参数2类型 参数2名称, ……) {
方法体语句;
return 返回值;
}
方法定义的格式说明:
修饰符:现在先认为是固定的 public static
返回值类型:方法体中的代码执行结果的数据类型
方法名 :标识符 参数 :类比数学中函数的自变量 z = f(x, y)
方法体:实现具体功能的语句结合
return:跳转控制关键字 (并非必须)
返回值:方法执行的到的最终结果
注意
键盘录入一个数据n(1<=n<=9),输出对应的nn乘法表
public class Exercise {
public static void main(String[] args) {
//调用方法
// 2 x 2乘法表
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
printMulti(n);
}
//定义一个方法来完成输出n x n乘法表
public static void printMulti(int n) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "x" + i + "=" + j * i + " ");
}
System.out.println();
}
}
}
在同一个类中,允许存在一个以上的同名方法
a.只要它们的参数个数
b.参数类型不同
c.参数顺序不同: 不是指形式参数的变量名顺序不同,而是指形式参数类型顺序
编译器如何区分方法呢? 通过方法签名
方法签名:方法名 + 参数列表 比如 add(int, int)
add(double, dobule)
示例:
public class OverLoadDemo {
public static void main(String[] args) {
System.out.println(add(3, 5));// 8
System.out.println(add(3, 5, 10));// 18
System.out.println(add(3.0, 5));// 8.0
System.out.println(add(3, 5.0));// 8.0
// 我们已经见过的方法的重载
System.out.println();// 0个参数
System.out.println(1);// 参数是1个int
System.out.println(3.0);// 参数是1个double
}
/** 求和的方法 */
public static int add(int n1, int n2) {
int sum = n1 + n2;
return sum;
}
// 方法名相同,参数个数不同,构成重载
public static int add(int n1, int n2, int n3) {
int sum = n1 + n2 + n3;
return sum;
}
// 方法名相同,参数类型不同,构成重载
public static double add(double n1, int n2) {
double sum = n1 + n2;
return sum;
}
// 方法名相同,参数顺序不同,构成重载
public static double add(int n1, double n2) {
double sum = n1 + n2;
return sum;
}
//编译错误:只有返回值不同,不构成方法的重载
public static double add(int n1, int n2) {
double sum = n1 + n2;
return sum;
}
//编译错误:只有参数名称不同,不构成方法的重载
public static int add(int n2, int n1) {
double sum = n1 + n2;
return sum;
}
}
数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的三个基本特点:
长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
其元素必须是相同类型,不允许出现混合类型。
数组类型可以是任何数据类型,包括基本类型和引用类型。
数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中存储的。
数组的声明方式有两种(以一维数组为例)
type[] arr_name; //(推荐使用这种方式)
type arr_name[];
注意事项
声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这时才与长度有关。
声明一个数组的时候并没有数组真正被创建。
构造一个数组,必须指定长度。
数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。
1. 静态初始化
除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值。
int[] a = { 1, 2, 3 };// 静态初始化基本类型数组;
Man[] mans = { new Man(1, 1), new Man(2, 2) };// 静态初始化引用类型数组;
2.动态初始化
数组定义与为数组元素分配空间并赋值的操作分开进行。
int[] a1 = new int[2];//动态初始化数组,先分配空间;
a1[0]=1;//给数组元素赋值;
a1[1]=2;//给数组元素赋值;
3.数组的默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
int a2[] = new int[2]; // 默认值:0,0
boolean[] b = new boolean[2]; // 默认值:false,false
String[] s = new String[2]; // 默认值:null, null
数组遍历(依次输出数组中的每一个元素)
public class Demo {
public static void main(String[] args) {
int[] arr = {1, 23, 4, 5, 6};
traverse(arr);
}
//数组遍历(依次输出数组中的每一个元素)
public static void traverse(int[] arr) {
for (int i : arr) {
System.out.print(i + "\t");
}
System.out.println();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aCrzVCYC-1586313350091)(C:\Users\魏铭志\AppData\Roaming\Typora\typora-user-images\image-20200306175113055.png)]
数组元素逆序
//数组元素逆序
public static void reverseOrder(int[] arr) {
int length = arr.length;
int[] arr2 = new int[length];
for (int i : arr) {
arr2[--length] = i;
}
for (int i = 0; i < arr.length; i++) {
arr[i] = arr2[i];
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PeJ93qCz-1586313350093)(C:\Users\魏铭志\AppData\Roaming\Typora\typora-user-images\image-20200306175508925.png)]
对取值范围在1~100的数据集合排序
//对取值范围在1~100的数据集合排序
public static void countSort(int[] arr) {
int[] arr2 = new int[101];
for (int i : arr) {
arr2[i]++;
}
int count = 0;
for (int i = 0; i < arr2.length; i++) {
for (int j = 0; j < arr2[i]; j++) {
arr[count++] = i;
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3g4OAbry-1586313350095)(C:\Users\魏铭志\AppData\Roaming\Typora\typora-user-images\image-20200306175636225.png)]
数组获取最值(获取数组中的最大值最小值)
//这里以最大值为例
//数组获取最值(获取数组中的最大值或最小值)
public static int findMax(int[] arr) {
//存取数组中的最大值
int max = arr[0];
for (int i : arr) {
if (i > max) {
max = i;
}
}
return max;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tCUaTyjM-1586313350097)(C:\Users\魏铭志\AppData\Roaming\Typora\typora-user-images\image-20200306175720505.png)]
数组查表法(根据键盘录入索引,查找对应星期)
/**
* 数组查表法(根据键盘录入索引,查找对应星期)
*
* @param index 1 代表星期一...7 代表星期日
* @return
*/
public static String findDayWeek(int index) {
String[] daysOfWeeek = {"星期一", "星期二", "星期三",
"星期四", "星期五", "星期六", "星期日"};
return daysOfWeeek[index - 1];
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6yhSLcbN-1586313350098)(C:\Users\魏铭志\AppData\Roaming\Typora\typora-user-images\image-20200307195857106.png)]
数组元素查找(查找指定元素第一次在数组中出现的索引)
//数组元素查找(查找指定元素第一次在数组中出现的索引)
public static int findLocation(int[] arr, int value) {
int index = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
return i;
}
}
return index;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8g3rGwiR-1586313350100)(C:\Users\魏铭志\AppData\Roaming\Typora\typora-user-images\image-20200306175904724.png)]
多维数组可以看成以数组为元素的数组。可以有二维、三维、甚至更多维数组,但是实际开发中用的非常少。
二维数组的声明
public class Test {
public static void main(String[] args) {
// Java中多维数组的声明和初始化应按从低维到高维的顺序进行
int[][] a = new int[3][];
a[0] = new int[2];
a[1] = new int[4];
a[2] = new int[3];
// int a1[][]=new int[][4];//非法
}
}
二维数组的静态初始化
public class Test {
public static void main(String[] args) {
int[][] a = { { 1, 2, 3 }, { 3, 4 }, { 3, 5, 6, 7 } };
System.out.println(a[2][3]);
}
}
二维数组的动态初始化
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[][] a = new int[3][];
// a[0] = {1,2,5}; //错误,没有声明类型就初始化
a[0] = new int[] { 1, 2 };
a[1] = new int[] { 2, 2 };
a[2] = new int[] { 2, 2, 3, 4 };
System.out.println(a[2][3]);
System.out.println(Arrays.toString(a[0]));
System.out.println(Arrays.toString(a[1]));
System.out.println(Arrays.toString(a[2]));
}
}
方法定义中调用方法本身的现象
递归方法的注意事项:
递归结构包括两个部分:
定义递归头。解答:什么时候不调用自身方法。如果没有头,将陷入死循环,也就是递归的结束条件。
递归体。解答:什么时候需要调用自身方法。
对于一个复杂的大规模的问题(无法直接求解的问题),可以将其转化为若干小规模的相似的子问题,只要能解决,小规模的子问题,把这些子问题的解组合起来,就形成了大规模问题的解。
- 有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
a. 每次只能移动一个圆盘;
b. 大盘不能叠在小盘上面。
提示:可将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。
问:最少要移动多少次?如何移?
public class Demo2 {
public static void main(String[] args) {
//测试一下我们的hanoi方法
hanoi(4, 'A', 'C', 'B');
System.out.println(count(4));
}
/*
n表示待移动的盘片数量
方法的返回值表示,n个盘片移动的总次数
*/
public static int count(int n) {
if (n == 1) {
return 1;
}
return 2 * count(n - 1) + 1;
}
/**
*
* @param n 待搬运的圆盘的数量(表征汉诺塔问题的规模)
* @param start 待搬运的这n个盘所在的杆的名称
* @param end 这待搬运的n个盘,要搬运到的目标杆的名称
* @param middle 在搬运这n个盘的时候,所用来辅助搬运这n个盘的杆的名称
*/
public static void hanoi(int n, char start, char end, char middle) {
//递归的出口条件,
if (n == 1) {
//当待搬运的盘片数量,足够小,直接就知道该如何搬运, 此时直接搬运完成即可,不用递归
System.out.println(start + " -> " + end);
return;
}
//第一步,首先将start杆上,最大的那个盘,之上的n-1个盘,搬运到midle杆上
hanoi(n - 1, start, middle, end); // 把n-1个盘片从start->middle
//第二步,把start杆上的最大的那个盘,一步完成,搬运到目标杆上去
System.out.println(start + " -> " + end); // 移动了一次
//第三步,将middle杆上的剩余的n-1个盘片,以start杆为辅助,搬运到end杆上
hanoi(n - 1, middle, end, start); // 把 n-1个盘片从middle -> end
}
}
- 求n的阶乘
public class Demo4 {
public static void main(String[] args) {
//递归求解阶乘
System.out.println(f(5));
//循环求解阶乘
System.out.println(calculateByFor(5));
}
/**
* 返回值就表示n的阶乘的结果
* @param n 阶乘的阶数
*/
public static int f(int n) {
//递归出口
if (n == 1) {
// 1的阶乘直接返回结果
return 1;
}
int result = n * f(n - 1);
return result;
}
/*
用循环来求解阶乘
n同样表示阶乘的阶数
*/
public static int calculateByFor(int n) {
int result = 1;
for (int i = n; i >= 1; i--) {
result = result * i;
}
return result;
}
}
- 有一对兔子,从出生后第三个月开始每月生一对兔子,小兔子从第三个月开始每月也生一对兔子,假如是不死神兔,那么第20个月一共生多少对兔子?
public class Demo5 {
public static void main(String[] args) {
System.out.println(count(20));
System.out.println(fibnacci(20));
System.out.println(fibnacci2(20));
}
/**
*
* 方法返回值,求解的就是 第n个月的兔子的总数
* @param n 表示的就是第n个月份
*/
public static int count(int n) {
//递归出口
if (n == 1 || n == 2) {
return 1;
}
return count(n - 1) + count(n - 2);
}
/*
可以用循环的方式,来求解斐波那契额数列
*/
public static int fibnacci(int n) {
// 该数组中存了前n个斐波那契额数列的值
int[] tmp = new int[n];
//斐波那契额数列的前两个值为1
tmp[0] = 1;
tmp[1] = 1;
//用循环求解
for (int i = 2; i < n; i++) {
tmp[i] = tmp[i - 1] + tmp[ i - 2];
}
return tmp[n - 1];
}
/*
可以用循环的方式,来求解斐波那契额数列
*/
public static int fibnacci2(int n) {
//斐波那契额数列的前两个值为1
int preOne = 1;
int preTwo = 1;
//最终斐波那契额第n个位置的值
int result = -1;
//用循环求解
for (int i = 2; i < n; i++) {
result = preOne + preTwo;
//preOne和preTwo的值变成了,下一个位置的斐波那契额数的前一个和前两个位置的值
preOne = preTwo;
preTwo = result;
}
return result;
}
}