JavaSE
1、Java语言概述
1.1、基础常识
计算机重要组成部分:硬件与软件
硬件
CPU、内存、存储设备、输入设备、输出设备、通信设备
- CPU(Central Processing Unit,中央处理器)
- 人靠大脑思考,电脑靠CPU来运算、控制
- 硬盘(Hard Disk Drive)
- 计算机最主要的存储设备,容量大,断电数据不丢失
- 分类:
机械硬盘(HDD)
、固态硬盘(SSD)
以及混合硬盘(SSHD)
- 固态硬盘在开机速度和程序加载速度远远高于机械硬盘
- 内存(Memory)
- 负责硬盘上的数据与CPU之间数据交换处理
- 保存从硬盘读取的数据,提供给CPU使用;保存CPU的一些临时执行结果,以便CPU下次使用或保存到硬盘
- 断电后数据丢失(断电即失)
软件
软件:即一系列按照特定顺序组织的计算机数据和指令的集合,可分为系统软件
和应用软件
系统软件:windows、mac os、linux、unix、android、ios
应用软件:word、微信、饿了么、淘宝、高德地图、百度网盘……
人机交互方式
-
图形化界面(Graphical User Interface GUI)该方式简单直观,使用者易于接受,容易上手操作
-
命令行方式(Command Line Interface CLI):需要在控制台输入一些特定的指令,让计算机完成一些操作。较为麻烦,需要记住一些命令
常用DOC命令
- dir: 列出当前目录下的文件以及文件夹
e:
:快速切换到 E 盘- md: 创建目录
- rd: 删除目录
- cd: 进入指定目录
- cd …: 退回到上一级目录
- cd \: 退回到根目录
- del: 删除文件
- exit: 退出 dos 命令行
- 常用快捷键
- ← →:移动光标
- ↑ ↓:调阅历史操作命令
- Delete和Backspace:删除字符
- cls:清屏
- exit:退出终端
1.2、初识Java
应用程序 = 数据结构 + 算法
计算机语言发展迭代史
- 第一代:机器语言,指令以二进制代码形式存在(打孔纸带)
- 第二代:汇编语言,使用助记符表示一条机器指令(add、sub、mov)
- 第三代:高级语言
- 面向过程: C、Pascal、Fortran
- 面向过程/面向对象:C++
- 面向对象:Java、JavaScript、Python
不管是什么语言,最后都要向机器语言靠近,因为CPU只认识0和1
Java是什么?
Java是SUN(Stanford University Network,斯坦福大学网络公司 ) 1995年推出的一门高级编程语言
随着互联网的快速发展,同时也随着Java技术在Web方面的不断成熟,已经成为Web应用程序的首选开发语言
Java语言版本迭代
发行版本 | 发行时间 | 备注 |
---|---|---|
Java 1.0 | 1996.01.23 | Sun公司发布了Java的第一个开发工具包 |
Java 1.1 | 1997.02.19 | JavaOne会议召开,创当时全球同类会议规模之最 |
Java 1.2 | 1998.12.08 | Java拆分成:J2SE(标准版)、J2EE(企业版)、J2ME(小型版) |
Java 1.3 | 2000.05.08 | |
Java1.4 | 2004.02.06 | |
Java 5.0 | 2004.09.30 | ①版本号从1.4直接更新至5.0;②平台更名为JavaSE、JavaEE、JavaME |
Java 6.0 | 2006.12.11 | 2009.04.20 Oracle宣布收购SUN公司 |
2009.04.20 | Oracle公司收购SUN,交易价格74亿 美元 | |
Java 7.0 | 2011.07.02 | |
Java 8.0 | 2014.03.18 | 此版本是继Java 5.0以来变化最大的版本。是长期支持版本(LTS) |
Java 9.0 | 2017.09.22 | ①此版本开始,每半年更新一次;②Java 9.0开始不再支持windows 32位系统 |
Java 10.0 | 2018.03.21 | |
Java 11.0 | 2018.09.25 | JDK安装包取消独立JRE安装包,是长期支持版本(LTS) |
Java 12.0 | 2019.03.19 | |
… | … | |
Java17.0 | 2021.09 | 发布Java 17.0,版本号也称为21.9,是长期支持版本。 |
… | … | |
Java19.0 | 2022.09 | 发布Java19.0,版本号也称为22.9 |
应用领域
- 企业级应用领域(JavaEE后台):开发企业级的应用程序、各种类型的网站
- 移动应用领域(集成Android平台):Java在Android端是主要的开发语言,占有重要地位
- 大数据分析、人工智能领域:流行的大数据框架,如Hadoop、Flink都是用Java编写的
语言特点
-
面向对象性
- 两个要素:类、对象
- 三个特征:封装、继承、多态
-
健壮(安全)性
- 吸收了C/C++语言的优点,但去掉了其影响程序健壮性的部分(如指针、内存的申请与释放等),提供了一个相对安全的内存管理和访问机制
- 自动的垃圾回收机制,仍会出现内存溢出、内存泄露问题
-
跨平台性
-
Write once,Run Anywhere
一次编译,到处运行 -
一切功劳都归功于
JVM (Java Virtual Machine)
-
Java两种核心机制
- Java虚拟机 (Java Virtal Machine)
- 垃圾收集机制 (Garbage Collection)
JDK、JRE、JVM三者之间的关系
- JDK:Java Development Kit(开发者工具)
- JRE:Java RunTime Environment(运行时环境)
- JVM:Java Virtual Machine(Java虚拟机)
JDK下载与安装
注:安装路径尽量不要包含中文或者空格等特殊符号
path环境变量的配置
环境变量
path环境变量:windows操作系统执行命令时所要搜寻的路径
为什么要配置path环境变量?
希望java的开发工具(javac.exe、java.exe)在任何文件的执行路径下都可执行成功!
如何配置?
1.3、Java三大版本
- JavaSE:标准版(桌面程序、控制台开发 )
- JavaME:嵌入式开发(手机、小家电)
- JavaEE:企业级开发(web端、服务器开发)
1.4、第一个Java程序
我的第一个Java程序——HelloWorld
-
编写源文件
创建java源文件,文件名为:
HelloWorld.java
public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello World!!!"); } }
-
编译源文件
# javac 源文件名.java javac HelloWorld.java
-
运行
.class
文件# java 类名 java HelloWorld
注:在一个java源文件中可以包含多个class。但是,只能有一个类声明为public的,并且要求声明为public的类应与文件名一致,否则编译失败!
编译之后,会生成一个或多个字节码文件,字节码文件的文件名与java源文件中的类名相同
1.5、注释与API文档
注释(Comment):用于注解说明解释程序的文字就是注释
分为三类
- 单行注释:
//
- 多行注释:
/* */
- 文档注释(java特有) :
/** */
作用
- 对编写的程序进行解释说明,增强代码可读性,便于协作开发
- 便于调试自己所写的代码
特点:对于单行和多行注释,注释的文字不参与编译,换而言之,编译以后生成的以.class
结尾的字节码文件中不包含注释掉的信息
对于文档注释,注释的内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件形式体现该程序的说明文档
/**
* @author zhang 作者
* @version 1.0 版本号
* @since 1.8 需要使用的jdk版本
*/
/**
*
* @param name 参数名
* @param pwd
* @return 返回值
* @throws Exception 异常抛出情况
*/
public boolean login(String name,String pwd) throws Exception{
return true;
}
Java API文档:
API:(Application Programming Interface,应用程序编程接口)是 Java 提供的基本编程接口,通常习惯上将语言提供的类库,都称为API
API文档:针对于提供的类库如何使用所提供的一个说明书,类似于汉字中的《新华字典》
2、变量与数据类型
2.1、关键字和保留字
关键字(keyword)定义和特点
定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)
特点:关键字中所有字母都为小写
Java保留字(reserved word):现有Java版本尚未使用,但以后版本可能会作为关键使用功能用。自己命名标识符时要避免使用这些保留字,goto 、const
2.2、标识符
标识符(Identifier):Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符
注:凡是自己可以起名字的地方都叫标识符
定义合法标识符规则:字下美元其后数
,不可使用关键字或保留字,但可以包含关键字和保留字,不能包含空格
Java中的名称命名规范
注:在起名称时,为了提高代码可读性,要尽量起的有意义 见名知意
java采用unicode字符集
,因此标识符也可以使用汉字声明,但是不推荐使用
2.3、变量
变量的概念
- 内存中的一个存储区域
- 该区域的数据可以在同一类型范围内不断变化
- 变量是程序中最基本的存储单元。包含
变量类型、变量名和存储的值
变量的作用:用于在内存中保存数据
注:
- Java中每个变量必须先声明,后使用
- 使用变量名来访问这块区域的数据
- 变量的作用域:其定义所在的一对
{ }
内 - 变量只有在其作用域内才有效,同一个作用域内,不能定义重名的变量
变量的分类
按数据类型划分
对于每一种数据都定义了明确的具体数据类型(强类型语言),在内存中分配了不同大小的内存空间
Java各整数类型有固定的表数范围和字段长度,不受具体OS的影响,以保证java程序的可移植性
整型
java的整型常量默认为 int 型,声明long型常量后面须加L
java程序中变量通常声明为 int 型,除非不足以表示较大的数,才使用long
byte b = 110;
short s = 256;
int number = 10;
long count = 1354684542564L;
注:bit:计算机中的最小存储单位
。byte:计算机中的基本存储单元
浮点型
与整数类型类似,Java 浮点类型也有固定的表数范围和字段长度,不受具体操作系统的影响
float:单精度,尾数可以精确到7位有效数字。很多情况下,精度很难满足需求
double:双精度,精度是float的两倍。通常采用此类型
Java的浮点型常量默认为double型,声明float型常量,后面须加加‘f’或‘F’
float f = 15896456245F;
double d = 6.19;
字符型
char 型数据用来表示通常意义上“字符”(1字符 = 2字节)
Java中的所有字符都使用Unicode编码,故一个字符可以存储一个字母,一个汉字,或其他书面语的一个字符
// 表示方式一:声明一个字符
char bigLetter = 'A';
char smallLetter = 'a';
char chineseCharacter = '林';
// 表示方式二:转义字符
char c1 = '\n';
char c2 = '\t';
// 表示方式三:Unicode值
char c3 = '\u0031';
注:char类型是可以进行运算的。因为它有对应的Unicode码
布尔类型
boolean 类型用来判断逻辑条件,一般用于程序流程控制:
if条件控制语句;
while循环控制语句;
do-while循环控制语句;
for循环控制语句;
注:boolean类型数据只允许取值true和false,无null
按声明位置的不同划分
在方法体外,类里面声明的变量称为成员变量
在方法体内部声明的变量称为局部变量
2.4、数据类型
强类型语言
- 要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
弱类型语言
- 弱类型语言是一种弱类型定义的语言,某一个变量被定义类型,该变量可以根据环境变化自动进行转换,不需要经过显性强制转换。弱类型语言包括vb 、PHP、javascript等语言
强类型语言和弱类型语言区别
- 无论是强类型语言还是弱类型语言,判别的根本是是否会隐性的进行语言类型转变。强类型语言在速度上略逊于弱类型语言,但是强类型定义语言带来的严谨性又能避免不必要的错误。
2.5、基本数据类型转换
自动类型转换
容量小的类型自动转换为容量大的数据类型,数据类型按容量大小排序为:
int count = 66;
double number = count; // 自动提升运算,提升为double
System.out.println(number);
byte、short、char之间不会相互转换,他们三者在计算时首先转换为int类型
boolean类型不能与其它数据类型运算
注:当把任何基本数据类型的值和字符串(String)进行连接运算时(+),基本数据类型的值将自动转化为字符串(String)类型。
强制类型转换
要把容量大的类型转换为容量小的数据类型,必须要进行强制类型转换
double count = 3.14;
int b = (int) count; // 强制装换为int类型
System.out.println(b);
注:在把高容量装换到低容量的时候,强制转换的时候可能会存在内存溢出,或者精度丢失问题!
2.6、字符串类型
String不是基本数据类型,属于引用数据类型
一个字符串可以拼接另一个字符串,也可以直接拼接其他类型的数据
String str = "hello world!";
System.out.println(str);
注:String可以和8种基本数据类型变量做运算,且运算只能是连接运算
,运算结果仍是String类型!
2.7、计算机的存储规则
在计算机中,任意数据最终都是以二进制的形式来存储的。包括文本(数字、字母、汉字)、图片、声音、视频等
世界上有2种人 ,认识和不认识二进制的
数字存储
进制的分类
- 十进制(decimal)
- 数字组成:0-9
- 进位规则:逢十进一,借一当十,正常写,代码前面不需要加任何前缀
- 二进制(binary)
- 数字组成:0-1
- 进位规则:逢二进一,代码中以
0b
或0B
开头
- 八进制(octal):很少使用
- 数字组成:0-7
- 进位规则:逢八进一,代码中以数字
0
开头表示
- 十六进制
- 组成部分:0-9,a-f
- 进位规则:逢十六进一,代码中以
0x
或0X
开头表示。此处的 a-f 不区分大小写
public static void main(String[] args) {
int x = 100; // 十进制
int y = 0b1101; // 二进制
int z = 056; // 八进制
int q = 0X35a; // 十六进制
System.out.println(x); // 100
System.out.println(y); // 13
System.out.println(z); // 46
System.out.println(q); // 858
}
进制之间相互转换
任意进制转十进制
公式:系数 * 基数的全次幂 相加
- 系数:每一位上的数
- 基数:当前进制数
- 从右往左,依次为 0 1 2 3 4 5 6 ……
二进制转十进制
8421快速转换法
每一位二进制值的1都是代表一个固定数值
把每一位的1代表的十进制数加起来得到的结果就是它所代表的十进制数
十进制转其他进制
除基取余法
不断的除以基数(几进制,基数就是几)得到余数,直到商为0,再将余数倒着拼起来即可
字母存储:ASCII (American Standard Code for Information Interchange)码表:美国信息交换标准代码表
汉字存储
- GB2312编码:1981年5月1日发布的简体中文汉字编码国家标准。收录7445个图形字符,其中包括6763个汉字
- BIG5编码:台湾地区繁体中文标准字符集,共收录13053个中文字,1984年实施
- GBK编码:2000年3月17日发布,收录21003个汉字,包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字
- Unicode编码(万国码):国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码, 以满足跨语言、跨平台的文本信息转换
图片存储:通过每一个像素点中RGB三原色来存储
声音存储:对声音的波形图进行采样再进行存储
2.8、运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等
-
算术运算符 +,-,*,/,%,++,- -
- %
取模(取余)
- 前++
先运算,后取值
- 后++
先取值,后运算
- – 同理
- %
-
赋值运算符 =、+=、-=、*=、/=、%=
- 当
=
两侧数据类型不一致时,可以使用自动类型转换或强制类型转换原则进行处理 - 支持连续赋值
// 连续赋值 // 方式一 int num1 = 10, num2 = 20; // 方式二 int count1, count2; count1 = count2 = 20; byte number1 = 20; number1 = number1 + 5; // 编译不通过 byte number2 = 20; number2 += 5; // 编译通过,+= 这种方式不会改变其本身的数据类型 System.out.println(number2);
- 当
-
比较运算符(关系运算符) >,<,>=,<=,==,!=
-
比较运算符的
结果都是boolean型
,也就是说要么是true,要么是false -
比较运算符
==
不能误写成=
// = 和 == 的区别 boolean k1 = true; boolean k2 = false; System.out.println(k2 == k1); // 双等比较 false System.out.println(k2 = k1); // 单等赋值 true
-
-
逻辑运算符 &&,||,!
-
位运算符 &,|,^,>>,<<,>>>(不常用)
-
三元运算符
(条件表达式) ? 表达式1 : 表达式2
// 比较两个整数的较大值 int m = 99,n = 88; int max = (m > n) ? m : n; System.out.println("两者比较最大值为:" + max);
三元运算符与if-else的联系与区别:
- 三元运算符可简化if-else语句
- 三元运算符要求必须返回一个结果
- if后的代码块可有多个语句
2.9、包机制
为了更好地组织类,Java提供包机制,用于区别类名的命名空间
package pkg1 pkg2 pkg3...;
一般利用公司域名倒置作为包名 www.baidu.com com.baidu.www
为了能够使用某一个包的成员,我们需要在Java程序中明确导入该包,使用import语句可完成此功能
import pkg1 pkg2 pkg3...;
import com.zhang.base.*; //导入这个包下所有的类
3、程序流程控制
流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块
其流程控制方式采用结构化程序设计中规定的三种基本流程结构,即:
- 顺序结构
- 程序从上到下逐行地执行,中间没有任何判断和跳转
- 选择结构
- 根据条件,选择性地执行某段代码
- 有if…else和switch-case两种分支语句
- 循环结构
- 根据循环条件,重复性的执行某段代码
- 有while、do…while、for三种循环语句
注:JDK1.5提供了foreach循环`,方便的遍历集合、数组元素
3.1、顺序结构
是按照自上而下的顺序执行的,也是任何一个算法都离不开的一种基本算法结构,也是最为简单的算法结构
3.2、选择结构
- if单选择结构
- if双选择结构
- 多重if选择结构
- 嵌套if选择结构
- switch多选择结构
if单选择结构
if(条件表达式){
//执行代码块
}
if双选择结构
if(条件表达式){
//执行代码块1
}else{
//执行代码块2
}
多重if选择结构
if(条件表达式1){
//如果条件表达式1为true执行代码
}else if(条件表达式2){
//如果条件表达式2为true执行代码
}else if(条件表达式3){
//如果条件表达式3为true执行代码
}else{
//如果以上条件表达式都不为true将执行代码
}
注:多重if选择结构常用于区间判断
嵌套if选择结构
if(条件表达式1) {
//如果条件表达式1的值为true执行代码
if(条件表达式2){
//如果条件表达式2的值为true执行代码
}else{
//如果条件表达式2的值为false执行代码
}
}else{
//如果条件表达式1的值为false执行代码
}
if-else使用说明
- 条件表达式必须是布尔表达式(关系表达式或逻辑表达式)、布尔变量
- 语句块只有一条执行语句时,一对
{}
可以省略,但建议保留
switch多选择结构
- 多选择结构还有一个实现方式就是
switch case
语句 - switch case语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支
int num = 6;
switch (num){
case 1:
//语句
break; //可选
case 2:
//语句
break; //可选
case 3:
//语句
break; //可选
case 4:
//语句
break; //可选
//可以有任意数量的case语句
default: //可选
break; //可选
}
switch语句有关规则:
- switch(表达式)中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举(jdk 5.0),String (jdk 7.0)
- case子句中的值必须是常量,不能是变量名或不确定的表达式值
- break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾
- default子句是可选的。同时,位置也是灵活的。当没有匹配的case时,执行default
注:switch常用于等值判断
凡是可以使用switch-case的,都可以改写为if-else。反之则不成立
Java随机数
通过Math.random()
来获取随机数。实际上,它返回的是0(包含)到1(不包含)之间的double值
public static void main(String[] args) {
// 随机生成三位随机数
for (int i = 0; i < 6; i++) {
// 公式:(最大 - 最小 + 1) + 最小
// 999 100
int number = (int) ((Math.random() * 999-100+1) + 100);
System.out.println(number);
}
}
3.3、循环结构
循环结构:在某些条件满足的情况下,反复执行特定代码的功能
循环语句的四个组成部分
- 初始化部分(init_statement)
- 循环条件部分(test_exp)
- 循环体部分(body_statement)
- 迭代部分(alter_statement)
循环语句分类
while 循环
while (布尔表达式){
// 循环体
}
- 只要布尔表达式为true,循环就会一直执行下去
- 大多数情况是会让循环停止下来的,此时需要一个让表达式失效的方式来结束循环
- 循环条件一直为true就会造成
无限循环[死循环]
,正常的业务编程中应该尽量避免死循环,会影响程序性能或者造成程序卡死崩溃!
do-while 循环
do {
// 代码语句
}while (布尔表达式);
- 对于while语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次
- do…while循环和while循环相似,不同的是,do…while 循环至少会执行一次
while和do…while的区别:
- while先判断后执行,do while是先执行后判断
- do…while总是保证循环体会被至少执行一次!这是他们的主要差别
for 循环
for (初始化;布尔表达式;更新迭代){
// 循环体
}
- for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构
- for循环执行的次数是在执行前就确定的。
for循环执行顺序:参数初始化–>条件判断–>循环体–>更新迭代变量
for (;;){
System.out.println("test"); // 死循环
}
foreach循环(SE5)
for(元素类型t 元素变量x : 数组或集合对象){
// 引用了x的java语句
}
增强for循环是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作
三大循环应用场景
- 循环次数确定的情况,通常选用for循环
- 循环次数不确定的情况,通常选用while或do-while循环
- foreach适用于只是进行集合或数组遍历,for则在较复杂的循环中效率更高
- foreach不能对数组或集合进行修改(添加删除操作),如果想要修改就要用for循环
3.4、break&continue
- break在任何循环语句的主体部分,均可用break控制循环的流程。break用于终止循环,不执行循环中剩余的语句。(break语句也在switch语句中使用)
- continue语句用在循环语句体中,用于跳出本次循环,进入下一次循环
3.5、二重循环
什么是二重循环?
- 二重循环顾名思义就是循环中嵌套另一个循环
- 在二重循环中,外层循环变量变化一次,内层循环变量要从初始值到结束值变化一遍(外层循环一次,内层循环一遍)
- break:跳出本层循环,continue:继续本层的下一轮循环
- **技巧:**从二维图形的角度看,外层循环控制
行数
,内层循环控制列数
- **开发经验:**实际开发中,最多见到的嵌套循环是两层。一般不会出现超过三层的嵌套循环。如果将要出现,一定要停下来重新梳理业务逻辑,重新思考算法的实现,控制在三层以内。否则,可读性会很差
图形打印:
// 打印5行直角三角形
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <=i ; j++) {
System.out.print("*");
}
System.out.println();
}
// 打印5行倒直角三角形
for (int i = 1; i <= 5; i++) {
for (int j = 5; j >= i; j--) {
System.out.print("*");
}
System.out.println();
}
// 打印九九乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
// 打印"菱形"
// 打印上半部分
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 10 - 2 * i; j++) {
System.out.print(" ");
}
for (int x = 1; x <= 2 * i - 1; x++) {
System.out.print("* ");
}
System.out.println();
}
// 下半部分
for (int i = 1; i <= 4; i++) {
// -
for (int j = 1; j <= 2 * i; j++) {
System.out.print(" ");
}
// *
for (int k = 1; k <= 9 - 2 * i; k++) {
System.out.print("* ");
}
System.out.println();
}
4、方法
4.1、什么是方法?
Java方法时语句的集合,它们在一起执行一个功能
- 方法是解决一类问题的步骤的有序组合
- 方法包含于类或对象中
- 方法在程序中被创建,在其他地方被引用
设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成1个功能,这样有利于后期的扩展
命名规则:驼峰命名
4.2、方法的定义
Java的方法类似于其它语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:
-
修饰符:这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
-
返回值类型:方法可能会返回值。returnValue Type是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值,在这种情况下,returnValue Type是关键字void
-
方法名:是方法的实际名称。方法名和参数表共同构成方法签名。(见名知意)
-
参数列表:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指参数的顺序和参数的个数。参数是可选的,可有可无可多个。(参数类型,参数名)
- 形式参数:在方法被调用时用于接收外界输入的数据。
- 实参: 调用方法时实际传给方法的数据。
方法体:方法体包含具体的语句,定义该方法的功能。
语法格式:
// [访问修饰符] 返回值类型 方法名 (参数类型 形式参数,参数类型 形式参数...){
...
// 方法体
...
return 返回值; // 作用: 结束方法、返回结果
}
注:
- 方法不调用就不执行
- 方法形参和实参传递的类型要一一对应
- return的返回值必须要跟返回值类型相同
4.3、方法调用
- 调用方法:对象名.方法名(实参列表)
- Java支持两种调用方法的方式,根据方法是否有返回值来选择
- 当方法返回一个值的时候,方法调用通常被当做一个值。例如:
int result = compare(5, 6);
如果方法返回值是void,方法调用一定是一条语句
4.4、方法的重载
在Java中,同一个类中的多个方法可以有相同的方法名称,但是有不同的参数列表,这就称为方法重载(method overloading)
方法的重载的规则
- 在同一个类中,方法名称必须相同
- 参数列表必须不同(参数的类型、参数的个数、参数的顺序)
- 与返回值、访问修饰符无关
- 仅仅返回类型不同不足以称为方法的重载
实现理论
方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错,这叫做重载分辨
4.5、可变参数
- JDK 1.5开始,Java支持传递同类型的可变参数给一个方法。
- 在方法声明中,在指定参数类型后加一个省略号(…)。
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明
public void getMax(double... number){
if (number.length == 0) {
System.out.println("No number");
return;
}
double result = number[0]; // 默认是第一个数是数组最大的值
for (int i = 1; i < number.length; i++) {
if (result < number[i]) {
result = number[i];
}
}
System.out.println("The Max is:" + result);
}
4.6、静态方法static(类方法)和 非静态方法(实例方法)的区别
静态变量:被static修饰的成员变量,叫做静态变量,被static修饰的成员方法,叫做静态方法
特点:被该类所有对象共享
- 调用对象、引用变量不同
- 静态方法,是使用static关键字修饰的方法,又叫类方法。属于类的,不属于对象。(静态属性,静态方法都是属于类的,所以可以直接通过类名调用)。
- 非静态方法,是不含有static关键字修饰的普通方法,又称为实例方法。属于对象的,不属于类的。(成员属性,成员方法是属于对象的,必须通过new关键字创建对象后,再通过对象调用)。
- 调用方法不同
- 静态方法可以直接调用,类名调用和对象调用。(类名.方法名 / 对象名.方法名)
但是非静态方法只能通过对象调用。(对象名.方法名)
- 静态方法可以直接调用,类名调用和对象调用。(类名.方法名 / 对象名.方法名)
- 生命周期不同
- 静态方法的生命周期跟相应的类一样长,静态方法和静态变量会随着类的定义而被分配和装载入内存中(随着类的加载而加载,优先于对象存在)。一直到线程结束,静态属性和方法才会被销毁。(也就是静态方法属于类)
- 非静态方法的生命周期和类的实例化对象一样长,只有当类实例化了一个对象,非静态方法才会被创建,而当这个对象被销毁时,非静态方法也马上被销毁。(也就是非静态方法属于对象)
总结:类方法可以直接通过类名调用,实例方法必需先实例化类,再初始化对象,然后通过类的实例对象才能调用
注:static可以用来修饰属性、方法和代码块
// 2.赋初值
{
System.out.println("匿名代码块");
}
// 1.只执行一次
static {
System.out.println("静态代码块");
}
// 3
public Pet() {
System.out.println("构造方法");
}
执行顺序:静态代码块–>匿名代码块–>构造方法
注:
- 静态方法只能访问静态变量和静态方法
- 非静态方法可以访问所有
- 静态方法中没有this关键字
局部变量和成员变量的区别和定义
局部变量 | 成员变量 | |
---|---|---|
定义位置 | 方法内。方法声明上(形参) | 类的内部,方法的外部 |
默认值 | 无默认值,使用前需要赋初值 | 有默认值,int 0、String null |
内存位置不同 | 栈内存 | 堆内存 |
声明周期不同 | 随着方法的调用而存在,随着方法的运行结束而消失 | 随着对象的创建而存在,随着对象的消失而消失 |
作用域 | 当前方法中有效 | 整个类中有效 |
5、数组
5.1、什么是数组?
- 数组是多个相同数据类型的有序集合
- 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
5.2、数组声明创建
必须先声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
int[] num; // 声明数组
num = new int[5]; // 分配空间 使用new操作符来创建数组
num[0] = 99; // 数组元素赋值
num[1] = 88;
num[2] = 77;
......
System.out.println(num[0]); // 使用,访问数组中第一个元素
// 声明数组并分配空间
int[] arr = new int[5];
arr[0] = 66; // 数组元素赋值
arr[1] = 77;
.....
// 声明数组分配空间并赋值
int[] arr2 = {55,66,77};
// 等同于==> int[] arr2 = new int[]{55,66,77}; // 不能指定数组长度
- 数组的元素是通过索引访问的,数组索引从0开始
- 获取数组长度:arrays.length
数组的基本特点:
- 其长度是确定的,数组一旦被创建,它的大小就是不可以改变的
- 其元素必须是相同类型,不允许出现混合类型
- 数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型
数组边界
下标的合法区间:[0,length-1]
数组长度是确定的,不可变的。如果越界,则报:ArrayIndexOutOfBoundsException:数组下标越界异常
5.3、三种初始化
静态初始化
除了用new关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值
String[] goods = {"鱼香肉丝", "宫保鸡丁", "手撕包菜","大盘鸡","烧茄子"};
动态初始化
数组定义与为数组元素分配空间并赋值的操作分开进行
int[] arr = new int[5];
arr[0] = 10;
arr[1] = 36;
arr[2] = 95;
arr[3] = 82;
默认初始化
- 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化
int[] arr = new int[5];
double[] db = new double[5];
boolean[] bool = new boolean[5];
char[] chars = new char[5];
String[] str = new String[5];
System.out.println(arr[0]); // 默认值 0
System.out.println(db[0]); // 默认值 0.0
System.out.println(bool[0]); // 默认值 false
System.out.println(chars[0]); // 0
System.out.println(str[0]); // 默认值 null
5.4、数组遍历
- 普通for循环
int[] arrays = {66, 11, 22, 55, 84, 85};
// 打印数组中的全部元素
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i] + "\t");
}
- for-each循环
// 没有下标 常用于遍历值
for (int num : arrays) {
System.out.print(num + "\t");
}
- 数组作方法参数
public static void printArrays(int[] arr) {
System.out.println("数组元素为:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
printArrays(arrays); // 调用显示数组元素方法
5.5、二维数组
什么是二维数组?
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其中每一个元素都是一个一维数组
二维数组的定义及使用
int[][] arrays = {{11, 22, 33}, {99, 88, 77}, {100, 200, 300}};
System.out.println(arrays[0][2]); // 33
System.out.println(arrays[1][0]); // 99
System.out.println(arrays[2][1]); // 200
/**
* 遍历二维数组
*/
for (int i = 0; i < arrays.length; i++) {
for (int j = 0; j < arrays[i].length; j++) {
System.out.print(arrays[i][j] + "\t");
}
}
小案例
// 使用二维数组,存储每个季度的营业额,并计算每个季度的营业额和全年营业额(单位:万)
double[][] turnover = {{12.5, 16.2, 18.5, 20}, {8.5, 9.6, 8.0, 10.6}, {16, 22.6, 17.2, 16.6}};
// 计算全年总营业额
double fillYearTurnover = 0.0;
for (int i = 0; i < turnover.length; i++) {
// 计算每个季度营业额
double seasonTurnover = 0.0;
for (int j = 0; j < turnover[i].length; j++) {
fillYearTurnover += turnover[i][j];
seasonTurnover += turnover[i][j];
}
System.out.println("第" + (i + 1) + "季度营业额为:" + seasonTurnover + "万元");
}
System.out.println("全年总营业额为:" + fillYearTurnover + "万元");
数组常见算法
数组元素反转
int[] arr = {95, 84, 32, 48, 36, 18, 35, 68, 89, 100};
System.out.println("交换之前:");
for (int i : arr) {
System.out.print(i + "\t");
}
// 方式一:
for (int i = 0; i < arr.length / 2; i++) {
// 交换 arr[i] 和 arr[arr.length - 1 - i]位置的元素
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
// 方式二:
// for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
// int temp = arr[i];
// arr[i] = arr[j];
// arr[j] = temp;
// }
System.out.println("\n交换之后:");
for (int i : arr) {
System.out.print(i + "\t");
}
查找指定元素在数组中的索引位置(线性查找)
int[] arr = {64, 949, 94, 36, 494, 87, 65, 99};
int findEle = 36;
boolean flag = true;
for (int i = 0; i < arr.length; i++) {
if (findEle == arr[i]) {
flag = false;
System.out.println("找到了" + findEle + ",索引为:" + i);
break;
}
}
if (flag){
System.out.println("没有找到你需要的数值");
}
查找指定元素在数组中的索引位置(二分查找)
// 二分法查找:要求数组必须是有序的
int[] arr = new int[]{0, 2, 8, 33, 43, 256, 566,867};
int target = 256;
int head = 0; // 默认首索引
int end = arr.length - 1; // 默认尾索引
boolean flag = false; // 判断是否找到了指定元素
while (head <= end) {
int middle = (head + end) / 2;
if (target == arr[middle]) {
System.out.println("找到了" + target + "对应索引为:" + middle);
flag = true;
break;
} else if (target > arr[middle]) {
head = middle + 1;
} else {
head = middle - 1;
}
}
if (!flag) {
System.out.println("未找到你想要的元素");
}
冒泡排序
public static void main(String[] args) {
int[] arr = {46, 2, 816, 494, 16, 84, 31, 99, 91, 15};
int[] sortArr = bubbleSort(arr);
for (int i : sortArr) {
System.out.print(i + "\t");
}
}
public static int[] bubbleSort(int[] sortArr) {
for (int i = 0; i < sortArr.length - 1; i++) {
boolean flag = true; // 默认已经排好序
// 内层循环,比较判断两个数,如果第一个数比第二个数大,则交换位置
for (int j = 0; j < sortArr.length - 1 - i; j++) {
if (sortArr[j] > sortArr[j + 1]) {
int temp = sortArr[j];
sortArr[j] = sortArr[j + 1];
sortArr[j + 1] = temp;
flag = false; // 如果元素发生了交换,那么说明数组还没有排好序
}
}
if (flag) {
break; // 如果flag依然为true,说明已经排好序,可以提前终止循环,从而减少比较次数和交换次数,提高排序效率
}
}
return sortArr;
}
5.6、Arrays工具类
Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用
int[] arr1 = {99, 88, 77, 66, 55};
int[] arr2 = {99, 88, 77, 66, 55};
boolean flag = Arrays.equals(arr1, arr2); // 比较两个数组中的值是否相等
System.out.println("flag = " + flag); // true
System.out.println(Arrays.toString(arr1)); // 输出数组元素信息
Arrays.sort(arr1); // 使用排序算法快速排序(升序)
System.out.println(Arrays.toString(arr1));
Arrays.fill(arr2, 66); // 将指定值填充到数组中
System.out.println(Arrays.toString(arr2)); // arr2数组中值全部为66
// (二分查找) 前提条件:传递的数组必须是有序的
int index = Arrays.binarySearch(arr1, 88);
System.out.println("index = " + index); // 3
int[] originArr = {100, 200, 300, 600, 700};
// 将指定数组的指定范围复制到新数组中
int[] copyRangeArr = Arrays.copyOfRange(originArr, 3, originArr.length);
System.out.println(Arrays.toString(copyRangeArr)); // [600,700]
5.7、内存分析
Java内存分析
堆
- 存放对象和数组,new出来的,都存储在堆内存
- 可以被所有的线程共享,不会存放别的对象引用
栈
- 存放基本变量类型(包含这个基本类型的具体数值)
- 引用对象的变量(会存放引用在堆里面的具体地址值)
方法区
- 可以被所有的线程共享
- 包含了所有的class和static变量
5.8、基本数据类型与引用数据类型
- 基本数据类型:数据值是存储在自己的空间中
- 特点:赋值给其他变量,也是赋的真实的值
- 引用数据类型:数据值是存储在其他空间中(堆),自己空间中存储的是地址值
- 特点:赋值给其他变量,赋的地址值