第一章 Java概述
1.1 Java历史
Java诞生于SUN(Stanford University Network),09年SUN被Oracle(甲骨文)收购。
Java之父是詹姆斯.高斯林(James Gosling)。
1996年发布JDK1.0版。
1.2 Java语言最主要的特点
- 特点一:面向对象
两个基本概念:类、对象
三大特性:封装、继承、多态
- 特点二:健壮性
吸收了C/C++语言的优点,但去掉了其影响程序健壮性的部分(如指针、内存的申请与释放等),提供了一个相对安全的内存管理和访问机制
- 特点三:跨平台性
跨平台性:通过Java语言编写的应用程序在不同的系统平台上都可以运行。“Write once , Run Anywhere”一次编写,处处运行。
原理:只要在需要运行 java 应用程序的操作系统上,先安装一个Java虚拟机 (JVM Java Virtual Machine) 即可。由JVM来负责Java程序在该系统中的运行。因为有了JVM,同一个Java 程序在三个不同的操作系统中都可以执行。这样就实现了Java 程序的跨平台性。
1.3 Java环境搭建
1.3.1 JDK、JRE、JVM
Java开发人员需要安装JDK。如果仅仅是运行Java程序,那么只需要按照JRE。
JDK(Java Development kits):Java开发工具包。
JRE(Java Runtime Environment):Java运行环境。
JVM(Java Virtual Machine):Java虚拟机。
JDK = JRE + 开发工具(javac.exe,java.exe,javadoc.exe等)
JRE = JVM + 核心类库(常用类:String、日期时间、数学、集合、IO、网络、多线程等)
1.3.2 Java环境搭建
1、安装JDK
2、配置JDK的开发工具目录到path环境变量中
例如:D:\ProgramFiles\Java\jdk1.8.0_51\bin;
注意:这个安装目录以你自己的安装目录为准
(1)为什么配置path?
希望在命令行使用javac.exe等工具时,任意目录下都可以找到这个工具所在的目录。
(2)如何配置环境变量?
【计算机】右键【属性】,选择【高级系统设置】,选择【高级】,选择【环境变量】,选择【系统环境变量】,编辑path,在【path原有值】的前面加入D:\ProgramFiles\Java\jdk1.8.0_51\bin;
1.4 第一个Java应用程序
class HelloWorld{
public static void main(String[] args){
System.out.print("Hello Java!");
}
}
1.4.1 Java程序的开发步骤
三步:
1、编辑/编写源代码
要求:源文件必须是.java文件
2、编译
目的:把源文件编译为.class字节码文件(因为JVM只认识字节码)
工具:javac.exe
格式:
javac 源文件名.java
3、运行
工具:java.exe
格式:
java 类名
java 字节码文件名
要求:可以被运行的类,必须包含main方法
1.4.2 Java程序的结构与格式
结构:
类{
方法{
语句;
}
}
格式:
(1)每一级缩进一个Tab键
(2){}的左半部分在行尾,右半部分单独一行,与和它成对的"{"的行首对齐
1.4.3 Java程序的入口
Java程序的入口是main方法
public static void main(String[] args){
}
1.4.4 Java注释
1、单行注释
//注释内容
2、多行注释
/*
注释内容
*/
3、文档注释
/**
文档注释(后面注解部分讲解)
*/
1.5 编写Java程序时应该注意的问题
1、字符编码问题
当cmd命令行窗口的字符编码与.java源文件的字符编码不一致,如何解决?
解决方案一:
在Notepad++等编辑器中,修改源文件的字符编码
解决方案二:
在使用javac命令式,可以指定源文件的字符编码
javac -encoding utf-8 Review01.java
2、大小写问题
(1)源文件名:
不区分大小写,我们建议大家还是区分
(2)字节码文件名与类名
区分大小写
(3)代码中
区分大小写
3、源文件名与类名一致问题?
(1)源文件名是否必须与类名一致?public呢?
如果这个类不是public,那么源文件名可以和类名不一致。
如果这个类是public,那么要求源文件名必须与类名一致。
我们建议大家,不管是否是public,都与源文件名保持一致,而且一个源文件尽量只写一个类,目的是为了好维护。
(2)一个源文件中是否可以有多个类?public呢?
一个源文件中可以有多个类,编译后会生成多个.class字节码文件。
但是一个源文件只能有一个public的类。
(3)main必须在public的类中吗?
不是。
但是后面写代码时,基本上main习惯上都在public类中。
第二章 Java的基础语法
2.1 标识符
简单的说,凡是程序员自己命名的部分都可以称为标识符。
即给类、变量、方法、包等命名的字符序列,称为标识符。
1、标识符的命名规则
(1)Java的标识符只能使用26个英文字母大小写,0-9的数字,下划线_,美元符号$
(2)不能使用Java的关键字(包含保留字)和特殊值
(3)数字不能开头
(4)不能包含空格
(5)严格区分大小写
2、标识符的命名规范
(1)见名知意
(2)类名、接口名等:每个单词的首字母都大写,形式:XxxYyyZzz,
例如:HelloWorld,String,System等
(3)变量、方法名等:从第二个单词开始首字母大写,其余字母小写,形式:xxxYyyZzz,
例如:age,name,bookName,main
(4)包名等:每一个单词都小写,单词之间使用点.分割,形式:xxx.yyy.zzz,
例如:java.lang
(5)常量名等:每一个单词都大写,单词之间使用下划线_分割,形式:XXX_YYY_ZZZ,
例如:MAX_VALUE,PI
2.2 变量
2.2.1 变量的概念
变量的作用:用来存储数据,代表内存的一块存储区域,变量中的值是可以改变的。
2.2.2 变量的三要素
1、数据类型
2、变量名
3、值
2.2.3 变量的使用应该注意什么?
1、先声明后使用
如果没有声明,会报“找不到符号”错误
2、在使用之前必须初始化
如果没有初始化,会报“未初始化”错误
3、变量有作用域
如果超过作用域,也会报“找不到符号”错误
4、在同一个作用域中不能重名
2.2.4 变量的声明和赋值、使用的语法格式?
1、变量的声明的语法格式:
数据类型 变量名;
例如:
int age;
String name;
double weight;
char gender;
boolean isMarry;
2、变量的赋值的语法格式:
变量名 = 值;
例如:
age = 18;
name = "柴林燕"; //字符串的值必须用""
weight = 44.4;
gender = '女';//单字符的值必须使用''
isMarry = true;
3、变量的使用的语法格式:
通过变量名直接引用
例如:
(1)输出变量的值
System.out.print(name);
System.out.print("姓名:" + name);//""中的内容会原样显示
System.out.print("name = " + name);
(2)计算
age = age + 1;
2.3 数据类型
2.3.1 Java数据类型的分类
1、基本数据类型
8种:整型系列(byte,short,int,long)、浮点型(float,double)、单字符型(char)、布尔型(boolean)
2、引用数据类型
类、接口、数组、枚举…
2.3.2 Java的基本数据类型
1、整型系列
(1)byte:字节类型
占内存:1个字节
存储范围:-128~127
(2)short:短整型类型
占内存:2个字节
存储范围:-32768~32767
(3)int:整型
占内存:4个字节
存储范围:-2的31次方 ~ 2的31次方-1
(4)long:整型
占内存:8个字节
存储范围:-2的63次方 ~ 2的63次方-1
注意:如果要表示某个常量数字它是long类型,那么需要在数字后面加L
2、浮点型系列(小数)
(1)float:单精度浮点型
占内存:4个字节
精度:科学记数法的小数点后6~7位
注意:如果要表示某个常量数字是float类型,那么需要在数字后面加F或f
(2)double:双精度浮点型
占内存:8个字节
精度:科学记数法的小数点后15~16位
3、单字符类型
char:字符类型
占内存:2个字节
Java中使用的字符集:Unicode编码集
字符的三种表示方式:
(1)‘一个字符’
例如:‘A’,‘0’,‘尚’
(2)转义字符
\n:换行
\r:回车
\t:Tab键
\\:\
\":”
\':
\b:删除键Backspace
(3)\u字符的Unicode编码值的十六进制型
例如:\u5c1a代表’尚’
4、布尔类型
boolean:只能存储true或false
2.3.3 进制(了解,可以暂时忽略)
1、进制的分类:
(1)十进制
数字组成:0-9
进位规则:逢十进一
(2)二进制
数字组成:0-1
进位规则:逢二进一
(3)八进制
数字组成:0-7
进位规则:逢八进一
(4)十六进制
数字组成:0-9,af(或AF)
进位规则:逢十六进一
2、请分别用四种类型的进制来表示10,并输出它的结果:(了解)
(1)十进制:正常表示
System.out.println(10);
(2)二进制:0b或0B开头
System.out.println(0B10);
(3)八进制:0开头
System.out.println(010);
(4)十六进制:0x或0X开头
System.out.println(0X10);
3、为什么byte是-128~127?(理解)
1个字节:8位
0000 0001 ~ 0111 111 ==> 1~127
1000 0001 ~ 1111 1111 ==> -127 ~ -1
0000 0000 ==>0
1000 0000 ==> -128(特殊规定)
*解释:*计算机数据的存储(了解)
计算机数据的存储使用二进制补码形式存储,并且最高位是符号位,1是负数,0是正数。
规定:正数的补码与反码、原码一样,称为三码合一;
负数的补码与反码、原码不一样:
负数的原码:把十进制转为二进制,然后最高位设置为1
负数的反码:在原码的基础上,最高位不变,其余位取反(0变1,1变0)
负数的补码:反码+1
例如:byte类型(1个字节,8位)
25 ==> 原码 0001 1001 ==> 反码 0001 1001 -->补码 0001 1001
-25 ==>原码 1001 1001 ==> 反码1110 0110 ==>补码 1110 0111
底层是用加法代替减法:-128==》-127-1==》-127+(-1)
-127- -1 ==> -127 + 1
4、学生疑惑解答?
(1)为什么float(4个字节)比long(8个字节)的存储范围大?
(2)为什么double(8个字节)比float(4个字节)精度范围大?
因为float、double底层也是二进制,先把小数转为二进制,然后把二进制表示为科学记数法,然后只保存:
(1)符号位(2)指数位(3)尾数位
2.3.4 基本数据类型的转换
1、自动类型转换
(1)当把存储范围小的值(常量值、变量的值、表达式计算的结果值)赋值给了存储范围大的变量时,
byte->short->int->long->float->double
char->
int i = 'A';//char自动升级为int
double d = 10;//int自动升级为double
(2)当存储范围小的数据类型与存储范围大的数据类型一起混合运算时,会按照其中最大的类型运算
int i = 1;
byte b = 1;
double d = 1.0;
double sum = i + b + d;//混合运算,升级为double
(3)当byte,short,char数据类型进行算术运算时,按照int类型处理
byte b1 = 1;
byte b2 = 2;
byte b3 = (byte)(b1 + b2);//b1 + b2自动升级为int
char c1 = '0';
char c2 = 'A';
System.out.println(c1 + c2);//113
(4)boolean类型不参与
2、强制类型转换
(1)当把存储范围大的值(常量值、变量的值、表达式计算的结果值)赋值给了存储范围小的变量时,需要强制类型转换
double->float->long->int->short->byte
->char
提示:有风险,可能会损失精度或溢出
double d = 1.2;
int num = (int)d;//损失精度
int i = 200;
byte b = (byte)i;//溢出
(2)boolean类型不参与
(3)当某个值想要提升数据类型时,也可以使用强制类型转换
int i = 1;
int j = 2;
double shang = (double)i/j;
提示:这个情况的强制类型转换是没有风险的。
2.3.5 特殊的数据类型转换
1、任意数据类型的数据与String类型进行“+”运算时,结果一定是String类型
System.out.println("" + 1 + 2);//12
2、但是String类型不能通过强制类型()转换,转为其他的类型
String str = "123";
int num = (int)str;//错误的
2.4 运算符
1、按照操作数个数的分类:
(1)一元运算符:操作数只有一个
例如:正号(+),负号(-),自增(++),自减(–),逻辑非(!),按位取反(~)
(2)二元运算符:操作数有两个
例如:加(+),减(-),乘(*),除(/),模(%)
大于(>),小于(<),大于等于(>=),小于等于(<=),等于(==),不等于(!=)
赋值(=,+=,-=,*=,/=,%=,>>=,<<=。。。)
逻辑与(&),逻辑或(|),逻辑异或(^),短路与(&&),短路或(||)
左移(<<),右移(>>),无符号右移(>>>),按位与(&),按位或(|),按位异或(^)
(3)三元运算符:操作数三个
例如: ? :
2、Java基本数据类型的运算符:
(1)算术运算符
(2)赋值运算符
(3)比较运算符
(4)逻辑运算符
(5)条件运算符
(6)位运算符(难)
2.4.1 算术运算符
加法:+
减法:-
乘法:*
除法:/
注意:整数与整数相除,只保留整数部分
取模:% 取余
注意:取模结果的正负号只看被模数
正号:+
负号:-
自增:++
自减:–
原则:自增与自减
++/–在前的,就先自增/自减,后取值
++/–在后的,就先取值,后自增/自减
整个表达式的扫描,是从左往右扫描,如果后面的先计算的,那么前面的就暂时先放到“操作数栈”中
代码示例:
int i = 1;
i++;//i=2
int j = 1;
++j;//j=2
int a = 1;
int b = a++;//(1)先取a的值“1”放操作数栈(2)a再自增,a=2(3)再把操作数栈中的"1"赋值给b,b=1
int m = 1;
int n = ++m;//(1)m先自增,m=2(2)再取m的值“2”放操作数栈(3)再把操作数栈中的"2"赋值给n,n=1
int i = 1;
int j = i++ + ++i * i++;
/*
从左往右加载
(1)先算i++
①取i的值“1”放操作数栈
②i再自增 i=2
(2)再算++i
①i先自增 i=3
②再取i的值“3”放操作数栈
(3)再算i++
①取i的值“3”放操作数栈
②i再自增 i=4
(4)先算乘法
用操作数栈中3 * 3 = 9,并把9压会操作数栈
(5)再算求和
用操作数栈中的 1 + 9 = 10
(6)最后算赋值
j = 10
*/
2.4.2 赋值运算符
基本赋值运算符:=
扩展赋值运算符:+=,-=,*=,/=,%=…
注意:所有的赋值运算符的=左边一定是一个变量
扩展赋值运算符=右边的计算结果的类型如果比左边的大的话会强制类型转换,所以结果可能有风险。
扩展赋值运算符的计算:(1)赋值最后算(2)加载数据的顺序是把左边的变量的值先加载,再去与右边的表达式进行计算
int i = 1;
int j = 5;
j *= i++ + j++;//j = j *(i++ + j++);
/*
(1)先加载j的值“5”
(2)在计算i++
①先加载i的值“1”
②再i自增,i=2
(3)再计算j++
①先加载j的值"5"
②再j自增,j=6
(4)算 加法
i + 5 = 6
(5)算乘法
5 * 6 = 30
(6)赋值
j = 30
*/
2.4.3 比较运算符
大于:>
小于:<
大于等于:>=
小于等于:<=
等于:== 注意区分赋值运算符的=
不等于:!=
注意:比较表达式的运算结果一定只有true/false
比较表达式可以作为(1)条件(2)逻辑运算符的操作数
2.4.4 逻辑运算符
逻辑运算符的操作数必须是布尔值,结果也是布尔值
逻辑与:&
运算规则:只有左右两边都为true,结果才为true。
例如:true & true 结果为true
false & true 结果为false
true & false 结果为false
false & false 结果为false
逻辑或:|
运算规则:只要左右两边有一个为true,结果就为true。
例如:true | true 结果为true
false | true 结果为true
true | false 结果为true
false | false 结果为false
逻辑异或:^
运算规则:只有左右两边不同,结果才为true。
例如:true ^ true 结果为false
false ^ true 结果为true
true ^ false 结果为true
false ^ false 结果为false
逻辑非:!
运算规则:布尔值取反
例如:!true 为false
!false 为true
短路与:&&
运算规则:只有左右两边都为true,结果才为true。
例如:true & true 结果为true
true & false 结果为false
false & ? 结果就为false
它和逻辑与不同的是当&&左边为false时,右边就不看了。
短路或:||
运算规则:只要左右两边有一个为true,结果就为true。
例如:true | ? 结果为treu
false | true 结果为true
false | false 结果为false
它和逻辑或不同的是当||左边为true时,右边就不看了。
开发中一般用短路与和短路或比较多
面试题:&& 和 &的区别?
&&当左边为false,右边不计算
&不管左边是true还是false,右边都要计算
2.4.5 条件运算符
? :
语法格式:
条件表达式 ? 结果表达式1 : 结果表达式2
运算规则:
整个表达式的结果:当条件表达式为true时,就取结果表达式1的值,否则就取结果表达式2的值
代码示例:
(1)boolean类型
boolean marry = true;
System.out.println(marry? "已婚" : "未婚");
(2)求最值
int i = 3;
int j = 5;
int max = i>=j ? i : j;
//当i>=j时,max就赋值为i的值,否则就赋值为j的值
2.4.6 位运算符
左移:<<
运算规则:左移几位就相当于乘以2的几次方
右移:>>
运算规则:右移几位就相当于除以2的几次方
无符号右移:>>>
运算规则:往右移动后,左边空出来的位直接补0,不看符号位
按位与:&
运算规则:
1 & 1 结果为1
1 & 0 结果为0
0 & 1 结果为0
0 & 0 结果为0
按位或:|
运算规则:
1 | 1 结果为1
1 | 0 结果为1
0 | 1 结果为1
0 & 0 结果为0
按位异或:^
运算规则:
1 ^ 1 结果为0
1 ^ 0 结果为1
0 ^ 1 结果为1
0 ^ 0 结果为0
按位取反:~
运算规则:~0就是1
~1就是0
如何区分&,|,^是逻辑运算符还是位运算符?
如果操作数是boolean类型,就是逻辑运算符,如果操作数是整数,那么就位运算符。
2.4.7 运算符优先级
提示说明:
(1)表达式不要太复杂
(2)先算的使用()
2.4.8 运算符操作数类型说明
1、算术运算符
数字和单个字符可以使用算术运算符。
其中+,当用于字符串时,表示拼接。
2、赋值运算符
右边的常量值、表达式的值、变量的值的类型必须与左边的变量一致或兼容(可以实现自动类型转换)或使用强制类型转换可以成功。
3、比较运算符
其他的比较运算符都是只能用于8种基本数据类型。
其中的==和!=可以用于引用数据类型的比较,用于比较对象的地址。(后面讲)
int i = 10;
int j = 10;
System.out.println(i==j);//true
char c1 = '帅';
char c2 = '帅';
System.out.println(c1 == c2);//true
4、逻辑运算符
逻辑运算符的操作数必须是boolean值
5、条件运算符
?前面必须是条件,必须是boolean值
结果表达式1和结果表达式2要保持类型一致或兼容
6、位运算符
一般用于整数系列
以上运算符都是针对基本数据类型设计的。
能够用于引用数据类型只有基本的赋值运算符=,和比较运算符中的==和!=。其他运算符都不能用于引用数据类型。
其中字符串类型还有一个+,表示拼接。
第三章 流程控制语句结构
流程控制语句结构分为:
1、顺序结构:从上到下依次执行
2、分支结构:多个分支选择其中一个分支执行
3、循环结构:重复执行某些代码
3.1 顺序结构
执行过程:从上到下顺序执行
3.1.1 输出语句
1、System.out.print(输出内容); #输出内容后不换行
2、System.out.println(输出内容); #输出内容后换行
#输出常量
System.out.print(1);
System.out.print('尚');
System.out.print(44.4);
System.out.print(true);
System.out.print("尚硅谷");
#输出变量
int a = 1;
char c = '尚';
double d = 44.4;
boolean b = true;
String school = "尚硅谷";
System.out.print(a);
System.out.print(c);
System.out.print(d);
System.out.print(b);
System.out.print(school);
#输出拼接结果
System.out.print("a = " + a);
System.out.print("c = " + c);
System.out.print("d = " + d);
System.out.print("b = " + b);
System.out.print("school = " + school);
3.1.2 输入语句
键盘输入代码的三个步骤:
1、准备Scanner类型的变量
2、提示输入xx
3、接收输入内容
示例代码:
//1、准备Scanner类型的变量
java.util.Scanner input = new java.util.Scanner(System.in);//System.in默认代表键盘输入
//2、提示输入xx
System.out.print("请输入一个整数:");
//3、接收输入内容
int num = input.nextInt();
//列出各种数据类型的输入
int num = input.nextInt();
long bigNum = input.nextLong();
double d = input.nextDouble();
boolean b = input.nextBoolean();
String s = input.next();
char c = input.next().charAt(0);//先按照字符串接收,然后再取字符串的第一个字符(下标为0)
3.2 分支结构
分支结构:根据条件选择性的执行某些代码
分为:
1、条件判断:if…else系列
2、选择结构:switch…case系列
3.2.1 条件判断
1、单分支结构
语法格式:
if(条件表达式){
当条件表达式成立(true)时需要执行的语句块;
}
执行过程:
条件成立,就执行{}其中的语句块,不成立就不执行。
注意:
(1)if(条件表达式)中的条件表达式的结果必须是boolean类型
(2)当{}中的语句只有一个语句(简单的语句,也可以是一个复合语句)时,可以省略{},但是我们不建议省略
//省略{}的情况
if(score<0 || score>100)
System.out.println("输入有误!");//简单的语句
else
//复合语句
if(score==100){
System.out.println("满分");
}else if(score>=80){
System.out.println("优秀");
}else if(score>=60){
System.out.println("及格");
}else{
System.out.println("不及格");
}
示例代码:
int year = 2019;
int days = 28;
if(year%4==0 && year%100!=0 || year%400==0){
days= 29;
}
2、双分支结构
语法格式:
if(条件表达式){
当条件表达式成立(true)时需要执行的语句块1;
}else{
当条件表达式不成立(false)时需要执行的语句块2;
}
执行过程:
当条件表达式成立(true)时执行语句块1,否则执行语句块2
注意:
(1)if(条件表达式)中的条件表达式的结果必须是boolean类型
(2)当{}中的语句只有一个语句(简单的语句,也可以是一个复合语句)时,可以省略{},但是我们不建议
示例代码:
int num = 10;
if(num%2==0){
System.out.println(num + "是偶数");
}else{
System.out.println(num + "是奇数");
}
3、多分支结构
语法格式:
if(条件表达式1){
当条件表达式1成立的时候,执行的语句块1;
}else if(条件表达式2){
当条件表达式1不成立,
条件表达式2成立的时候,执行的语句块2;
}else if(条件表达式3){
当条件表达式1不成立,
条件表达式2也不成立,
条件表达式3成立的时候,执行的语句块3;
}
。。。
【else{
当以上所有的条件表达式都不成立,需要执行的语句块n+1;
}】
执行过程:
(1)多个条件顺序往下判断,如果上面有一个条件成立了,下面的条件就不看了
(2)多个分支也只会执行其中的一个
注意:
(1)每一个条件表达式都必须是boolean值
(2)当{}中只有一个语句时,也可以省略{},但不建议省略
(3)当多个条件是“互斥”关系(没有重叠部分),顺序可以随意;
当多个条件是“包含”关系(有重叠部分),顺序不能随意,小的在上,大的在下面
示例代码:
int score = 78;
if(score==100){
System.out.println("满分");
}else if(score>=80){
System.out.println("优秀");
}else if(score>=60){
System.out.println("及格");
}else{
System.out.println("不及格");
}
4、嵌套
执行过程:
当嵌套在if中,就是当外面的if成立时,才会看里面的条件判断;
当嵌套在else中,就当外面的else满足时,才会看里面的条件判断;
3.2.2 选择结构
语法格式:
switch(表达式){
case 常量值1:
语句块1;
【break;】
case 常量值2:
语句块2;
【break;】
。。。
【default:
语句块n+1;
【break;】
】
}
执行过程:
(1)入口
①当switch(表达式)的值与case后面的某个常量值匹配,就从这个case进入;
②当switch(表达式)的值与case后面的所有常量值都不匹配,寻找default分支进入;
(2)一旦从“入口”进入switch,就会顺序往下执行,直到遇到“出口”
(3)出口
①自然出口:遇到了switch的结束}
②中断出口:遇到了break等
注意:
(1)switch(表达式)的值的类型,只能是:4种基本数据类型(byte,short,int,char),两种引用数据类型(枚举、String)
(2)case后面必须是常量值,而且不能重复
示例代码:
int month = 4;
switch(month){
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;
case 12:
case 1:
case 2:
System.out.println("冬季");
break;
default:
System.out.println("输入有误!");
}
3.3 循环结构
循环结构:
“重复”执行某些代码
循环结构的分类:
1、for循环
2、while循环
3、do…while循环
3.3.1 for循环
语法格式:
for(;;){
循环体语句块;
if(条件表达式){
break;
}
}
for(初始化表达式; 循环条件; 迭代表达式){
循环体语句块;(需要重复执行的代码)
}
执行过程:
(1)初始化表达式;
(2)判断循环条件;
(3)如果循环条件成立,先执行循环体语句块;然后执行迭代表达式,再回到(2)…
(4)如果循环条件不成立,会结束for;
或者在当前循环中遇到break语句,也会结束当前for循环;
注意:
(1)for(;;)中的两个;是不能多也不能少
(2)循环条件必须是boolean类型
示例代码:
//遍历1-100之间的偶数
for(int i=1; i<=100; i++){//每次循环的步幅是1
if(i%2==0){
System.out.println(i);
}
}
//遍历1-100之间的偶数
for(int i=2; i<=100; i+=2){//每次循环的步幅是2
System.out.println(i);
}
3.3.2 while循环
语法格式:
while(循环条件){
循环体语句块;
}
经典的形式:
while(true){
循环体语句块;
if(条件表达式){
break;
}
}
执行过程:
(1)先判断循环条件
(2)如果循环条件成立,就执行循环体语句块;然后回到(1)
(3)如果循环条件不成立,就结束while循环;
如果在循环体语句块中,遇到break,也会结束while循环;
注意:
(1)while(循环条件)中循环条件必须是boolean类型
示例代码:
//遍历1-100之间的偶数
int num = 2;
while(num<=100){
System.out.println(num);
num+=2;
}
3.3.3 do…while循环
语法格式:
do{
循环体语句块;
}while(循环条件);
执行过程:
(1)先执行一次循环体语句块;
(2)判断循环条件
(3)如果循环条件成立,再次执行循环体语句块;然后回到(2)…
(4)如果循环条件不成立,就结束do…while循环;
如果在循环体语句块中,遇到break,也会结束do…while循环;
注意:
(1)while(循环条件)中循环条件必须是boolean类型
(2)do{}while();最后有一个分号
(3)do…while结构的循环体语句是至少会执行一次,这个和for和while是不一样的
示例代码:
//从键盘输入整数,统计正数、负数的个数,输入0结束
java.util.Scanner input = new java.util.Scanner(System.in);
int num;
int positive = 0;
int negative = 0;
do{
System.out.print("请输入整数(0结束):");
num = input.nextInt();
if(num > 0){
positive++;
}else if(num < 0){
negatvie++;
}
}while(num!=0);
System.out.println("正数的个数:" + positive);
System.out.println("负数的个数:" + negatvie);
3.3.4 三种循环的选择
原则:三种循环之间是可以互相转换的,都能实现循环的功能
建议(习惯上):当我们次数比较明显的时候,或者说从几循环到几的时候,一般先考虑for;
当循环体语句块至少要执行一次的时候,一般先考虑do…while;
当循环条件比较明显,但是次数不明显,循环体语句块也不是至少执行一次,那么可以考虑while结构;
三种循环结构都具有四要素:
(1)循环变量的初始化表达式
(2)循环条件
(3)循环变量的修改的迭代表达式
(4)循环体语句块
3.3.5 跳转语句
1、break
用于:
(1)switch结构
作用:结束switch结构
(2)循环结构
作用:结束当前循环
2、continue
用于:
只能用于循环结构
作用:提前结束本次循环,继续下一次循环
3、return(后面讲)
第四章 数组
4.1 数组的相关概念和名词(了解)
1、数组(array):
一组具有相同数据类型的数据的按照一定顺序排列的集合。
把有限的几个相同类型的变量使用一个名称来进行统一管理。
2、数组名:
(1)这个数组名,代表的是一组数
(2)这个数组名中存储的整个数组的“首地址”
3、下标(index):
我们使用编号、索引、下标来区别表示一组数当中某一个。
范围:[0,数组长度-1]
例如:for(int i = 0; i<arr.length; i++){}
4、元素(element):
这一组中的的每一个数据都是元素。
如何表示数组元素? 数组名[下标]
5、数组的长度(length)
数组中元素的总个数。
如何获取数组长度? 数组名.length
注意:名称是为了沟通的方便,概念不用一字不落背下来
4.2 数组的相关语法
4.2.1 数组的声明
语法格式:
//推荐
元素的数据类型[] 数组名;
//也对,但是不推荐
元素的数据类型 数组名[];
示例:
//要存储一组整数
int[] array;
//要存储一组单字符
char[] array;
//要存储一组字符串
String[] array;
4.2.2 数组的初始化
初始化的目的:(1)确定数组的长度(2)为元素赋值
两种初始化方式:
1、动态初始化
语法格式:
//指定数组长度
数组名 = new 元素的数据类型[长度];
//为元素赋值
数组名[下标] = 值; //这个值可以是个常量值,也可以是个表达式的计算结果,也可以是键盘输入的
//如果每个元素的赋值比较有规律,通常使用for循环赋值
for(int i=0; i<长度; i++){
数组名[下标] = 值;
}
问:如果只指定数组长度,没有为元素手动赋值,那么元素有值吗?
有默认值
(1)基本数据类型
byte,short,int,long:0
float,double:0.0
char:\u0000
boolean:false
(2)引用数据类型
统统都是null
2、静态初始化
语法格式:
数组名 = new 元素的数据类型[]{值列表};
//int[] arr = new int[5]{1,2,3,4,5};//错误的
//更简洁
//当声明与静态初始化一起完成时,可以简化
元素的数据类型[] 数组名 = {值列表};
适用场合:
当数组的元素是已知的有限个时,可以使用静态初始化。
示例代码:
String[] weeks = {"monday","tuesday","wednesday","thursday","friday","saturday","sunday"};
int[] daysOfMonths = {31,28,31,30,31,30,31,31,30,31,30,31};
char[] letters = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
4.2.3 数组的遍历
for循环遍历数组:
for(int i=0; i<数组名.lenght; i++){
//或赋值
数组名[i] = 值;
//或显示
System.out.println(数组名[i]);
//或其他操作
//例如:判断是否是偶数
if(数组名[i]%2==0){
//...
}
}
4.2.4 数组的内存分析
元素是基本数据类型的一维数组内存分析:
int[] arr = {1,2,3,4,5};
int[] arr = new int[5];
for(int i=0; i<arr.length; i++){
arr[i] = i+1;
}
4.3 数组的相关算法
4.3.1 数组找最值
1、数组中找最值
思路:
(1)先假设第一个元素最大/最小
(2)然后用max/min与后面的元素一一比较
示例代码:
int[] arr = {4,5,6,1,9};
//找最大值
int max = arr[0];
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
2、数组中找最值及其下标
情况一:找最值及其第一次出现的下标
思路:
(1)先假设第一个元素最大/最小
(2)然后用max/min与后面的元素一一比较
示例代码:
int[] arr = {4,5,6,1,9};
//找最大值
int max = arr[0];
int index = 0;
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
index = i;
}
}
或
int[] arr = {4,5,6,1,9};
//找最大值
int maxIndex = 0;
for(int i=1; i<arr.length; i++){
if(arr[i] > arr[maxIndex]){
maxIndex = i;
}
}
System.out.println("最大值:" + arr[maxIndex]);
情况二:找最值及其所有最值的下标(即可能最大值重复)
思路:
(1)先找最大值
①假设第一个元素最大
②用max与后面的元素一一比较
(2)遍历数组,看哪些元素和最大值是一样的
示例代码:
int[] arr = {4,5,6,1,9};
//找最大值
int max = arr[0];
for(int i=1; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
//遍历数组,看哪些元素和最大值是一样的
for(int i=0; i<arr.length; i++){
if(max == arr[i]){
System.out.print(i+"\t");
}
}
4.3.2 数组统计:求总和、均值、统计偶数个数等
思路:遍历数组,挨个的累加,判断每一个元素
示例代码:
int[] arr = {4,5,6,1,9};
//求总和、均值
int sum = 0;//因为0加上任何数都不影响结果
for(int i=0; i<arr.length; i++){
sum += arr[i];
}
double avg = (double)sum/arr.length;
示例代码2:
int[] arr = {4,5,6,1,9};
//求总乘积
long result = 1;//因为1乘以任何数都不影响结果
for(int i=0; i<arr.length; i++){
result *= arr[i];
}
示例代码3:
int[] arr = {4,5,6,1,9};
//统计偶数个数
int even = 0;
for(int i=0; i<arr.length; i++){
if(arr[i]%2==0){
even++;
}
}
4.3.3 反转
方法有两种:
1、借助一个新数组
2、首尾对应位置交换
第一种方式示例代码:
int[] arr = {1,2,3,4,5,6,7,8,9};
//(1)先创建一个新数组
int[] newArr = new int[arr.length];
//(2)复制元素
int len = arr.length;
for(int i=0; i<newArr.length; i++){
newArr[i] = arr[len -1 - i];
}
//(3)舍弃旧的,让arr指向新数组
arr = newArr;//这里把新数组的首地址赋值给了arr
//(4)遍历显示
for(int i=0; i<arr.length; i++){
System.out.println(arr[i]);
}
第二种方式示例代码:
int[] arr = {1,2,3,4,5,6,7,8,9};
//(1)计算要交换的次数: 次数 = arr.length/2
//(2)首尾交换
for(int i=0; i<arr.length/2; i++){//循环的次数就是交换的次数
//首 与 尾交换
int temp = arr[i];
arr[i] = arr[arr.length-1-i];
arr[arr.length-1-i] = temp;
}
//(3)遍历显示
for(int i=0; i<arr.length; i++){
System.out.println(arr[i]);
}
4.3.4 复制
应用场景:
1、扩容
2、备份
3、截取
示例代码:扩容
int[] arr = {1,2,3,4,5,6,7,8,9};
//如果要把arr数组扩容,增加1个位置
//(1)先创建一个新数组,它的长度 = 旧数组的长度+1
int[] newArr = new int[arr.length + 1];
//(2)复制元素
//注意:i<arr.length 因位arr比newArr短,避免下标越界
for(int i=0; i<arr.length; i++){
newArr[i] = arr[i];
}
//(3)把新元素添加到newArr的最后
newArr[newArr.length-1] = 新值;
//(4)如果下面继续使用arr,可以让arr指向新数组
arr = newArr;
//(4)遍历显示
for(int i=0; i<arr.length; i++){
System.out.println(arr[i]);
}
示例代码:备份
int[] arr = {1,2,3,4,5,6,7,8,9};
//1、创建一个长度和原来的数组一样的新数组
int[] newArr = new int[arr.length];
//2、复制元素
for(int i=0; i<arr.length; i++){
newArr[i] = arr[i];
}
//3、遍历显示
for(int i=0; i<arr.length; i++){
System.out.println(arr[i]);
}
示例代码:截取
int[] arr = {1,2,3,4,5,6,7,8,9};
int start = 2;
int end = 5;
//1、创建一个新数组,新数组的长度 = end-start + 1;
int[] newArr = new int[end-start+1];
//2、赋值元素
for(int i=0; i<newArr.length; i++){
newArr[i] = arr[start + i];
}
//3、遍历显示
for(int i=0; i<newArr.length; i++){
System.out.println(newArr[i]);
}
4.3.5 查找
查找分为两种:
1、顺序查找:挨个看
对数组没要求
2、二分查找:对折对折再对折
对数组有要求,元素必须有大小顺序的
顺序查找示例代码:
int[] arr = {4,5,6,1,9};
int value = 1;
int index = -1;
for(int i=0; i<arr.length; i++){
if(arr[i] == value){
index = i;
break;
}
}
if(index==-1){
System.out.println(value + "不存在");
}else{
System.out.println(value + "的下标是" + index);
}
二分查找示例代码:
/*
2、编写代码,使用二分查找法在数组中查找 int value = 2;是否存在,如果存在显示下标,不存在显示不存在。
已知数组:int[] arr = {1,2,3,4,5,6,7,8,9,10};
*/
class Exam2{
public static void main(String[] args){
int[] arr = {1,2,3,4,5,6,7,8,9};//数组是有序的
int value = 2;
int index = -1;
int left = 0;
int right = arr.length - 1;
int mid = (left + right)/2;
while(left<=right){
//找到结束
if(value == arr[mid]){
index = mid;
break;
}//没找到
else if(value > arr[mid]){//往右继续查找
//移动左边界,使得mid往右移动
left = mid + 1;
}else if(value < arr[mid]){//往左边继续查找
right = mid - 1;
}
mid = (left + right)/2;
}
if(index==-1){
System.out.println(value + "不存在");
}else{
System.out.println(value + "的下标是" + index);
}
}
}
使用for
class Exam2{
public static void main(String[] args){
int[] arr = {1,2,3,4,5,6,7,8,9};//数组是有序的
int value = 2;
int index = -1;
for(int left=0,right=arr.length-1,mid = (left+right)/2; left<=right; mid = (left + right)/2){
//找到结束
if(value == arr[mid]){
index = mid;
break;
}//没找到
else if(value > arr[mid]){//往右继续查找
//移动左边界,使得mid往右移动
left = mid + 1;
}else if(value < arr[mid]){//往左边继续查找
right = mid - 1;
}
}
if(index==-1){
System.out.println(value + "不存在");
}else{
System.out.println(value + "的下标是" + index);
}
}
}
4.3.6 排序
数组的排序算法有千万种,我们只讲了两种:
1、冒泡排序
2、简单的直接排序
示例代码:冒泡:从小到大,从左到右两两比较
int[] arr = {5,4,6,3,1};
for(int i=1; i<arr.length; i++){//外循环的次数 = 轮数 = 数组的长度-1
/*
第1轮,i=1,从左到右两两比较,arr[0]与arr[1]。。。。。arr[3]与arr[4]
第2轮,i=2,从左到右两两比较,arr[0]与arr[1]。。。。。arr[2]与arr[3]
...
arr[j]与arr[j+1]比较
找两个关键点:(1)j的起始值:0(2)找j的终止值,依次是3,2,1,0,得出j<arr.length-i
*/
for(int j=0; j<arr.length-i; j++){
//两两比较
//从小到大,说明前面的比后面的大,就交换
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
示例代码:从大到小,从右到左
char[] arr = {'h','e','l','l','o','j','a','v','a'};
for(int i=1; i<arr.length; i++){//外循环的次数 = 轮数 = 数组的长度-1
/*
第1轮,i=1,从右到左两两比较,arr[8]与arr[7],arr[7]与arr[6]....arr[1]与arr[0]
第2轮,i=2,从右到左两两比较,arr[8]与arr[7],arr[7]与arr[6]....arr[2]与arr[1]
...
第8轮,i=8,从右到左两两比较,arr[8]与arr[7]
arr[j]与arr[j-1]
找两个关键点:(1)j的起始值:8(2)找j的终止值,依次是1,2,3,。。。8,得出j>=i
*/
for(int j=8; j>=i; j--){
//从大到小,后面的元素 > 前面的元素,就交换
if(arr[j]>arr[j-1]){
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}
}
}
示例代码:简单的直接选择排序
int[] arr = {3,2,6,1,8};
for(int i=1; i<arr.length; i++){//外循环的次数 = 轮数 = 数组的长度-1
//(1)找出本轮未排序元素中的最值
/*
未排序元素:
第1轮:i=1,未排序,[0,4]
第2轮:i=2,未排序,[1,4]
...
每一轮未排序元素的起始下标:0,1,2,3,正好是i-1的
未排序的后面的元素依次:
第1轮:[1,4] j=1,2,3,4
第2轮:[2,4] j=2,3,4
第3轮:[3,4] j=3,4
第4轮:[4,4] j=4
j的起点是i,终点都是4
*/
int max = arr[i-1];
int index = i-1;
for(int j=i; j<arr.length; j++){
if(arr[j] > max){
max = arr[j];
index = j;
}
}
//(2)如果这个最值没有在它应该在的位置,就与这个位置的元素交换
/*
第1轮,最大值应该在[0]
第2轮,最大值应该在[1]
第3轮,最大值应该在[2]
第4轮,最大值应该在[3]
正好是i-1的值
*/
if(index != i-1){
//交换arr[i-1]与arr[index]
int temp = arr[i-1];
arr[i-1] = arr[index];
arr[index] = temp;
}
}
//显示结果
for(int i=0; i<arr.length; i++){
System.out.print(arr[i]);
}
4.4 二维数组
二维数组的标记:[][]
4.4.1 相关的表示方式
(1)二维数组的长度/行数:
二维数组名.length
(2)二维数组的其中一行:
二维数组名[行下标]
行下标的范围:[0, 二维数组名.length-1]
(3)每一行的列数:
二维数组名[行下标].length
因为二维数组的每一行是一个一维数组
(4)每一个元素
二维数组名[行下标][列下标]
4.4.2 二维数组的声明和初始化
1、二维数组的声明
//推荐
元素的数据类型[][] 二维数组的名称;
//不推荐
元素的数据类型 二维数组名[][];
//不推荐
元素的数据类型[] 二维数组名[];
面试:
int[] x, y[];
//x是一维数组,y是二维数组
2、二维数组的初始化
(1)静态初始化
二维数组名 = new 元素的数据类型[][]{
{第一行的值列表},
{第二行的值列表},
...
{第n行的值列表}
};
//如果声明与静态初始化一起完成
元素的数据类型[][] 二维数组的名称 = {
{第一行的值列表},
{第二行的值列表},
...
{第n行的值列表}
};
(2)动态初始化(不规则:每一行的列数可能不一样)
//(1)先确定总行数
二维数组名 = new 元素的数据类型[总行数][];
//(2)再确定每一行的列数
二维数组名[行下标] = new 元素的数据类型[该行的总列数];
//(3)再为元素赋值
二维数组名[行下标][列下标] = 值;
(3)动态初始化(规则:每一行的列数是相同的)
//(1)确定行数和列数
二维数组名 = new 元素的数据类型[总行数][每一行的列数];
//(2)再为元素赋值
二维数组名[行下标][列下标] = 值;
4.4.3 二维数组的遍历
for(int i=0; i<二维数组名.length; i++){
for(int j=0; j<二维数组名[i].length; j++){
System.out.print(二维数组名[i][j]);
}
System.out.println();
}
第五章 面向对象基础
5.1 类与对象
1、类:一类具有相同特性的事物的抽象描述。
对象:类的一个个体,实例,具体的存在。
类是对象的设计模板。
2、如何声明类?
【修饰符】 class 类名{
成员列表:属性、方法、构造器、代码块、内部类
}
3、如何创建对象?
new 类名(); //匿名对象
类名 对象名 = new 类名(); //有名对象
5.2 类的成员之一:属性
1、如何声明属性?
【修饰符】 class 类名{
【修饰符】 数据类型 属性名; //属性有默认值
【修饰符】 数据类型 属性名 = 值; //属性有初始值
}
说明:属性的类型可以是Java的任意类型,包括基本数据类型、引用数据类型(类、接口、数组等)
总结:Java的数据类型
(1)基本数据类型
byte,short,int,long,float,double,char,boolean
(2)引用数据类型
①类:
例如:String、Student、Circle、System、Scanner、Math…
②接口:后面讲
③数组:
例如:int[],String[],char[],int[][]
int[] arr = new int[5];
这里把int[]看成数组类型,是一种引用数据类型,右边赋值的是一个数组的对象
元素的数据类型:int
数组的数据类型:int[]
2、如何为属性赋值?
(1)在声明属性时显式赋值
【修饰符】 class 类名{
【修饰符】 数据类型 属性名 = 值; //属性有初始值
}
代码示例:
class Student{
String name;
char gender = '男';//显式赋值
}
class TestStudent{
public static void main(String[] args){
Student s1 = new Student();
System.out.println("姓名:" + s1.name);//null
System.out.println("性别:" + s1.gender);//男
s1.name = "小薇";//修改属性的默认值
s1.gender = '女';//修改属性的初始值
System.out.println("姓名:" + s1.name);//小薇
System.out.println("性别:" + s1.gender);//女
Student s2 = new Student();
System.out.println("姓名:" + s2.name);//null
System.out.println("性别:" + s2.gender);//男
}
}
(2)创建对象之后赋值
【修饰符】 class 类名{
【修饰符】 数据类型 属性名; //属性有默认值
}
//创建对象
类名 对象名 = new 类名();
//为对象的属性赋值
对象名.属性名 = 值;
3、如何访问属性的值?
(1)在本类的方法中访问
示例代码:
class Circle{
double radius;
double getArea(){
return 3.14 * radius * radius;//直接访问
}
}
(2)在其他类的方法中访问
class Circle{
double radius;
}
class TestCircle{
public static void main(String[] args){
Circle c1 = new Circle();
double area = 3.14 * c1.radius * c1.radius;//对象名.属性名
}
}
4、属性的特点
(1)属性有默认值
基本数据类型:
byte,short,int,long:0
float,double:0.0
char:\u0000
boolean:false
引用数据类型:
null
(2)每一个对象的属性是独立,互不干扰
5、对象属性的内存图
class Student{
String name;
char gender = '男';//显式赋值
}
class TestStudent{
public static void main(String[] args){
Student s1 = new Student();
System.out.println("姓名:" + s1.name);//null
System.out.println("性别:" + s1.gender);//男
s1.name = "小薇";
s1.gender = '女';
System.out.println("姓名:" + s1.name);//小薇
System.out.println("性别:" + s1.gender);//女
Student s2 = new Student();
System.out.println("姓名:" + s2.name);//null
System.out.println("性别:" + s2.gender);//男
}
}
5.4 类的成员之二:方法
5.4.1 方法的概念
方法(method):代表一个独立的可复用的功能
目的/好处:
(1)复用
(2)简化代码
5.4.2 方法的语法
1、方法的声明格式:
【修饰符】 class 类名{
【修饰符】 返回值类型 方法名(【形参列表】){
方法体:实现功能的代码
}
}
说明:
(1)【修饰符】:待讲
(2)返回值类型:
①void:表示无返回值
②非void:所有的Java数据类型都可以
(3)方法名:能很好的体现方法的功能
命名的规范:①见名知意②从第二个单词开始首字母大写
(4)【形参列表】:
在完成这个方法的功能时,需要一些数据,这些数据要由“调用者”来决定,那我们就可以设计形参。
语法格式:
():无参,空参
(数据类型 形参名):一个形参
(数据类型1 形参名1, …, 数据类型n 形参名n):n个形参
(5)方法体:实现方法的功能,最好一个方法就完成一个独立的功能。
2、方法的调用格式:
//本类同级别方法调用:直接调用
【变量 = 】 方法名(【实参列表】);
//在其他类的方法中调用
【变量 = 】 对象名.方法名(【实参列表】);
(1)是否传实参
看被调用的方法是否有形参
(2)是否接收返回值
看被调用的方法是否是void,如果是void,就不需要也不能接收,如果不是void,就可以接收。
3、方法的声明与调用的代码示例
(1)无参无返回值方法
//本类
class Circle{
double radius;
void printInfo(){
System.out.println("半径:" + radius);
}
void test(){
printInfo();//本类中调用无参无返回值方法
}
}
//其他类
class Circle{
double radius;
void printInfo(){
System.out.println("半径:" + radius);
}
}
class TestCircle{
public static void main(String[] args){
Circle c1 = new Circle();
c1.printInfo(); //其他类中调用无参无返回值方法
}
}
(2)无参有返回值方法
//本类
class Circle{
double radius;
double getArea(){
return 3.14 * radius * radius();
}
void printInfo(){
// System.out.println("半径:" + radius + ",面积:" + getArea());//本类中调用无参有返回值
double area = getArea();//本类中调用无参有返回值
System.out.println("半径:" + radius + ",面积:" + area);
}
}
//其他类
class Circle{
double radius;
double getArea(){
return 3.14 * radius * radius();
}
}
class TestCircle{
public static void main(String[] args){
Circle c1 = new Circle();
double area = c1.getArea();
System.out.println("面积:" + area);
//或
System.out.println("面积:" + c1.getArea());
}
}
(3)有参无返回值方法
//本类
class GraphicTools{
void printRectange(int line, int column, char sign){
for(int i=1; i<=line; i++){
for(int j=1; j<=column; j++){
Sytem.out.print(sign);
}
System.out.println();
}
}
void test(){
printRectange(5,10,'%');//本类中调用有参无返回值方法
}
}
//其他类
class GraphicTools{
void printRectange(int line, int column, char sign){
for(int i=1; i<=line; i++){
for(int j=1; j<=column; j++){
Sytem.out.print(sign);
}
System.out.println();
}
}
}
class Test{
public static void main(String[] args){
GraphicTools tools = new GraphicTools();
tools.printRectange(5,10,'%');
}
}
(4)有参有返回值方法
//本类
class MyMath{
int sum(int a,int b){
return a+b;
}
void print(){
int x = 4;
int y = 7;
System.out.println(x + "+" + y + "=" + sum(x,y);//本类中调用有参有返回值的方法
}
}
//其他类
class MyMath{
int sum(int a,int b){
return a+b;
}
}
class Test{
public static void main(String[] args){
MyMath my = new MyMath();
int x = 4;
int y = 7;
System.out.println(x + "+" + y + "=" + my.sum(x,y));
}
}
4、方法声明与调用的原则
(1)方法必须先声明后调用
如果调用方法时,如果方法名写错或调用一个不存在的方法,编译会报错
(2)方法声明的位置必须在类中方法外
正确示例:
类{
方法1(){
}
方法2(){
}
}
错误示例:
类{
方法1(){
方法2(){ //错误
}
}
}
(3)方法的调用的位置有要求
正确示例:
类{
方法1(){
调用方法
}
}
错误示例:
类{
方法1(){
}
调用方法 //错误位置
}
(4)方法的调用格式要与方法的声明格式对应
①是否要加“对象.”:看是否在本类中,还是其他类中
②是否要接收返回值:看被调用方法是否是void
③是否要传实参:看被调用方法是有形参列表
5.4.3 方法的重载Overload
概念:在同一个类中,出现了两个或多个的方法,它们的方法名称相同,形参列表不同,这样的形式称为方法的重载。和返回值类型无关。
示例代码:
//求两个整数的最大值
public int max(int a,int b){
return a>b?a:b;
}
//求三个整数的最大值
public int max(int a, int b, int c){
return max(max(a,b),c);
}
//求两个小数的最大值
public double max(double a, double b){
return a>b?a:b;
}
5.4.4 方法的参数传递机制
Java中方法的参数传递机制:值传递
(1)形参是基本数据类型时,实参给形参传递数据值,是copy的形式,形参对值的修改不影响实参。
(2)形参是引用数据类型时,实参给形参传递地址值,形参对对象的属性的修改,会影响实参对象的属性值,因为此时形参和实参就是指向同一个对象。
示例代码:
class Test{
public static void swap(int a, int b){
int temp = a;
a = b;
b = temp;
}
public static void main(String[] args){
int x = 1;
int y = 2;
swap(x,y);//调用完之后,x与y的值不变
}
}
示例代码:
class Test{
public static void change(MyData my){
my.num *= 2;
}
public static void main(String[] args){
MyData m = new MyData();
m.num = 1;
change(m);//调用完之后,m对象的num属性值就变为2
}
}
class MyData{
int num;
}
陷阱1:
/*
陷阱1:在方法中,形参 = 新new对象,那么就和实参无关了
*/
class Test{
public static void change(MyData my){
my = new MyData();//形参指向了新对象
my.num *= 2;
}
public static void main(String[] args){
MyData m = new MyData();
m.num = 1;
change(m);//调用完之后,m对象的num属性值仍然为1
}
}
class MyData{
int num;
}
陷阱2:见字符串和包装类部分
5.3 对象数组
一维数组:
1、元素是基本数据类型
2、元素是引用数据类型,也称为对象数组,即数组的元素是对象
注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。
示例代码:
class MyDate{
int year;
int month;
int day;
}
class Test{
public static void main(String[] args){
MyDate[] arr = new MyDate[3];//创建数组对象本身,指定数组的长度
for(int i=0; i<arr.length; i++){
arr[i] = new MyDate();//每一个元素要创建对象
arr[i].year = 1990 + i;
arr[i].month = 1 + i;
arr[i].day = 1 + i;
}
}
}
对象数组的内存图: