Java基本知识
软件与程序与编程语言
-
软件是程序和数据的结合体
-
程序是用来处理数据的计算机指令集合
-
编程语言是用来书写计算机指令的语言
编程语言
-
机器语言 (计算机本身只能识别由0和1组成的机器语言)
-
汇编语言(增加了助记符)
-
高级语言 (独立于机器硬件,贴近人类的自然语言,按照人类日常会话的方式设计)
编译与解释
-
编译:源代码------>编译器(一次)------->目标代码------->执行(多次)-------->输出
优点:只要目标文件产生后就可以反复执行,无需再次编译
缺点:如果源代码发生改变,则需要重新编译生成新的目标文件
-
解释:源代码------->解释器-------->输出
优点:源代码发生改变,无需额外操作,直接执行即可
缺点:每次执行都需要重新翻译一次
java 语言概述
-
起源与历程
1995年、美国sun公司、Green项目
java之父:詹姆斯.高斯林
2009年:Oracle公司收购
JDK1~JDK17
-
语言体系
Java SE(java标准版) ------>桌面应用系统(PC机上开发桌面应用系统---单机)
精简: JavaME(java精简版) ----->手持设备(移动端:手机、paid、穿戴设备、汽车设备)
扩展:Java EE(java企业版) ----->企业级(服务器,对于web开发做后台支持)
-
语言特点
- 简单性
- 面向对象
- 跨平台
- 健壮与安全
-
java工作流程
-
JDK(Java开发工具包):源代码(*.java文件)------>java编译器------>字节码(.class文件)------>[类加载器------->字节码校验器------->解释器]------->操作系统平台
-
JRE(Java运行环境):字节码(.class文件)------>[类加载器------->字节码校验器------->解释器]------->操作系统平台
-
开发工具和环境
-
JDK(已经包含JRE)
提供Java开发人员所需的开发命令工具
JRE: Java程序运行需要的核心库、Java虚拟机(JVM)
- 版本选择(LTS):JDK8、JDK 11、JDK17
- Oracle JDK与open JDK
-
IDE(集成开发环境)
程序员工作中主要使用的开发软件
java
类命名的方法:字母、数字、$(大写字母开头)
//主类:有主函数的类
public class Test {
// 主函数、主方法、入口函数
public static void main(String[] args) {
System.out.print("哈哈哈哈哈");
System.out.println("试一试");
}
}
基本概念与语法
编程语言的组成:符号、标识符、指令语句、程序
标识符与关键字
标识符:在代码中打上标记帮助识别的符号,分为两类
-
系统(语言)预定义标识符,也叫关键字
-
用户自定义标识符
-
前人自定义的,后人用
-
本人自定义的
自定义标识符命名规则
硬规则:数字、字母、下划线以及$,其中不能以数字开头,不能与关键字重复且严格区分大小写
潜规则(行规):
-
见名知意
-
约定俗成:类名:
AaaBbb
(首字母大写);变量名:aaaBbbCcc
(首字母小写,后面大写);常量:AAA_BBB_CCC
-
-
class 与 main
- 在Java中所有的代码都要写在类的
{}
中 - 如果这个类的访问修饰符是
public
,那么类名必须和Java文件名保持一致 - 一篇Java文件中可以有多个类(通常不这样做),
public
只有一个 - 编译后的
class
文件数量与Java文件数量无关,只和Java文件中定义的类的数量有关(一个类一个class
文件)
数据类型、变量与常量
- 计算机的存储单位
- 位(
bit
):只存0
、1
,是最小存储单位 - 字节(
Byte
):8个位,是最小的处理单位 KB
:1KB
=1024Byte
MB
:1MB
=1024KB
GB
:1GB
=1024MB
TB
:1TB
=1024GB
- 位(
- 十进制整数转换为二进制
- 为了负数的存储,将最高位设置为符号位(第一位:符号位;第二位:偏移位)
- 原码:整数
- 反码:负数,数值一样,前面位取反
- 补码:反码加1
- 小数存放:在计算机中会有精度问题
- 在同样空间中实数存放比整数存放的范围更大
- 数据类型的作用:
- 告知计算机,用什么方式存储数据
- 告知计算机,划分多大的空间存储数据
基本数据类型
-
整型
byte
1个字节 (-128~127
)short
2个字节 (-2^15~2^15-1
)int
4个字节 (-2^31~2^31-1
)long
8个字节 (-2^63~2^63-1
)
常用int和long
-
浮点型
float
4个字节 最多保证8位,绝对能保证7位有效double
8个字节 最多保证17位,绝对能保证16位有效
-
字符型
-
char
专用于表示字符型,所占空间是2个字节,字符在计算机中的存储也是采用二进制形式单引号引用:转义字符例外---->
\t
,制表符,\n
换行,\r
回车,\\
表示\
-
ASCII码(
A:65
a:97
0:48
)
-
-
布尔型
true
false
引用数据类型
String
字符串
基本运算符
变量与常量
变量:在内存中分配一个空间,往此空间中存放数据;且随着程序的运行,该空间的数据值可以发生变化
语法: 数据类型 变量名;
由于新声明的变量里面的数据不确定且没有意义,所以变量在声明以后需要进行初始化,否则不允许访问和使用它
JDK10以后新增了局部变量类型推断,允许使用
var
关键字代替变量声明中的数据类型
var
只能用于方法内部的局部变量- 用
var
声明的变量必须马上赋初值var
类型推断是语法糖,编译器在编译后的字节码文件中还是编译成了推断后的类型名字
var age = 25;
int age;
age = 12;
int height = 190;
var flag = true;
var height = 186.7;
常量
- 字面常量
- 符号常量:给字面量起一个名字
- 语法:
final
数据类型 常量名 = 常量值
- 语法:
- 为什么要给常量取名?
- 把业务含义带入到常量值中
- 便于修改
运算符
-
算术运算符 (
+
-
*
/
%
)-
当
+
号两端出现一个字符串时,那么它执行的是字符串拼接动作 -
%
:取模,取余该符号是对左右两个操作数做除法,只不过最终结果不是商而是余数
特殊:1. 余数正负号,只跟第一个被除数有关
- 模运算只在整数运算下才有意义
-
最重要的:所有的算术运算符,如果左右两端的运算数据类型一致,那么结果就是该类型的结果;如果不一致,那么结果就是大的那个数据的结果
-
-
比较运算符 (
>
<
>=
<=
!=
==
)比较运算符最终的结果只能是
boolean
类型true
或false
-
逻辑运算符
布尔值:
true
和false
-
逻辑与
连接两个布尔表达式,当它们同为
true
,那么整体返回true;只要有一个为false
,整体返回假符号:
&&
逻辑与 && 是短路运算符,当它判断出第一个表达式为false的时候,它不会执行第二个表达式
-
逻辑或
连接两个布尔表达式,当它们中有一个为
true
,那么整体返回true
符号:
||
逻辑或 || 是短路运算符,当它判断出第一个表达式为true的时候,它不会执行第二个表达式
-
异或
两个表达式不同,即一真一假,组合为真
符号:
^
-
非
取反:非真即假,非假即真(单目)
符号:
!
用来对一个布尔表达式的结果取反,如果这个表达式为
true
,取反后的结果就是false
,反之亦然
-
-
赋值运算符 (
=
把赋值运算符右边的表达式,赋值给左边的变量)左边只有一个变量
要注意左右两边的数据类型:自动类型转换 和 强制类型转换
赋值语句也是一个表达式,整体作为表达式也有一个唯一值结果,结果就是=右边的计算值
//强制转换为整型 b = (int)(b + 3.14);
-
变形的赋值运算符(一)
+=
-=
*=
/=
%=
语句1:变量 = 变量 + 值;
语句2:变量 += 值;
注:这两句话的最终效果是一样的,但是如果出现类型不匹配的情况,语句1需要进行强制类型转换而语句2不用
-
变形的赋值运算符(二)
++
:自增--
:自减
前加 ++a 前减 --a
后加 a++ 后减 a--
单独使用a++ 和 ++a 是没有区别的(--也是同理),但在参与复杂运算时有区别
int num = 10; System.out.println(num++ * 5);//50 System.out.println(num);//11 int num1 = 10; System.out.println(++num1 * 5);//55 System.out.println(num1);//11
-
-
三目运算符 (
表达式
?语句1
:语句2
)-
表达式必须是一个布尔值表达式
-
当表达式为
true
时,用语句1
的结果作为整个三目运算符的结果 -
当表达式为
false
时,用**语句2
的结果**作为整个三目运算符的结果
-
-
位运算符
按位运算:
2
进制,真为1
,假为0
-
按位与
&
当它左右两端是布尔类型是,出现和
&&
同样的效果位与
&
不短路-
按位或
|
当它左右两端是布尔类型时,出现和
||
同样的效果位或
|
不短路-
按位非
~
按位取反,单目运算
-
按位或
^
任何一个数异或(
^
)它本身都为0
,任何一个数异或0
都为它本身 -
输入与输出
输入
-
声明一个输入器:
Scanner scan =new Scanner(System.in);
-
使用输入器接收输入
int age = scan.nextInt();
double height = scan.nextDouble();
String name = scan.next;
-
关闭输入器
scan.close();
import java.sql.SQLOutput;
import java.util.Scanner;
public class TestScanner {
public static void main(String[] args) {
/*
* 通过使用先人提供的Scanner的类,完成控制台输入
* Scanner的使用步骤
* 1、产生一个Scanner对象
* 2、调用该对象的方法完成输入
* 3、关闭Scanner对象
* */
Scanner scan = new Scanner(System.in);
System.out.println("请输入你的名字:");
String name =scan.next();
System.out.println("请输入你的年龄:");
int age = scan.nextInt();
System.out.println(name + "," + age + "岁");
scan.close();
}
}
输出
System.out.print
System.out.println
System.out.printf
分支语句
if
语句
-
单分支语句
格式:
if(条件表达式){ 语句块 }
执行顺序:程序首先对条件表达式进行判定,如果结果为
true
,则先执行{}
内的代码,结束之后继续执行{}
以后的代码,如果结果为false
,则跳过{}
,并执行{}
之后的代码 -
双分支语句
格式:
if(条件表达式){ 语句块1 }else{ 语句块2 }
执行顺序:程序首先对条件表达式进行判定,如果结果为
true
,执行语句块1,执行完后,跳到else
的结束}
外,继续往下执行;如果结果为false
,则执行语句块2,执行完后,跳到else
的结束}
外,顺序往下注:双分支语句可以改成单分支语句,但相较于单分支语句,多分支语句的判断次数较少
-
多分支语句
格式:
if(条件表达式1){ 语句块1 }else if(条件表达式2){ 语句块2 }else if(条件表达式3){ 语句块3 }else if(条件表达式4){ 语句块4 } ... else { 语句n }
执行顺序:程序首先判断条件
表达式1
,如果为true
则执行语句块1
,,然后跳到最后一个}
的后面顺序往下执行;如果为false
,则执行条件表达式2
,如果为true
,则执行语句块2
,然后跳到最后一个}
后面顺序往下;如果为false
,则继续判断表达式3
...如果所有的表达式判断都为
false
,则进入最后一个else
执行,然后出了最后一个}
往下执行注意:最后一个不带条件的
else
不是必须的,可以根据情况自主选择
switch 语句
格式:
switch(表达式){ case 常量1:语句块; break; case 常量2:语句块; break; case 常量3:语句块; break; ... default:语句块 break; }
注:
break
只能写在switch
和循环当中,其他地方不能写
在switch当中,所有的case,包括default是没有顺序可言的
在switch每个分支,如果最后不写break,那么程序会自动进入下一个分支开始执行
在JDK14中,switch设计了新的语法。可以把它当作一个表达式,每个分支返回不同的值,然后使用统一赋值给某个变量;
新的关键字“
yield
”,在每个分支中,起到返回值且起到break
的作用,整条语句后要有分号
int a = switch(表达式){ case 常量1:语句块; yield 值1; case 常量2:语句块; yield 值2; ... default 语句块; yield 值n };
int a = switch(表达式){ case 常量1-> 值1; case 常量2->值2; ... default->{ 语句块; yield 值n } };
循环语句
循环是由反复被执行的 循环体语句 和 循环终止的条件 共同组成的。
-
for
循环格式:
for(表达式1;表达式2;表达式3){ 循环体语句; }
-
for 里的表达式可以不写,但必须有
;
;
-
表达式1-------声明一个循环控制变量,记录循环开始的起始值 标准写法:
int i = 0;
表达式2-------是一个布尔表达式,用来判定什么时候继续循环;
当它为
true
时,就会继续循环 当它为
false
时,就会退出for
循环结束}
,继续向下执行表达式3------- 用来控制循环控制变量的自改变的,又被称为步长
i++;
- for循环中的语句执行的顺序:
a.一旦遇到for循环,首先执行表达式1;
b.然后马上判断表达式2,如果为
true
进入循环体;为false
,退出循环 c.循环体执行完以后,执行表达式3;
d.然后回到步骤b
- 表达式1中定义的循环控制体变量,其生命周期仅在这个循环之内,循环完这个变量就销毁了
在循环体当中声明的变量,其生命周期是每次单个的循环
-
-
while
当循环格式:
while(condition){ // do something }
- 当condition的结果为true,则执行循环,否则不执行
- 不明确知道循环次数
for
与while
是先验循环,先判断再执行 -
do-while
循环格式:
do { // do something } while(condition);
首先执行循环体的内容,然后根据condition的值判断是否继续循环。
do-while
循环是后验循环,即先执行再判断,至少执行一次循环中断
-
break
跳出本层循环体,从而提前结束本层循环 -
continue
是结束本次循环,进入下一次循环(while
和do while
是进入下一次判断,而for
是执行语句3)continue
在实际的使用当中并不多,通常我们在循环中是正向逻辑表达满足某个条件则做什么而continue所在的循环则代表的是反向逻辑,即满足某个条件就不做什么,正难则反的时候使用
-
tips:随机数
Math.random()
double r = Math.random();
//直接调用Math.random(),得到[0,1)的随机数
//如果要产生一个[min,max]之间的随机数
//(int)(Math.random()*(max - min + 1)) + min
System.out.println(r);
int s = (int)(Math.random()*11); //0到10的数
int y = (int)(Math.random()*50 + 50); //50到99的数
Random random = new Random();
// int, [0, n)
int intNum = random.nextInt(n);
// double
double doubleNum = random.nextInt();
弹窗功能
-
消息框
JOptionPane.showMessageDialog()
showMessageDialog
接收两个参数,中间用,
隔开- 参数1:目前固定写为
null
,代表弹窗在屏幕的正中央;参数2:显示在弹窗上的消息
JOptionPane.showMessageDialog(null,"今天天气真好!"); JOptionPane.showMessageDialog(null,"大傻子!");
-
输入框
JOptionPane.showInputDialog()
-
参数1:
null
,代表弹窗在屏幕的正中央;参数2:显示在弹窗上的提示信息
- 弹窗输入框中无论输入了什么内容,在程序中得到的都是字符串
- 如果点击了输入框中的取消按钮,那么Input会被赋值为null,即没有指向任何字符串
String input = JOptionPane.showInputDialog(null,"请输入今天的气温!"); System.out.println(input);
-
-
确认框
JOptionPane.showConfirmDialog()
提出一个问题,用户三个选择:"是"、"否"、"取消"
点击不同的按钮,会返回不同的int值
是 否 取消 0 1 2 int choice = JOptionPane.showConfirmDialog(null,"天气好吗?"); System.out.println(choice);
字符串转型
-
基本数据类型 转 字符串 --基本数据类型 + ""
-
字符串 转 基本数据类型
首先保证字符串里面的内容是一个正确的可以被转换的数据
Integer.parseInt(待转对象)
转换成int
型Double.parseDouble(待转对象)
转换成double
型Float.parseFloat(待转对象)
转换成float
型Long.parseLong(待转对象)
转换成long
型
String str = "123";
int num1 = Integer.parseInt(str);
System.out.println(num1+1);
String ageStr = JOptionPane.showInputDialog(null,"年龄:");
int age = Integer.parseInt(ageStr);
System.out.println(age +1);
嵌套循环
格式:
外层循环{
内层循环{
}
}
外层循环1次,内层循环1圈
数组
集合是将一组数据集中合并放置在一起,进行批量操作。
数组是集合中最原始简单的一种,几乎所有的编程语言,在语法设计的时候直接自带数组
数据的特点:
- 只能存放同一数据类型的元素
- 所有元素是存放在连续内存地址空间的
- 数组空间大小一旦确定,不可更改
声明语法:
数据类型[] 变量名 //标准语法
数据类型 变量名[]//非标准语法
初始化语法:
- 已知要放入数据的元素个数和值是多少
int[] score = {24,56,43,33};
double[] rainFall = {11.2,21,89.9};
String[] names = {"循环","嵌套","顺序"};
-
只知道要放入数组的元素个数
数组中的每个元素都会被自动初始化
- 1、如果元素是基本数据类型,那么赋初值0------>字符型是ASSCII码为0的字符,布尔型是
false
- 如果元素是引用数据类型,那么赋初始值为null
- 1、如果元素是基本数据类型,那么赋初值0------>字符型是ASSCII码为0的字符,布尔型是
//这里的10和5,我们称之为数组的长度
int[] ages = new int[10];
double[] height = new double[5];
操作数组中的元素
语法:
数组名[下标]
下标相当于数组元素在数组中的编号,英文“index”,所有的下标都是从0开始
我们完全可以把
数组名[]
当作一个变量来看,可以做相应的访问与修改
- 如果在访问数组元素时没有正确指定下标,编译不会报错,但运行时会报异常(ArrayIndexOutOfBoundsException--数组下标越界)为了对最大下标进行良好地控制,Java的数组中提供了一个叫做
length
的属性,可以获取的长度
System.out.println(score[1]);
for (int i = 0; i < score.length;i++){
System.out.println(score[i]);
}
for (int i = 0; i < ages.length; i++){
System.out.println(ages[i]);
}
- 字符串的
toCharArray()
方法,可以把一个字符串转成一个char[]
数组中的排序
对集合(数组)中的元素进行排序是一个非常常用的基本操作,排序的算法有:冒泡排序、选择排序、自然排序,前人已经实现了排序算法,我们可以直接调用
- 冒泡排序
冒泡排序的基本逻辑:假设考虑的是从小到大排序
1. 第0轮排序,用下标为0的元素依次与后面的元素进行比较,
谁小谁就放到0位置;
2. 第1轮排序,用下标为1的元素依次与它后面的元素进行比较,
谁小谁就放到1位置;
......
外层循环控制轮数,数组中有N个元素就做N-1轮。(最后剩下的元素无需比较了,也没有
元素跟它比较,所以少做一轮)。
内层循环控制目标位元素和它后面的元素依次比较。外层是第几轮,目标元素的下标就是几。
第0轮,目标元素就是数组[0];第1轮,目标元素就是数组[1];......
所以借用外层的循环控制变量用数组[i]来表示目标元素。
被比较元素是目标元素后面的每一个元素,所以被比较元素的下标是从i+1开始的,直到最后
一个元素,所以内层循环的j变量范围是从i+1 到 数组.length;
每次比较都是用数组[i]和数组[j]进行,满足条件则交换位置即可。所以在if语句中是
典型的交换变量的语法。
- 选择排序
- 自然排序
二维数组
-
声明语法
int[][] 数组名
-
创建语法
-
明确知道数组里面的每个元素(可以声明每行列数不同的二维数组)
数组 = {{1,2,3} ,{4,5,6} ,{7,8,9}};
-
并不清楚每个具体元素,只知道要放入多少个(只能声明每行列数相同的二维数组)
数组 = new int[3][5];
---------->3行5列
-
-
操作内部元素
数组[下标1][下标2]
下标都是从0开始,直到是最大长度-1
为了防止数组下标越界,仍然有length属性
- 用
数组名.length
得到的是行的最大数目 数组名[下标].length
得到的是下标所在行的列的最大数目
二维数组的遍历,天生就是要使用双重循环
int classSum = 0; int[][] scores = new int[3][5]; Scanner sc = new Scanner(System.in); for(int i = 0; i<scores.length;i++){ int sum = 0; for (int j = 0;j<scores[i].length;j++){ System.out.print("请输入第"+(i+1)+"组的第"+(j+1)+"位同学的分数:"); scores[i][j]=sc.nextInt(); sum+=scores[i][j]; } double avr = (double)sum / 5; classSum+=sum; System.out.println("第"+(i+1)+"组总分"+sum); System.out.println("第"+(i+1)+"组平均分"+avr); for (int j = 0;j<scores[i].length;j++){ double zuCha = scores[i][j] - (double)sum / 5; System.out.println("第"+(i+1)+"组的第"+(j+1)+"个人的组差"+zuCha); } } sc.close(); double classAvr = (double) classSum / 15; System.out.println("班级总分:"+classSum); System.out.println("班级平均分:"+classAvr); for (int i = 0; i<scores.length;i++){ for (int j = 0;j<scores[i].length;j++){ double banCha = scores[i][j] -(double)classSum /15; System.out.println("第"+(i+1)+"组的第"+(j+1)+"个人的班差"+banCha); } }
- 用
方法
本质:一个功能块
优点:模块化,复用性强、便于修改维护、(见名知意)便于开发
方法的意义
- 方法的出现是模块化的必然结果
- 设计人员不用考虑实现的细节,有利于其对程序宏观的控制
- 开发人员可以只考虑自己负责模块的实现,达到多人同时开发的效果,提升了效率
方法定义的语法
方法定义的语法
-
声明,作用是给调用方看的
-
外部能不能访问这个方法
-
如何访问这个方法,访问它需不需要传递数据
-
访问结束后有没有结果的返回
-
-
实现,实现部分是定义方自己关注和书写的,其任务就是完成这个方法的功能,调用方不关注实现,只关注结果
格式:
修饰符 返回类型 方法名(参数列表){
方法的实现
}
目前,所有方法的修饰符都写成:
public
static
;返回类型:定义的是这个方法执行结束以后会有一个什么类型的结果返回调用方
如果一个方法执行结束以后没有返回,那么这里的返回类型书写
void
void
代表没有返回值
- 方法名:能够“见名知意”能代表本方法完整功能描述的自定义标识符
通常采用:
aaaBbbbCcc
的书写规范;且通常是动词 或 动宾短语
- 参数列表:在调用本方法时需要我外部调用者传入哪些初始数据?由于在定义的时候并不能知道调用方真正传递的值是多少,只能确定需要哪些类型的数据。
所以参数列表的语法全是变量声明的语法,多个参数之间用“
,
”分隔 如果没有参数,可以不写,但
()
不能少
- 在方法实现部分除了完成功能的语句,另外要注意和声明语句的配合。
如果方法的声明是非
void
的,那么表示该方法一定会有某个类型的返回, 那么在该方法中一定要有
return
关键字,后面跟上和返回类型匹配的返回值注意:不是写一个
return
就可以了,而是保证该方法在任意执行路径下都要有return
return
真正的含义是结束方法,把执行流程返回给方法调用处
return是结束方法的,所以它后面不能再有直接语句;
声明为void的方法也能有return,只是后面不跟值
如果在main方法中书写return,代表程序结束
方法调用的语法
-
调用函数
-
可以在任意需要使用到这个函数的地方完成调用
-
被调用的函数可以和调用函数不在同一个class当中
-
-
语法格式:
类名.函数名(参数列表);
如果被调用函数有返回值,
数据类型 变量 = 类名.函数名(参数列表)
当被调用的方法和调用处处于同一个class文件中,那么访问语法中的“
类名.
”可以省略 -
方法定义处和方法调用处参数的关系与区别
-
方法定义处的参数,专有名---->形参
因为在定义处的参数只定义了参数形式,包括:参数类型、参数个数、参数顺序
方法调用处的参数,专有名---->实参
因为调用的时候才确定本次调用真正传递进入的每个参数的数据值,这个数据值可以是常量也可以是变量
- 调用处的传递的实参必须和定义处定义的形参相匹配:参数类型匹配、参数顺序一致、参数个数一致
- 注意:参数名其实是不用进行匹配的
-
方法中的参数传递
public class TestMethod {
public static void main(String[] args) {
int num = 10;
methodA(num);
}
public static void methodA (int a){
}
}
方法的使用,本质上是一个方法模块去调用另一个方法模块中的代码。 在很多情况下,被调用的方法模块(
methodA
)需要用到调用方(main
)的数据。 而根据变量的作用域,main
当中的数据只能在main
方法内部操作,而methodA
看不到也操作不到,所以需要传参。当我们调用方法的时候,首先并不是执行
{}
内的语句,而是先执行()
当中的语句,而形参语句的语法就是声明变量,所以一旦调用methodA
,会在methodA
当中声明一个叫做a
的整型变量。然后,JVM会做数据传递,把实参的数据传递给形参变量。
在
methodA
当中对形参进行任何操作,都不会直接影响到main
中的数据,如果想要影响,只有让methodA
把值返回出去,并且在main
中重新将其赋值给一个变量。
public class TestMethod {
public static void main(String[] args) {
int[]array = {100,200,300};
methodB(array);//101
}
public static void methodB (int[] array){
array[0]++;
System.out.println(array[0]);
}
}
在java中参数只有一种传递方式 --- “值传递”,永远都是把实参的”值“传递给形参。
只是由于Java中基本数据类型和引用数据类型变量保存值的方式不同,造成了效果上的差异!(牢记:不是传递方式的不同)
基本数据类型变量的值是保存在变量本身当中的,所以把真正的数据值传递给形参;
引用数据类型变量的值指向真正数据的引用,所以传参的时候把这个引用传递给了形参,从而导致形参和实参指向了同一个真正的数据(对象)
JDK新语法:当用数组作为形参的时候,可以把形参设计为可变参数
public class TestMethod {
public static void main(String[] args) {
String[] str = {"wd","asd","adad","asd"};
methodC(str);
methodD(str);
methodD("AJSDH","ASDI","ASDH","8E89","AHAKOO");
}
//传统写法,在调用处只能声明一个明确的数组对象,然后把该数组对象作为实参进行传递
public static void methodC(String[] args){
}
/*
可变参写法,在调用处,可以像传统方式直接传递一个数组对象
也能够采用元素罗列的方式进行传递,这样做就在某些场景中省略了声明数组的语句。
当然,作为形参的agrs仍然在methodD方法中被认为是一个数组,应该继续使用数组的语法进行操作
*/
public static void methodD(String...args){
System.out.println(args.length);
}
}
方法调用栈
程序执行的顺序:
默认是从main方法的第一句代码顺序往下,直到main方法的最后一句;
分支语句和循环语句打破了顺序执行;分支语句控制了根据条件执行某部分代码,而让另一部分代码不执行;循环语句控制了某部分代码被反复地连续执行
方法地调用其实也改变了顺序执行
一旦发生了方法调用,那么程序地流程就会离开调用处,进入被调用方法内部执行,
直到该方法执行结束,然后再返回调用处继续往下执行
在方法连续进行嵌套调用地时候,先调用地方法后结束,后调用地方法先结束。
这种顺序形成了”先进后出“的效果,专业词汇叫做”栈“。
public class TestMethod2 {
public static void main(String[] args) {
System.out.println("main第一句");
methodA();
// methodB();
System.out.println("main第二句");
}
public static void methodA(){
System.out.println("方法A第一句");
methodB();
System.out.println("方法A第二句");
}
public static void methodB(){
System.out.println("方法B第一句");
System.out.println("方法B第二句");
}
}
方法重载
所谓方法重载就是在一个java类当中运行命名多个重名的方法。名字一样的情况下,是依赖参数列表的不同来区分它们。参数列表包括:参数个数、参数类型、参数顺序,跟参数名无关
递归
一个方法自己调用自己本身,在效果上它就是一种循环,循环执行该方法自己内部的代码
递归的关键是控制循环的结束,也就是说自己内部调用自己不能采用无条件调用,一定要有一个判断,该判断的作用是让它在某个时刻停止自己调用自己,然后原路返回。
无论是for
while
do while
还是递归,虽然都可以通过程序员的控制实现相同的效果,但是在合适场景中使用最适合的语法才是自然的。
递归-------------上一次循环的结果,下一次循环的初始条件
public class TestMethod4 {
public static void main(String[] args) {
test(10);
tenToTwo(6);//110
tenToTwo1(6);//011
}
public static void test(int num){
System.out.println("I LOVE YOU");
num--;
if (num != 0)
test(num);
}
//二进制
public static void tenToTwo(int num){
int mod = num % 2;
num /= 2;
if (num != 0) {
tenToTwo(num);
}
System.out.print(mod);
}
public static void tenToTwo1(int num){
int mod = num % 2;
System.out.print(mod);
num /= 2;
if (num != 0) {
tenToTwo1(num);
}
}
}