本文章最初发布在 XJHui’s Blog,未经允许,任何人禁止转载!
注意:最新修改版本已发布在 这里,点击前往查看!
Java环境搭建
JDK、JRE、JVM
名词解释:
- JDK:Java Development Kit
- JRE:Java Runtime Environment
- JVM:Java Virtual Machine
关系图:
注意:
- jdk中包含了jre,所以我们开发时只安装jdk即可
- jvm是实现java一次编译到处运行的关键(屏蔽底层差异)
JDK卸载
在
此电脑(右键)\属性\高级系统设置\环境变量\系统变量
,找到JAVA_HOME:JAVA_HOME的值为
D:\environment\jdk8
,找到jdk8
这个文件夹将其删除 :删除系统变量JAVA_HOME:
双击打开
系统变量\Path
,删除两个带有JAVA_HOME的值:注意:删除后记得点击确定,使修改生效
快捷键
win+r
输入 cmd 进入命令行,输入:1
java -version
运行结果:
注意:如果未按上图,可以在
控制面板\程序\程序和功能
下找到 Java SE,双击删除后再次执行步骤2
JDK安装
打开链接,选择jdk下载:Java SE Development Kit 8 - Downloads (oracle.com)
注意:需要勾选许可协议,并登录oracle账号才允许下载
双击下载后的exe文件,修改安装路径:
注意:如果出现弹窗要求安装jre,关闭该窗口
右键
此电脑\属性\高级系统设置\环境变量\系统变量
,配置环境变量:新建系统变量JAVA_HOME:
给系统变量Path添加两个值:
1
2JAVA_HOME%\bin
JAVA_HOME%\jre
快捷键
win+r
输入 cmd 进入命令行,输入:1
java -version
运行结果:
Hello World
新建文件夹code,存放代码:
新建java文件:Hello.java
创建文件前先确保已显示文件拓展名
新建Hello.java文件,编辑内容:
1
2
3
4
5public class Hello{
public static void main(String[] args){
System.out.print("Hello world");
}
}注意代码规范:
- 所有符号均为英文符号,输出内容也尽量为英文
- class后的类名要与文件名一致,且首位必须大写
System.out.print("Hello world")
后要跟分号
打开命令行:
编译java文件:
1
javac Hello.java
编译结果:
运行java程序:
1
java Hello
运行结果:
Java运行机制
运行机制:编译型(C、C++等)、解释型(HTML、JavaScript等)
运行图:
Java基本语法
注释
作用:解释一行代码、一个函数、一个程序的作用,注释内容不会被编译
分类:单行注释、多行注释、文档注释
单行注释:
1
2
3// 单行注释
// 多个单行注释可以同时使用
// 一般用来解释单行代码的作用多行注释:
1
2
3
4
5/*
多行注释
注释内可以包含多行内容
一般用来解释单个方法的作用
*/文档注释:
1
2
3
4
5
6/**
* 文档注释
* 注释中的@author是会被识别的
* @author XJHui
* @date 2000.12.01
*/
标识符
包含:类名、方法名、变量名
标识符命名规则:
1
2
3
4
5
6
7
8
9
10
11
12
13/*
Java标识符(类名、方法名、变量名)命名规则:
1. 所有的标识符都只能以字母(A-Z或a-z),美元符($),下划线(_)开始
A、a、$、_
2. 首字母之后可以是字母(A-Z或a-z),美元符($),下划线(_),数字(0-9)的任何字符组合
Aa、a$、$1、_A
3. 不能使用关键字作为
关键字详见下图
4. 标识符大小写敏感
aa和Aa不相同
5. 可以使用中文命名但不推荐,也不推荐使用pinyin
你好、nihao
*/Java关键字:
数据类型
数据类型分类:
基本数据类型:整型(byte、short、int、long)、浮点型(float、double)、字符型(char)、布尔型(True、False)
注意:上图中-128~127表示该类型变量可表示的范围为[-128,127]
引用数据类型:除去基本类型都属于引用类型(字符串、数组等)
案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class Demo1 {
public static void main(String[] args) {
// 整型 byte short int long
byte num1 = 10; // 定义一个byte类型变量,变量的值为10
short num2 = 20;
int num3 = 30;
long num4 = 40L;
// 浮点型 float double
float num5 = 50.111F;
double num6 = 60.666;
// 字符型 char
char str1 = '你';
// 字符串 string(string不是关键字,是类)
String str2 = "你好";
// 布尔类型 true false
boolean flag1 = true; // 布尔类型的true和false都是小写
boolean flag2 = false;
}
}注意:
为了区分int和long,float和double,定义变量时long后加L(l),float后加F(f)
Java是强类型语言(变量的使用要严格符合规定),所有变量必须先定义再使用,且必须为其赋初值
byte范围是[-128,127],赋初值时不可以超过该范围,short、int、long、float、double同理
位、字节、字符:
- 位(bit):是计算机存储的最小单位,例如11001100是8位二进制数
- 字节(byte,B):是计算机处理数据的最小单位,1B (byte)= 8b(bit)
- 字符:是指计算机中使用的字母、数字、字、符号
类型转换
容量大小:
转换规则:
- 强制转换:低容量 <— 高容量
- 自动转换:低容量 —> 高容量
案例:
将int型变量转换为short类型
1
2
3
4
5
6
7
8
9
10
11public class demo2 {
/*
1. 不能对布尔值进行转换
2. 转换可能出现内存溢出、精度丢失等问题
*/
public static void main(String[] args) {
int a = 10;
short b = (short) a; // int类型容量大于short类型,需要强制转换
System.out.print(b); // 10
}
}将long类型变量转换为double类型
1
2
3
4
5
6
7public class demo2 {
public static void main(String[] args) {
long c = 10;
double d = c; // long类型容量小于double类型,自动转换
System.out.print(d); // 10.0
}
}
易错:
char与int相加:
1
2
3
4
5
6
7public class demo2 {
public static void main(String[] args) {
char a = 'a';
System.out.println(a + 1); // 98,两不同类型变量做运算,谁容量大结果为谁(int,类型)
System.out.println((char) (a + 1)); // b,int型变char型需要强制转换
}
}int和int相乘:
1
2
3
4
5
6
7
8public class demo2 {
public static void main(String[] args) {
int a = 10_0000_0000, b = 10_0000_0000;
System.out.println("【a * b】:" + a * b);
System.out.println("【(long) (a * b)】:" + (long) (a * b));
System.out.println("【a * ((long) b)】:" + a * ((long) b));
}
}运行结果:
变量
定义:可以变化的量;变量为什么可变?变量时存放在内存中的,而内存就像一个衣柜
语法:
1
数据类型 变量名 = 值;
注意:数据类型可以8中基本数据类型(整型、浮点型、字符型、布尔型)也可以是引用类型(数组、字符串等)
案例:创建变量PI,数据类型为double,值为3.1415926
1
2
3
4
5
6public class demo2 {
public static void main(String[] args) {
double PI = 3.1415926; // 数据类型 变量名 = 值;
System.out.println(PI); // 3.1415926
}
}变量分类:局部变量(方法外、类内);类变量(方法外、类内);实例变量(类内,方法外)
1
2
3
4
5
6
7
8
9
10
11
12
13public class demo2 {
// 类变量(类内,方法外),比实例对象多static,可直接引用
static double flag = 10;
// 实例变量(类内,方法外),要new对象才能引用
String name = "Jerry";
public static void main(String[] args) {
// 局部变量(方法内)
int i = 10;
System.out.println(i); // 10
}
}
常量
定义:定义后其值不会改变
案例:创建常量PI,其值为3.14
1
2
3
4
5
6
7
8public class demo2 {
// 定义常量PI
static final double PI = 3.14; // static、final都是修饰符无先后顺序
public static void main(String[] args) {
System.out.println(PI); // 3.14,添加了static修饰词,可以在方法内直接引用,去掉则不可
}
}
命名规则
- 常量:全大写字母,下划线(MAX_NUM)
- 局部变量、类变量、实例变量、方法名:首字母小写,驼峰命名法(sumSalary)
- 类名:首字母大写,驼峰命名法(TestDemo)
运算符
定义:运算符是一种特殊符号,用以表示数据的运算、赋值和比较。
分类:
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 位运算符(熟悉)
- 三元运算符
算术运算符
+(正)、-(负)、 +、 -、*、/、%(取余)、++(前、后自增)、–(前、后自减)、+(字符串拼接)
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74package day03;
public class AriTest {
public static void main(String[] args) {
/*
除法运算 /
*/
int num1 = 12;
int num2 = 5;
int result1 = num1 / num2;
System.out.println(result1); // 2,两int变量相除结果仍为int
double result3 = num1 / num2; // 2.0,相除结果为2强转为double
double result4 = (double) (num1 / num2); //2.0
double result5 = (num1 * 1.0) / num2; //2.4,double除int,结果为double
double result6 = ((double) num1) / num2; //2.4
/*
取余(模)运算 %
结果的符号与被模数符号一致
*/
int m1 = 12;
int n1 = 5;
System.out.println("m1 % n1: " + m1 % n1); // 2
int m2 = -12;
int n2 = 5;
System.out.println("m2 % n2: " + m2 % n2); // -2
int m3 = 12;
int n3 = -5;
System.out.println("m3 % n3: " + m3 % n3); // 2
int m4 = -12;
int n4 = -5;
System.out.println("m4 % n4: " + m4 % n4); // -2
/*
(前)++ 先自增1,再运算
(后)++ 先运算,再自增1
1. 自增1不会改变变量数据类型
2. 常量不能自加(1++)
*/
int a1 = 10;
int b1 = ++a1;
System.out.println("a1: " + a1 + " b1: " + b1); // 11 11
int a2 = 10;
int b2 = a2++;
System.out.println("a2: " + a2 + " b2: " + b2); // 11 10
int a3 = 10;
a3++; // ++a3
System.out.println("a3: " + a3); // 11
// 注意:
short s1 = 10;
// s1=s1+1; //编译失败,s1=(short)(s1+1) //正确编译
s1++; // 自增1不会改变变量本身数据类型
// 练习
int a4 = 10;
int b4 = a4--;
System.out.println(b4); // 10
/*
字符串拼接 +
拼接字符串,至少要保证一边为字符串类型
*/
int sNum = 10;
System.out.println("sNum: " + sNum); // 10,字符串+int,做拼接
System.out.println(10 + sNum); // 20,int+int,不做拼接
}
}案例练习:
随意给出一个三位数整数,打印显示它的个位数、十位数、百位数的值。
例如:数字153的情况如下: 个位数:3 十位数:5 百位数:1
1
2
3
4
5
6
7
8
9
10
11
12
13
14package day03;
public class AriExer {
public static void main(String[] args) {
int num = 123;
System.out.println("数字" + num + "的情况如下:");
int fNum = num / 100;
int sNum = (num / 10) % 10;
int tNum = num % 10;
System.out.println("个位数:" + tNum); // 3
System.out.println("十位数:" + sNum); // 2
System.out.println("百位数:" + fNum); // 1
}
}
赋值运算符
=、+=、-=、*=、/=、%=
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package day03;
public class SetValue {
public static void main(String[] args) {
/*
赋值符号 =
*/
int i1 = 10;
int j1 = 10; // 方式一(推荐)
int i2 = 10, j2 = 10; // 方式二
int i3, j3;
i3 = j3 = 10; // 方式三
// 赋值符号拓展: +=
int num1 = 10;
int num2 = 3;
num1 += num2; // 作用同 num1 = num1 + num2;
// 区别:s1 += s2; s1 = s1 + s2;
short s1 = 10;
// s1 = s1 + 2; // 编译失败
s1 += 2; // 不会改变变量本身的数据类型
}
}习题练习:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//练习1:实现变量+1,有几种方法?
int num = 1;
num += 1; // 方式一
num = num + 1; // 方式二
num++; // 方式三(推荐)
//练习2:
int i = 1;
i *= 0.1; // 0 = (int)0.1;
i++;
System.out.println(i); // 1
// 练习3:
int m = 2;
int n = 3;
n *= m++; // n=n*(m++)
System.out.println(m + " " + n); // 3 6
比较运算符
==、!=、<、>、<=、>=
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package day03;
public class CompareTest {
public static void main(String[] args) {
/*
比较运算符
1. 比较运算符结果为布尔类型
2. 区分==和=:==表示判断是否相等,=表示赋值
*/
int i = 10;
int j = 20;
System.out.println(i == j); // false,比较运算符(判断是否相等)
System.out.println(i = j); // 20,赋值
}
}
逻辑运算符:
&(与)、&&(短路与)、|(或)、||(短路或)、!(非)、^(异或)
注意:逻辑运算符操作的都是布尔类型的变量
逻辑运算图:
注意:
- &、&&:两边均为true,结果为true;
- |、||:任一边为true,结果就为true;
- !:true变false;false变true;
- ^:两边相异时结果为true,反之为false;
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package day03;
public class logicTest {
public static void main(String[] args) {
/*
区分&和&&,同理可推|和||
1. 相同点:&和&&的运算结果相同;当左边为true时都会执行右边的语句
2. 不同点:当左边为false时,&继续执行右边的语句,&&不在继续执行右边的语句
*/
boolean b1 = false;
int num1 = 10;
if (b1 & (num1++ > 0)) {
System.out.println("我在北京");
} else {
System.out.println("我在南京");
}
System.out.println(num1); // 11
boolean b2 = false;
int num2 = 10;
if (b2 && (num2++ > 0)) {
System.out.println("我在北京");
} else {
System.out.println("我在南京");
}
System.out.println(num2); // 10
}
}习题练习:
写出每题的输出结果
答案:
位运算符
<<(左移)、>>(右移)、>>>(无符号右移)、&、|、! 、^ 、~(取反)
注意:位运算符操作的都是整型的数据
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package day03;
public class BitTest {
public static void main(String[] args) {
/*
<<、>>
<<:在一定范围内,向左移动一位,相当于*2
>>:在一定范围内,向右移动一位,相当于/2
原理见下图
*/
int i = 21;
System.out.println("i<<2 " + (i << 2)); // 84
System.out.println("i<<3 " + (i << 3)); // 168
System.out.println("i>>2 " + (i >> 2)); // 5
System.out.println("i>>3 " + (i >> 3)); // 2
// &、|、^
int m = 12;
int n = 5;
System.out.println("m&n " + (m & n)); // 4
System.out.println("m|n " + (m | n)); // 13
System.out.println("m^n " + (m ^ n)); // 9
}
}图解位运算<<、>>原理:
图解位运算&、|、^:
习题练习:
交换两变量的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package day03;
public class BitExer {
public static void main(String[] args) {
/*
交换两变量的值
*/
int a = 10;
int b = 5;
int swap = a; // 方法一:借助第三个变量
a = b;
b = swap;
System.out.println(a + " " + b); // 5 10
a = a + b; // 方法二:a跳到b头上
b = a - b;
a = a - b;
System.out.println(a + " " + b); // 10 5
a = a ^ b; // 方法三:异或特性
b = a ^ b;
a = a ^ b;
System.out.println(a + " " + b); // 5 10
}
}
三元运算符
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35package day03;
public class ThreeTest {
public static void main(String[] args) {
/*
三元运算符
1. 语法:
(条件表达式)? 表达式一 : 表达式二;
2. 使用:
条件表达式为true时执行表达式一,否则执行表达式二
3. 注意:
① 三元运算符可以嵌套使用
② 任何三元运算符都可以改写成if-else语句,反之不成立
*/
int m = 12;
int n = 5;
int max = (m > n) ? m : n;
System.out.println(max); // 12
// 嵌套使用(不建议,代码可读性差)
String result = (m > n) ? "m大" : ((m == n) ? "m和n相等" : "n大");
System.out.println(result); // m大
// 改写为if-else语句
if (m > n) {
System.out.println("m大");
} else {
if (m == n) {
System.out.println("m和n相等");
} else {
System.out.println("n大");
}
}
}
}习题练习:
获取三个数中的最大值
1
2
3
4
5
6
7
8
9
10
11package day03;
public class ThreeExer {
public static void main(String[] args) {
int n = 10;
int m = -10;
int q = 99;
int max = (((n > m) ? n : m) > q) ? ((n > m) ? n : m) : q;
System.out.println(max); // 9
}
}三元运算符和if-else的选择:程序在保证代码可读性的前提下,既可以使用三元运算符又可以使用if-else,优先使用三元运算符,原因:简洁、高效。
程序流程控制
分类:
- 顺序结构
- 分支结构(if-else、switch-case)
- 循环结构(while、do…while、for)
顺序结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package day03;
public class ShunXuTest {
public static void main(String[] args) {
/*
顺序结构,程序从上到下逐行的执行,中间没有任何判断和跳转。
注意:Java中定义成员变量时采用合法的向前引用
*/
int num1 = 12;
int num2 = num1 + 1;
System.out.println(num2);
//int num2 = num1+1; // 编译错误,num1要先定义才能使用
//int num1 = 12;
//System.out.println(num2);
}
}分支语句
if-else
三种结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24第一种:
if(条件表达式){
执行表达式
}
第二种:二选一
if(条件表达式){
执行表达式1
}else{
执行表达式2
}
第三种:n选一
if(条件表达式){
执行表达式1
}else if(条件表达式){
执行表达式2
}else if(条件表达式){
执行表达式3
}
...
else{
执行表达式n
}读取键盘内容(Scanner类):
键盘读取个人信息(name、age、sex)并输出,输出格式如下:
【name】,您的性别为:sex,您的年龄为:age岁!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package day04;
/*
读取键盘内容
1. 导包 import java.util.Scanner;
2. 实例化对象 Scanner scan = new Scanner(System.in);
3. 调用Scanner类的方法(next/nextXxx),获取指定类型的变量
Scanner方法
1. 字符串: next()
2. 整型: nextByte,nextShort(),nextInt(),nextLong()
3. 浮点型: nextFloat,nextDouble()
*/
import java.util.Scanner; // 导包
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in); // 实例化对象
System.out.println("请输入姓名:");
String name = scan.next(); // 调用方法获取指定类型的变量
System.out.println("请输入年龄:");
int age = scan.nextInt();
// 获取字符型
System.out.println("请输入您的性别(男/女):");
char sex = scan.next().charAt(0); // 先当做字符串获取,再使用字符串的charAt方法获取某位置的字符,下标从0开始
System.out.println("【" + name + "】,您的性别为:" + sex + ",您的年龄为:" + age + "岁!");
}
}运行结果:
生成随机数(Math.random()):
1
2
3
4
5
6
7
8
9
10
11
12
13
14/*
生成随机数 Math.random()
1. 不需要导包
2. Math.random()生成的随机数范围为[0.0,1.0)
3. 生成[a,b]的随机数,公式:
(int) (Math.random() * (b - a + 1) + a);
*/
public class RandomTest {
public static void main(String[] args) {
// 案例:生成[10,99]的随机数
int num = (int) (Math.random() * (90) + 10);
System.out.println("生成的随机数为:" + num); // 57
}
}if-else的就近原则:
1
2
3
4
5
6
7
8
9
10
11
12
13
14package day04;
public class IfExer2 {
public static void main(String[] args) {
int x = 4;
int y = 1;
if (x > 2)
if (y > 2)
System.out.println(x + y);
//System.out.println("hello");
else // else会匹配离它最近的if
System.out.println("x is " + x);
}
}
switch-case:
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40package day04;
/*
1. switch-case语法:
switch(表达式){
case 常量1:
执行语句1;
// break;
case 常量2:
执行语句2;
// break;
...
default:
执行语句n;
// break;
}
2.注意:
① 根据switch表达式的值,依次匹配各个case。一旦匹配成功,则进入case调用执行语句。
当语句执行完后,仍然继续向下执行每个case结构中的执行语句,直到遇到break或switch-case语句结束。
② switch结构中的表达式,只能是以下6种:
byte、short、int、char、字符串(JDK7.0新增)、枚举(JDK5.0新增)
③ case后只能是常量不能是一个范围
④ break、default都是可选的,default相当于if-else中的else,且位置不固定
*/
public class SwitchCaseTest {
public static void main(String[] args) {
// 案例:使用switch-case语句,匹配数字1~3
int num = 3;
switch (num) {
case 1:
System.out.println("one");
break;
case 2:
System.out.println("two");
break;
default:
System.out.println("three");
}
}
}案例练习1:
对学生成绩大于 60 分的,输出“合格”。低于 60 分的,输出“不合格”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package day04;
public class SwitchCaseExer {
public static void main(String[] args) {
int score=87;
// 方式一:巧用break
switch (score/10){
case 0:
case 1:
case 2:
case 3: // 如果匹配到3,会依次往下执行每个case,直到遇到break或程序结束
case 4:
case 5:
System.out.println("不及格!");
break;
case 6:
case 7:
case 8:
case 9:
case 10:
System.out.println("及格!");
}
// 方式二:switch-case处理范围问题时,未必需要列出所有case
switch (score/60){
case 0:
System.out.println("不及格!");
break;
default:
System.out.println("及格!");
}
}
}运行结果:
案例练习2:
从键盘上输入 2019 年 的“ month ”和 day ”,通过程序输出:输入的日期 为 2019 年 的 第几天
1
2package day04;
import java.util.Scanner;
public class SwitchCaseExer2 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入2019年个month:"); // 输入数据 int month = scan.nextInt(); System.out.println("请输入2019年个day:"); int sumDay = 0; int day = scan.nextInt(); switch (month) { case 12: sumDay += 30; case 11: sumDay += 31; case 10: sumDay += 30; case 9: sumDay += 31; case 8: sumDay += 31; case 7: sumDay += 30; case 6: sumDay += 31; case 5: sumDay += 30; case 4: sumDay += 31; case 3: sumDay += 28; case 2: sumDay += 31; default: sumDay += day; } System.out.println("输入的日期 为 2019 年 的 第" + sumDay + "天"); } }
1
2
3
4
5
6
运行结果:
<img src="https://cdn.jsdelivr.net/gh/xingjiahui/CDN@latest/2020/12/05/09e12c6088225891186585e8914e14de.png" width="80%"/>
- switch-case和if-else的选择:程序既可以使用switch-case又可以使用if-else,优先使用switch-case,原因:高效。
循环结构
分类:for循环、while循环、do…while()循环
循环语句的组成:
for循环:
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package day04;
/*
1.循环条件:
① 初始化部分
② 循环条件部分
③ 循环体部分
④ 迭代部分
2. for循环结构:
for(①;②;④){
③
}
3. 执行过程:①->②->③->④->②->③->④->...->②
*/
public class ForTest {
public static void main(String[] args) {
// 案例:输出100个"hello world"
for (int i = 0; i < 100; i++) {
System.out.println("hello world");
}
}
}习题练习1:
写出程序运行结果:
1
2
3
4int num = 1;
for (System.out.print('a'); num <= 3; System.out.print('c'), num++) {
System.out.print('b');
}答案:abcbcbc
习题练习2:
遍历100以内的偶数,输出所有偶数的和,输出偶数的个数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package day04;
public class ForExer {
public static void main(String[] args) {
int numSum = 0;
int cnt = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
numSum += i;
cnt++;
}
}
System.out.println("偶数和:" + numSum + " 偶数数目:" + cnt); // 偶数和:2550 偶数数目:50
}
}习题练习3:
输入两个正整数 m 和 n ,求其最大公约数和最小公倍数 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32package day05;
import java.util.Scanner;
public class ForTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 键盘读入数据m、n
System.out.print("请输入m:");
int m = scan.nextInt();
System.out.print("请输入n:");
int n = scan.nextInt();
// 计算最大公约数
int min = (m < n) ? m : n;
for (int i = min; i >= 1; i--) {
if (m % i == 0 && n % i == 0) {
System.out.println("最大公约数为:" + i);
break; // 结束循环
}
}
// 计算最小公倍数
int max = (m > n) ? m : n;
for (int i = max; i <= m * n; i++) {
if (i % m == 0 && i % n == 0) {
System.out.println("最小公倍数为:" + i);
break;
}
}
}
}运行结果:
while循环
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34package day05;
/*
1. 循环结构的4个要素
① 初始化条件
② 循环条件 --->是boolean类型
③ 循环体
④ 迭代条件
2. while循环的结构
①
while(②){
③;
④;
}
执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ... - ②
3. 注意:
①写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!
②for循环和while循环是可以相互转换的!
区别:for循环和while循环的初始化条件部分的作用范围不同。
*/
public class WhileTest {
public static void main(String[] args) {
// 遍历10以内所有偶数
int num = 1;
while (num <= 10) {
if (num % 2 == 0) {
System.out.print(num + " "); // 2 4 6 8 10
}
num++;
}
}
}
do-while循环:
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package day05;
/*
一、循环结构的4个要素
① 初始化条件
② 循环条件 --->是boolean类型
③ 循环体
④ 迭代条件
二、do-while循环结构:
①
do{
③;
④;
}while(②);
执行过程:① - ③ - ④ - ② - ③ - ④ - ... - ②
三、注意:
1. do-while循环至少会执行一次循环体!
*/
public class DoWhileTest {
public static void main(String[] args) {
// 遍历10以内的偶数
int num = 1;
do {
if (num % 2 == 0) {
System.out.print(num + " "); // 2 4 6 8 10
}
num++;
} while (num <= 10);
}
}案例练习:
从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为 0 时结束 程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package day05;
import java.util.Scanner;
public class WhileExer {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int cnt1 = 0; // 正数数目
int cnt2 = 0; // 负数数目
while (true) { // 构造循环实现多次输入
System.out.print("请输入一个整数:");
int num = scan.nextInt();
if (num == 0) {
break;
}
if (num > 0) {
cnt1++;
} else if (num < 0) {
cnt2++;
}
}
System.out.println("正数数目:" + cnt1 + " 负数数目:" + cnt2);
}
}运行结果:
嵌套循环
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55package day05;
import javax.swing.*;
/*
嵌套循环的使用
1.嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环
2.
外层循环:循环结构B
内层循环:循环结构A
3. 说明
① 内层循环结构遍历一遍,只相当于外层循环循环体执行了一次
② 假设外层循环需要执行m次,内层循环需要执行n次。此时内层循环的循环体一共执行了m * n次
4. 技巧:
外层循环控制行数,内层循环控制列数
*/
public class ForForTest {
public static void main(String[] args) {
// ******
for (int i = 1; i <= 6; i++) {
System.out.print("*");
}
System.out.println("\n");
/*
******
******
******
******
*/
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 6; j++) {
System.out.print("*");
}
System.out.println();
}
System.out.println("\n");
/* i(行号) j(*数目)
* 1 1
** 2 2
*** 3 3
**** 4 4
*/
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
System.out.println();
}
}
}案例练习:
输出 20 以内所有素数(质数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package day05;
public class ForForExer {
public static void main(String[] args) {
for (int i = 2; i <= 20; i++) {
boolean isFlag = true;
for (int j = 2; j <= Math.sqrt(i); j++) { // 优化二:c=a*b,a和b肯定分布在根号c两边,只判断a即可
if (i % j == 0) {
isFlag = false;
break; // 优化一:只要能整除,就停止判断
}
}
if (isFlag == true) {
System.out.print(i + " "); // 2 3 5 7 11 13 17 19
}
}
}
}
特殊关键字:
breake、continue:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32package day05;
/*
break和continue关键字的使用
使用范围 循环中使用的作用(不同点) 相同点
break: switch-case
循环结构中 结束当前循环 关键字后面不能声明执行语句
continue: 循环结构中 结束当次循环 关键字后面不能声明执行语句
*/
public class BreakContinueTest {
public static void main(String[] args) {
/* *************** break ******************** */
for (int i = 1; i < 10; i++) {
if (i % 4 == 0) {
break; // 结束循环
// System.out.println("太阳从西边出来!"); // 编译错误,break,continue后面都不可以跟语句
}
System.out.print(i); // 123
}
System.out.println();
/* *************** continue ******************** */
for (int i = 0; i < 10; i++) {
if (i % 4 == 0) {
continue; // 结束此次循环
// System.out.println("太阳从西边出来!"); // 编译错误,break,continue后面都不可以跟语句
}
System.out.print(i); // 1235679
}
System.out.println();
}
}带标签的break:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class BreakContinueTest {
public static void main(String[] args) {
flag:
// 给for循环添加标签
for (int i = 1; i < 10; i++) {
for (int j = 1; j < 10; j++) {
if (j % 4 == 0) {
break flag; // 添加标签后,可停止指定循环
//break; // 默认情况下,break是停止此循环
}
System.out.print(j); // 123
}
}
}
}
数组
数组的概述
数组(Array):是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
数组的相关概念:
- 数组名
- 元素
- 索引(下标、角标)
- 数组的长度(元素个数)
数组分类:
- 按照维数:一维数组、二维数组 …
- 按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
数组的特点:
- 数组是有序排列的
- 数组属于引用数据类型的变量;数组的元素既可以是基本数据类型,也可以是引用数据类型;
- 创建数组对象会在内存(堆)中开辟一整块连续的空间
- 数组的长度一旦确定,就不能修改
一维数组
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41package cn.plushine.test;
public class ArrayTest {
public static void main(String[] args) {
// 1.一维数组的声明和初始化
// 注意:数组一旦初始化完成,其长度就确定了
int[] ids; // 声明
ids = new int[] { 2, 1, 3, 0 }; // 写法1,静态初始化:赋值和初始化同时进行
String[] names = new String[3]; // 写法2,动态初始化:赋值和初始化分开进行
names[0] = "小明"; // 赋值
names[1] = "小红";
names[2] = "小军";
int[] arr4 = { 1, 2, 3, 4 }; // 写法3,类型推断
// 2.如何调用数组的指定位置的元素:通过索引的方式调用
// 注意:数组的角标(或索引)从0开始的,到数组的长度-1结束
System.out.println(ids[3]); // 0
System.out.println(names[0]); // "小明"
// 3.如何获取数组的长度
System.out.println(ids.length); // 4
System.out.println(names.length); // 3
// 4.如何遍历数组
for (int i = 0; i < ids.length; i++) {
System.out.print(ids[i]); // 2130
}
/*
* 5.数组元素的默认初始化值
* 数组元素是整型:0
* 数组元素是浮点型:0.0
* 数组元素是char型:0或'\u0000'(类似空格),而非'0'
* 数组元素是boolean型:false
* 数组元素是引用数据类型:null
*/
}
}内存解析:
代码运行后,栈、堆的变化过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package cn.plushine.test;
public class ArrayTest {
public static void main(String[] args) {
int[] arr1 = new int[4]; // 堆中开辟空间存放int型变量,长度为4,初值为0,首地址为0x12ab,栈中的arr1指向该地址
arr1[0] = 10; // 将首地址为0x12ab的第1个值改为10
arr1[2] = 20; // 将首地址为0x12ab的第3个值改为20
String[] arr2 = new String[3]; // 堆中开辟空间存放字符串,长度3,初值null,首地址为0x34ab,栈中的arr2指向该地址
arr2[1] = "刘杰"; // 将首地址为0x34ab的第2个值改为“刘杰”
arr2 = new String[5]; // 堆中开辟空间存放字符串(注),长度为5,初值为null,首地址为0x78cd,栈中的arr2指向该地址
}
}
// 简单的垃圾回收机制
// 当main方法执行结束以后,arr2、arr1相继出栈,出栈后arr1与0x12ab的指针会断开连接,堆中判断到没有指针指向0x12ab后会将数组回收,其余数组同理注:字符串并不是存储在堆中,上图为了方便演示,才写成“堆中开辟空间存放字符串”。
案例练习:
升景坊单间短期出租 4 个月 550 元 月(水电煤公摊,网费 35 元 月),空调、卫生间、厨房齐全。
屋内均是 IT 行业人士,喜欢安静。所以要求来租者最好是同行或者刚毕业的年轻人,爱干净、安静。1
2
3
4
5
6
7
8
9
10public class ArrayTest {
public static void main(String[] args) {
int[] arr = new int[] { 8, 2, 1, 0, 3 };
int[] index = new int[] { 2, 0, 3, 2, 4, 0, 1, 3, 2, 3, 3 };
String tel = "";
for (int i = 0; i < index.length; i++) {
tel += arr[index[i]];
}
System.out.println(" 联系方式:" + tel);
}答案:18013820100
多维数组
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38package cn.plushine.test;
/*
* 二维数组的理解:可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。
*/
public class ArrayTest2 {
public static void main(String[] args) {
// 1.二维数组的声明和初始化
// 静态初始化
int[][] arr1 = new int[][] { { 1, 2, 3 }, { 4, 5 }, { 6, 7, 8 } };
// 动态初始化1
String[][] arr2 = new String[2][3];
// 动态初始化2
String[][] arr3 = new String[3][];
arr3[0] = new String[] { "1", "2" }; // 赋值
// 其它正确写法
int[] arr4[] = { { 1, 2, 3 }, { 4, 5 } };
int arr5[][] = { { 1, 2, 3 }, { 4, 5 } };
// 2.如何调用数组的指定位置的元素
System.out.println(arr1[0][1]);// 2
System.out.println(arr2[1][1]);// null
// 3.获取数组的长度
System.out.println(arr4.length);// 3,行数
System.out.println(arr4[0].length);// 3,列数
// 4.如何遍历二维数组
for (int i = 0; i < arr4.length; i++) {
for (int j = 0; j < arr4[i].length; j++) {
System.out.print(arr4[i][j] + " ");
}
System.out.println();
}
}
}默认初始化值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package cn.plushine.test;
/*
* 1.二维数组的外层元素和内层元素定义:
* 例:int[][] arr = new int[4][3];
* 外层元素:arr[0],arr[1]等
* 内层元素:arr[0][0],arr[1][2]等
*
* 2.数组元素的默认初始化值
* 初始化方式一:int[][] arr = new int[4][3];
* 外层元素的初始化值为:地址值
* 内层元素的初始化值为:与一维数组初始化情况相同,整型:0,浮点型:0.0,字符型:'\u0000',布尔型:false等
*
* 初始化方式二:int[][] arr = new int[4][];
* 外层元素的初始化值为:null
* 内层元素的初始化值为:不能调用,否则报错。
*/
public class ArrayTest3 {
public static void main(String[] args) {
// 初始化方式一:
int[][] arr = new int[4][3];
System.out.println(arr[0]); // [I@15db9742,[:一维数组,I:int型,15db9742:首地址
System.out.println(arr[0][0]); // 0,一维数组中int型初始化为0
// 初始化方式二:
double[][] arr3 = new double[4][];
System.out.println(arr3[1]);// null,引用数据类型初始化为null,数组也是引用数据类型
// System.out.println(arr3[1][0]);//报错
}
}内存解析:
代码运行后,栈、堆的变化过程:
1
2
3
4
5
6int[][] arr4 = new int[3][]; // 栈中开辟空间存放int型一维数组,长度为3,初始化为null,首地址为0x5566,arr4指向该地址
System.out.println(arr4[0]); // 一维数组为引用数据类型,初始化值为null
// System.out.println(arr4[0][0]); // 报错
arr4[0] = new int[3]; // 栈中开辟空间存放int型变量,长度为3,初始化为0,首地址为0x8899,arr4[0]指向该地址
arr4[0][1] = 5; // 修改栈中首地址为0x8899的第2个变量的值为5
arr4[1] = new int[] { 1, 2 }; // 栈中开辟空间存放int型变量,长度为2,首地址为0x8899,arr4[1]指向该地址案例练习:
【题目】
使用二维数组打印一个10 行杨辉三角
【提示】
第一行有 1 个元素, 第 n 行有 n 个元素
每一行的第一个元素和最后一个元素都是 1
从第三行开始, 对于非第一个元素和最后一个元素的元素。即:yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
程序代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package cn.plushine.exer;
public class YangHuiTest {
public static void main(String[] args) {
int[][] arrayList = new int[10][]; // 由于不确定每行的元素个数,先动态初始化
for (int i = 0; i < 10; i++) {
arrayList[i] = new int[i + 1]; // 初始化每行元素数目
for (int j = 0; j <= i; j++) {
if (j == 0 || j == i) {
arrayList[i][j] = 1; // 两边值为1
} else {
arrayList[i][j] = arrayList[i - 1][j - 1] + arrayList[i - 1][j];
}
}
}
for (int i = 0; i < 10; i++) { // 输出
for (int j = 0; j <= i; j++) {
System.out.print(arrayList[i][j] + " ");
}
System.out.println();
}
}
}运行结果:
常见算法
分类:
- 数组元素的赋值(杨辉三角、回环数)
- 求数值型数组中的最大值、最小值、平均数、总和等
- 数组的复制、反转、查找(线性查找、二分查找)
- 数组元素的排序算法
数组的复制:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package cn.plushine.exer;
public class ArrayTest {
public static void main(String[] args) {
int[] arr1 = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
int[] arr2 = arr1; // arr2赋值为arr1
for (int i = 0; i < arr1.length; i++) { // 输出arr1的内容
System.out.print(arr2[i] + "\t");
}
System.out.println();
for (int i = 0; i < arr2.length; i++) { // 修改arr2中偶数位的值
if (i % 2 == 0) {
arr2[i] = i;
}
}
for (int i = 0; i < arr1.length; i++) { // 输出arr1
System.out.print(arr2[i] + "\t");
}
}
}运行结果:
内存分析:
总结:直接赋值不能实现数组复制,可以使用for循环遍历依次赋值。
二分查找:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package cn.plushine.exer;
public class ArrayTest1 {
public static void main(String[] args) {
int[] arr1 = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int aim = 1;
int l = 0; // 左边界
int r = arr1.length - 1; // 右边界
while (l <= r) {
int mid = (l + r) / 2; // 中间索引
if (arr1[mid] > aim) { // 当前值>目标值
r = mid - 1;
} else if (arr1[mid] < aim) { // 当前值<目标值
l = mid + 1;
} else if (arr1[mid] == aim) { // 当前值==目标值
System.out.println("位置:" + mid); // 1
System.exit(0); // 退出程序
}
}
System.out.println("未查询到该数!");
}
}注意:
- 左右边界可以重合(l <= r)
- 判断当前值(arr1[mid])和目标值(aim)的大小,修改l、r的值
排序算法(冒泡排序)
思路:
- 从头开始比较相邻两变量大小,每次循环结束都会将最大的一个数移动到最后
- 数组元素个数为n,就需要循环n-1次(选出n-1个最大的数)
动态图:
源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package cn.plushine.exer;
public class ArrayTest2 {
public static void main(String[] args) {
int[] arr1 = new int[] { 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 }; // 初始数组
for (int i = 0; i < arr1.length - 1; i++) {
for (int j = 0; j < arr1.length - i - 1; j++) {
if (arr1[j] > arr1[j + 1]) { // 交换变量
int swap = arr1[j];
arr1[j] = arr1[j + 1];
arr1[j + 1] = swap;
}
}
}
for (int i = 0; i < arr1.length; i++) { // 输出排序后数组
System.out.print(arr1[i] + " ");
}
}
}
Arrays工具类
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package cn.plushine.exer;
import java.util.Arrays;
public class ArrayTest3 {
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 isEqual = Arrays.equals(arr1, arr2);
System.out.println(isEqual); // false,返回布尔值
// 2.String toString(int[] a):输出数组信息。
System.out.println(Arrays.toString(arr1)); // [1, 2, 3, 4]
// 3.void sort(int[] a):对数组进行排序。
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2)); // [1, 2, 3, 4],顺序从小到大
// 4.进行二分查找
int[] arr3 = new int[] { -98, -34, 2, 34, 54, 66, 79, 105, 210, 333 };
int index = Arrays.binarySearch(arr3, -34);
System.out.println(index); // 1,返回索引值
}
}运行结果:
数组常见异常
数组索引越界的异常(ArrayIndexOutOfBoundsExcetion):
1
2
3
4
5
6
7
8package cn.plushine.exer;
public class ArrayExceptionTest {
public static void main(String[] args) {
int[] arr1 = new int[] { 1, 2, 3, 4 };
//System.out.println(arr1[4]); // 数组索引越界
}
}空指针异常(NullPointerException):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package cn.plushine.exer;
public class ArrayExceptionTest {
public static void main(String[] args) {
// 情况1:一维数组
int[] arr2 = new int[] { 1, 2, 3 };
arr2 = null;
System.out.println(arr2[0]);
// 情况2:二维数组
int[][] arr3 = new int[4][];
System.out.println(arr3[0][0]);
// 情况3:调用方法
int[][] arr4 = new int[4][];
System.out.println(arr4[0].toString());
}
}
面向对象(上)
面向过程和面向对象
区别:
- 面向过程(POP):强调的是功能行为,以函数为最小单位,考虑怎么做。
- 面向对象(OOP):将功能封装进对象,强调具备了功能的对象,以类、对象为最小单位,考虑谁来做。
学习代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package cn.plushine.java;
/*
* 一、“人把大象装进冰箱”
*
* 1.面向过程:
*
* ① 把冰箱门打开
* ② 把大象装进冰箱
* ② 把冰箱门关闭
*
* 2.面向对象:
*
* 人{
* 打开(冰箱){
* 冰箱.开门();
* }
* 抬起(大象){
* 大象.进入(冰箱);
* }
* 关闭(冰箱){
* 冰箱.关门();
* }
* }
*
* 冰箱{
* 开开(){}
* 闭合(){}
* }
*
* 大象{
* 进入(冰箱){}
* }
*
* 二、面向对象的两个要素:
* 类:对一类事物的描述,是抽象的、概念上的定义
* 对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
*
*/
public class OopTest {
}案例练习:
练习1:我要开车去丽江,这句话包含的类有什么?
答案:人、车
练习2:售货员统计收获小票的金额,这句话包含的类有什么?
答案:人、小票
类和对象
学习代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54package cn.plushine.java;
/*
* 1.类和对象的使用:
* ①创建类
* ②创建类对象
* ③调用对象的属性、方法
*
* 2.创建类:设计类的成员(属性、方法)
* 属性 = 成员变量 = field = 域、字段
* 方法 = 成员方法 = 函数 = method
*
* 3.创建类的对象 = 类的实例化 = 实例化类
*
* 4. 注意:创建类对象要在方法中
*
*/
public class PersonTest {
public static void main(String[] args) {
// ******************创建类对象p1*****************
Person p1 = new Person();
// 调用对象的属性:“对象.属性”
p1.name = "Tom";
p1.isMale = true;
System.out.println(p1.name); // "Tom"
// 调用对象的方法:“对象.方法”
p1.eat();
p1.talk("English");
// ******************创建类对象p2*****************
Person p2 = new Person();
System.out.println(p2.name); // 0或'\u0000',而不是"Tom",具体见下文分析
}
}
// 设计类(设计类成员):属性、方法
class Person {
// 属性
String name;
int age = 1;
boolean isMale;
// 方法
public void eat() {
System.out.println("人可以吃饭!");
}
public void talk(String language) {
System.out.println("人可以说话,用的语言是:" + language);
}
}内存分析:
p2.name != p1.name
属性(成员变量)
学习代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55package cn.plushine.java;
/*
* 属性(成员变量)VS 局部变量
*
* 1.相同点:
* 1.1 定义变量的格式:数据类型 变量名 = 变量值
* 1.2 先声明,后使用
* 1.3 变量都有其对应的作用域
*
* 2.不同点:
* 2.1 在类中声明的位置的不同
* 属性:直接定义在类的一对{}内
* 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
*
* 2.2 关于权限修饰符的不同
* 属性:可以在声明属性时,指明其权限,使用权限修饰符。
* 常用的权限修饰符:private、public、缺省、protected --->封装性
* 目前,大家声明属性时,都使用缺省就可以了。
* 局部变量:不可以使用权限修饰符。
*
* 2.3 默认初始化值的情况:
* 属性:类的属性,根据其类型,都有默认初始化值。
* 整型(byte、short、int、long):0
* 浮点型(float、double):0.0
* 字符型(char):0 (或'\u0000')
* 布尔型(boolean):false
* 引用数据类型(类、数组、接口):null
*
* 局部变量:没有默认初始化值。
* 意味着,我们在调用局部变量之前,一定要显式赋值。
*
* 2.4 在内存中加载的位置:
* 属性:加载到堆空间中 (非static)
* 局部变量:加载到栈空间
*
*/
public class UserTest {
public static void main(String[] args) {
User u1 = new User(); // 创建类对象
System.out.println(u1.name); // 调用类属性
u1.eat(); // 调用类方法
}
}
class User {
String name; // 属性(成员变量)
public void eat() {
String food = "烙饼"; // 局部变量
System.out.println("北方人喜欢吃:" + food);
}
}内存分析:
方法(成员方法)
学习代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70package cn.plushine.java;
/*
* 类中方法的声明和使用
*
* 方法:描述类应该具有的功能。
* 比如:Person类:eat()\...
* Math类:sqrt()\random() \...
* Scanner类:nextXxx() ...
* Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ...
*
* 1.方法举例:
* public void eat(){}
* public void sleep(int hour){}
* public String getName(){}
* public String getNation(String nation){}
*
* 2. 方法的声明:权限修饰符 返回值类型 方法名(形参列表){
* 方法体
* }
* 注意:static、final、abstract 来修饰的方法,后面再讲。
*
* 3. 说明:
* 3.1 关于权限修饰符:默认方法的权限修饰符先都使用public
* Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说
*
* 3.2 返回值类型: 有返回值 vs 没有返回值
* 如果方法有返回值,则必须在方法声明时指定返回值的类型,使用void表示无返回值。
* 方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
*
* 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
*
* 3.4 形参列表: 方法可以声明0个,1个,或多个形参。
* 格式:数据类型1 形参1,数据类型2 形参2,...
*
* 3.5 方法体:方法功能的体现。
*
* 4.return关键字的使用:
* 1.使用范围:使用在方法体中
* 2.作用:① 结束方法
* ② 针对有返回值类型的方法,使用"return 数据"来返回所要的数据。
* 3.注意点:return关键字后面不可以声明执行语句。
*
* 5. 方法的使用中,可以调用当前类的属性或方法
* 特殊的:方法A中又调用了方法A:递归方法。
* 方法中,不可以定义方法。
*/
public class CustomerTest {
public static void main(String[] args) {
Customer c1 = new Customer(); // 创建类对象
c1.name = "Tom"; // 调用类的属性
c1.status(); // 调用类的方法
}
}
// 设计类
class Customer {
String name;
int age;
public void status() {
eat(name); // 方法中调用属性、方法
}
public void eat(String name) {
System.out.println(name + "在吃饭!"); // Tom在吃饭!
}
}案例练习:
定义类 Student ,包含三个属性:学号 number(int),年级 state(int),成绩score(int)
创建 20 个学生对象,学号为 1 到 5 ,年级和成绩都由随机数确定
打印出 3 年级 (state 值为 3 )的学生信息
使用冒泡排序按学生成绩排序,并遍历所有学生信息
程序代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77package cn.plushine.exer;
public class Exer3Test {
public static void main(String[] args) {
Student[] s1 = new Student[5]; // 创建长度为5的Student类数组
for (int i = 0; i < s1.length; i++) { // 创建Student类对象并给属性赋值
s1[i] = new Student();
s1[i].number = i + 1; // 学号(i+1)
s1[i].state = (int) (Math.random() * (3 - 1 + 1) + 1); // 年级[1-3]
s1[i].score = (int) (Math.random() * (100 - 0 + 1) + 0); // 成绩[0-100]
}
Exer3Test e1 = new Exer3Test(); // 创建Exer3Test类对象,方便调用该类中方法
System.out.println("----------------排序前------------------");
e1.show(s1);
System.out.println("-------------status == 3----------------");
e1.showInfo(s1, 3);
System.out.println("----------------排序后------------------");
e1.sort(s1);
e1.show(s1);
}
/**
* @Description 根据score大小,对s1数组排序(递增)
* @author XJHui
* @date 2020年12月10日下午8:46:13
* @param s1 Student类数组
*/
public void sort(Student[] s1) {
for (int i = 0; i < s1.length - 1; i++) {
for (int j = 0; j < s1.length - i - 1; j++) {
if (s1[j].score > s1[j + 1].score) {
Student swap = s1[j];
s1[j] = s1[j + 1];
s1[j + 1] = swap;
}
}
}
}
/**
* @Description 输出state值为3的信息
* @author XJHui
* @date 2020年12月10日下午8:47:08
* @param s1 Student类数组
* @param state 年级
*/
public void showInfo(Student[] s1, int state) {
for (int i = 0; i < s1.length; i++) {
if (s1[i].state == 3) {
System.out.println(s1[i].number + " , " + s1[i].state + " , " + s1[i].score);
}
}
}
/**
* @Description 遍历数组并输出所有信息
* @author XJHui
* @date 2020年12月10日下午8:47:40
* @param s1 Student类数组
*/
public void show(Student[] s1) {
for (int i = 0; i < s1.length; i++) {
System.out.println(s1[i].number + " , " + s1[i].state + " , " + s1[i].score);
}
}
}
// 设计类
class Student {
// 属性
int number; // 学号
int state; // 年级
int score; // 成绩
}运行结果:
匿名对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34package cn.plushine.java;
/*
* 匿名对象的使用:
* 1.理解:我们创建的对象,没有显式的赋给一个变量名。
* 2.特征:匿名对象只能调用一次。
*/
public class InstanceTest {
public static void main(String[] args) {
// Phone p1=new Phone(); // 先创建一个对象,再通过该对象调用属性、方法。
// p1.sendEmail();
new Phone().price = 1.23; // 匿名对象,只能调用一次
System.out.println(new Phone().price); // 0.0,因为每次new都会在内存中开辟新的空间
PhoneMall pm1 = new PhoneMall(); // 虽然匿名对象只能调用一次,但可通过该方法实现匿名对象的多次调用
pm1.show(new Phone());
}
}
class Phone {
double price;
public void sendEmail() {
System.out.println("发送邮件!");
}
}
class PhoneMall {
public void show(Phone phone) {
phone.price = 1.0;
System.out.println(phone.price); // 1.0
}
}
重载、可变个数形参、值传递、递归
方法重载:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package cn.plushine.java;
/*
* 1. 定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
* 2. 判断是否构成重载:跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
*/
public class OverLoadTest {
public static void main(String[] args) {
OverLoadTest ol1=new OverLoadTest();
ol1.getSum(0, 1);
}
// 以下四种方法构成重载(参数数目、类型不同)
public void getSum(int i, int j) {
System.out.println("1");
}
public void getSum(double d1, double d2) {
System.out.println("2");
}
public void getSum(String s, int i) {
System.out.println("3");
}
public void getSum(int i, String s) {
System.out.println("4");
}
// 以下是错误重载
// public int getSum(int i, int j) {
// return 0;
// }
//
// public void getSum(int m, int n) {
// System.out.println("5");
// }
//
// private void getSum(int i, int j) {
// System.out.println("6");
// }
}可变个数的形参:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package cn.plushine.java;
/*
* 1.语法:数据类型 ... 变量名
* 2.参数个数:0个,1个,2个 ...
* 3.重载:
* ①可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
* ②可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载(二者不能共存)
* 4.注意:
* ①形参中【可变个数形参】和【非可变个数形参】同时存在时,可变个数形参在最后
* ②可变个数形参至多有一个
*/
public class MethodArgsTest {
public static void main(String[] args) {
new MethodArgsTest().showInfo("A", "B", "C");
}
public void showInfo(String... str) {
for (int i = 0; i < str.length; i++) {
System.out.print(str[i] + ' '); // A B C
}
}
// 形参中【可变个数形参】和【非可变个数形参】同时存在时,可变个数形参在最后
public void showInfo(int num, String... str) {
for (int i = 0; i < str.length; i++) {
System.out.print(str[i] + ' ');
}
}
}值传递机制
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package cn.plushine.java;
/*
* 方法的形参的传递机制:值传递
*
* 1.形参:方法定义时,声明的小括号内的参数
* 实参:方法调用时,实际传递给形参的数据
*
* 2.值传递机制:
* 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
* 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
*
*/
public class ValueTransferTest {
public static void main(String[] args) {
}
}案例练习1:
交换两个变量的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class ValueTransferTest {
public static void main(String[] args) {
// 失败方法
int m = 10;
int n = 20;
System.out.println("m = " + m + ", n = " + n); // m = 10, n = 20
ValueTransferTest vt1 = new ValueTransferTest();
vt1.swap(m, n); // 参数为基本数据类型,实参传递给形参的是值而非地址
System.out.println("m = " + m + ", n = " + n); // m = 10, n = 20
}
public void swap(int m, int n) {
int temp = m;
m = n;
n = temp;
}
}内存解析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package cn.plushine.java;
public class ValueTransferTest2 {
public static void main(String[] args) {
// 正确方法
Data d1 = new Data();
d1.m = 10;
d1.n = 20;
System.out.println("d1.m = " + d1.m + ", d1.n = " + d1.n);
ValueTransferTest2 vt2 = new ValueTransferTest2();
vt2.swap(d1); // 参数是引用数据类型,实参传递给形参的是地址
System.out.println("d1.m = " + d1.m + ", d1.n = " + d1.n);
}
public void swap(Data data) {
int swap = data.m;
data.m = data.n;
data.n = swap;
}
}
class Data {
int m;
int n;
}内存解析:
案例练习2:
画出下面程序的参数传递图示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package cn.plushine.exer;
public class MethodTransferExer {
public static void main(String[] args) {
MethodTransferExer test = new MethodTransferExer();
test.first();
}
public void first() {
int i = 5;
Value v = new Value();
v.i = 25;
second(v, i);
System.out.println(v.i); // 20
}
public void second(Value v, int i) {
i = 0;
v.i = 20;
Value val = new Value();
v = val;
System.out.println(v.i + " " + i); // 15 0
}
}
class Value {
int i = 15;
}过程图示:
递归方法:
基本使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38package cn.plushine.java;
/*
* 1.定义:一个方法调用它自身
* 2.方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
* 3.注意:递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
*/
public class RecursionTest {
public static void main(String[] args) {
// 案例
RecursionTest r1 = new RecursionTest();
int numSum = r1.getSum(100);
System.out.println("1-100之间所有自然数的和为:" + numSum); // 5050
int f10 = r1.f(10);
System.out.println("f(10)的值为:" + f10); // 10497
}
// 1.计算1-100之间所有自然数的和
public int getSum(int n) {
if (n == 1) {
return 1;
} else {
return n + getSum(n - 1);
}
}
// 2.已知数列: f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),求 f(10)
public int f(int n) {
if (n == 0) {
return 1;
} else if (n == 1) {
return 4;
} else {
return 2 * f(n - 1) + f(n - 2);
}
}
}可能用到递归:汉诺塔问题、斐波那契数列、快速排序、计算阶乘
不足之处,欢迎留言,会及时回复,及时更正!
创作不易,感谢支持!