03-第三章 变量
day11 课堂笔记
1、方法
1.1、什么是方法,有什么用?
(可以先看一下一个程序如果没有方法,会出现什么问题?)
方法(英语单词:method)是可以完成某个特定功能的并且可以被重复利用的代码片段。
在C语言中,方法被称为“函数”。在java中不叫函数,叫做方法。
你定义了一个/抽取了一个方法出来,而这个方法确无法完成某个功能,
那么你抽取的这个方法毫无意义。一般一个方法就是一个“功能单元”。
假设在以后的开发中,某个功能是可以独立抽取出来的,建议定义为
方法,这样以后只要需要这个功能,那么直接调用这个方法即可,而
不需要重复编写业务逻辑代码。
1.2、方法怎么定义,语法机制是什么?
/*
对于一个java程序来说,如果没有“方法”,会存在什么问题?
代码无法得到复用。(怎么提高复用性,可以定义方法,然后需要
使用该功能的时候,直接调用一下方法即可。这样代码就得到复用了。)
*/
public class MethodTest01{
// 入口主方法。
public static void main(String[] args){
// 需求1:请编写程序,计算100和200的求和。
int x = 100;
int y = 200;
int z = x + y;
System.out.println(x + "+" + y + "=" + z);
// 需求2:请编写程序,计算666和888的求和。
// 这个需求2实际上和需求1是完全相同的,只不过具体求和时的“数据不同”
int a = 666;
int b = 888;
int c = a + b;
System.out.println(a + "+" + b + "=" + c);
// 需求3:请编写程序,计算111和222的和
int m = 111;
int n = 222;
int k = m + n;
System.out.println(m + "+" + n + "=" + k);
/*
需求1和需求2本质上相同,只不过参与运算的数值不同,
代码编写了两份,显然代码没有得到重复利用,专业术语
叫做“复用性”差。
功能/业务逻辑既然相同,为什么要重复编写代码,代码能不能
写一次,以后要是需要再次使用该“业务/需求”的时候,直接调用
就可以了。
如果想达到代码复用,那么需要学习java语言中的方法机制。
*/
}
}
/*
这个程序是一个体验程序,你看不懂,你只需要去体验就行了。
体验一下方法的好处。
注意:
程序开始执行的时候是先执行main方法。
因为main方法是一个入口。
在java语言中所有的方法体中的代码都必须遵循自上而下的顺序依次逐行执行。
这个必须记住。
main方法不需要程序员手动调用,是由JVM调用的。
但是除了main方法之外其他的方法,都需要程序员
手动调用,方法只有调用的时候才会执行,方法不调用
是不会执行的。
*/
public class MethodTest02{
// 方法定义在类体当中。
// 方法定义的先后顺序没有关系。都可以。
/*
public static void sumInt(int x, int y){ // 自上而下的顺序依次逐行执行。
int z = x + y;
System.out.println(x + "+" + y + "=" + z);
}
*/
// 主方法。入口。
public static void main(String[] args){ // 自上而下依次逐行执行。
// 需求1:请编写程序,计算100和200的求和。
sumInt(100, 200);
// 需求2:请编写程序,计算666和888的求和。
sumInt(666, 888);
// 需求3:请编写程序,计算111和222的和
sumInt(111, 222);
}
// 专门在这个类体当中定义一个方法,这个方法专门来完成求和。
// x y z在以下的sumInt方法中都属于局部变量
// 局部变量有一个特点:方法结束之后,局部变量占用的内存会自动释放。
public static void sumInt(int x, int y){ // 自上而下的顺序依次逐行执行。
int z = x + y;
System.out.println(x + "+" + y + "=" + z);
}
public static void sum(){
//System.out.println(x);
//System.out.println(y);
//错误: 找不到符号
//System.out.println(z);
}
}
// 这里并没有讲解方法的定义,以及方法的调用。
/*
1、方法怎么定义,语法机制是什么?
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
注意:
[] 符号叫做中括号,以上中括号[]里面的内容表示不是必须的,是可选的。
方法体由Java语句构成。
方法定义之后需要去调用,不调用是不会执行的。
1.1、关于修饰符列表:
修饰符列表不是必选项,是可选的。目前为止,大家统一写成:public static
后面你就理解应该怎么写了。
1.2、关于返回值类型:
第一:返回值类型可以是任何类型,只要是java中合法的数据类型就行,数据
类型包括基本数据类型和引用数据类型,也就是说返回值类型可以是:byte short
int long float double boolean char String......
第二:什么是返回值?
返回值一般指的是一个方法执行结束之后的结果。
结果通常是一个数据,所以被称为“值”,而且还叫
“返回值”。
方法就是为了完成某个特定的功能,方法结束之后
大部分情况下都是有一个结果的,而体现结果的一般
都是数据。数据得有类型。这就是返回值类型。
main{
// 调用a方法
a();..如果a方法执行结束之后有返回值,这个返回值返回给main了。
}
a(){}
方法执行结束之后的返回值实际上是给调用者了。谁调用就返回给谁。
第三:当一个方法执行结束不返回任何值的时候,返回值
类型也不能空白,必须写上void关键字。所以void表示该
方法执行结束后不返回任何结果。
第四:如果返回值类型“不是void”,那么你在方法体执行结束的时候必须使用
"return 值;"这样的语句来完成“值”的返回,如果没有“return 值;”这样的语句
那么编译器会报错。
return 值; 这样的语句作用是什么?作用是“返回值”,返回方法的执行结果。
第五:只要有“return”关键字的语句执行,当前方法必然结束。
return只要执行,当前所在的方法结束,记住:不是整个程序结束。
第六:如果返回值类型是void,那么在方法体当中不能有“return 值;”这样的
语句。但是可以有“return;”语句。这个语句“return;”的作用就是用来终止当前
方法的。
第七:除了void之外,剩下的都必须有“return 值;”这样的语句。
1.3、方法名
方法名要见名知意。(驼峰命名方式)
方法名在标识符命名规范当中,要求首字母小写,后面每个单词首字母大写。
只要是合法的标识符就行。
1.4、形式参数列表
简称:形参
注意:形式参数列表中的每一个参数都是“局部变量”,方法结束之后内存释放。
形参的个数是:0~N个。
public static void sumInt(){}
public static void sumInt(int x){}
public static void sumInt(int x, int y){}
public static void sum(int a, int b, double d, String s){}
形参有多个的话使用“逗号,”隔开。逗号是英文的。
形参的数据类型起决定性作用,形参对应的变量名是随意的。
1.5、方法体:
由Java语句构成。java语句以“;”结尾。
方法体当中编写的是业务逻辑代码,完成某个特定功能。
在方法体中的代码遵循自上而下的顺序依次逐行执行。
在方法体中处理业务逻辑代码的时候需要数据,数据来源就是这些形参。
2、方法定义之后怎么调用呢?
方法必须调用才能执行。
怎么调用,语法是什么?
类名.方法名(实际参数列表);
实参和形参的类型必须一一对应,另外个数也要一一对应。
*/
public class MethodTest03{
//方法定义在这里可以。
// main方法结束之后不需要给JVM返回任何执行结果。
public static void main(String[] args){
// 调用方法
//错误: 不兼容的类型: String无法转换为int
//MethodTest03.divide("abc", 200); // int a = "abc";
//错误原因: 实际参数列表和形式参数列表长度不同
//MethodTest03.divide();
// (10, 2)叫做实际参数列表,简称实参。
// 注意:实参和形参必须一一对应,类型要对应,个数要对应。
MethodTest03.divide(10, 2);
// 调用sum方法
// 怎么去接收这个方法的返回结果????
// 使用变量来接收这个方法的返回值。
// 注意:变量的定义需要指定变量的数据类型。
// 变量的数据类型是什么呢?
int jieGuo = MethodTest03.sum(100, 200);
System.out.println(jieGuo); //300
// jieGuo变量可以是double类型吗?
// double是大容量。int是小容量。自动类型转换。
double jieGuo2 = MethodTest03.sum(100, 200);
System.out.println(jieGuo2); //300.0
// 对于没有返回值的方法,变量能接收吗?
// divide方法结束没有返回值。不能接收。
// 错误: 不兼容的类型: void无法转换为int
//int i = MethodTest03.divide(100, 50);
// 当一个方法有返回值的时候,我可以选择不接收吗?
// 你可以返回值,但是我可以选择不要你这个值。这是允许的。
// 只不过这样没有意义,一般程序返回了执行结果,都是需要接收这个结果的。
// 我们可以不接收,但是这个返回值该返回还是会返回的。只不过不用变量接收。
// 以下代码虽然没有使用变量接收这个返回值,但是这个值还是返回了。
// 返回之后内存马上释放,因为没有使用变量接收。
MethodTest03.sum(100, 200);
byte b1 = 10;
//int a = b1;
byte b2 = 20;
int result = sum(b1, b2); // (b1,b2)是实参。自动类型转换。
System.out.println(result);
}
// 计算两个int类型数据的和
/*
public static String sum(int a, int b){
// 错误: 不兼容的类型: int无法转换为String
return a + b;
}
*/
public static int sum(int a, int b){
return a + b;
}
// 方法定义到这里也可以。没有顺序要求。
// 业务是什么?计算两个int类型数据的商
// 方法执行结束之后返回执行结果。
//错误: 缺少返回语句
/*
public static int divide(int x, int y){
int z = x / y;
}
*/
//错误: 不兼容的类型: String无法转换为int
/*
public static int divide(int x, int y){
int z = x / y;
return "abc";
}
*/
//可以
/*
public static int divide(int x, int y){
int z = x / y;
return z;
}
*/
//可以
/*
public static int divide(int x, int y){
return x / y;
}
*/
// 可以
/*
public static int divide(int a, int b){
return a / b;
}
*/
// 如果我不需要执行结束之后的返回值?
// 这个结果我希望直接输出。
//错误: 不兼容的类型: 意外的返回值
/*
public static void divide(int a, int b){
return a / b;
}
*/
//可以
/*
public static void divide(int a, int b){
return; // 用来终止这个方法的
}
*/
// 可以
/*
public static void divide(int a, int b){
}
*/
// 可以
public static void divide(int a, int b){
System.out.println(a / b); // 5
}
}
/*
在方法调用的时候,什么时候“类名.”是可以省略的。什么时候不能省略?
a()方法调用b()方法的时候,a和b方法都在同一个类中,“类名.”可以
省略。如果不在同一个类中“类名.”不能省略。
*/
// 类1
public class MethodTest04{
public static void daYin3(){
System.out.println("动力节点-口口相传的Java黄埔军校!");
}
// 入口
public static void main(String[] args){
// 调用println()方法。
MethodTest04.daYin();
MethodTest04.daYin2();
MethodTest04.daYin3();
// “类名. ”可以省略吗?
daYin();
daYin2();
daYin3();
// 第一次跨类调用。
// 像这种情况下:“类名.”就不能省略了。
MyClass.daYin();
//daYin();
}
public static void daYin(){
System.out.println("hello world!");
}
public static void daYin2(){
System.out.println("hello world2!!!");
}
}
// 类2
class MyClass{
public static void daYin(){
System.out.println("打印1");
}
public static void daYin2(){
System.out.println("打印2");
}
public static void daYin3(){
System.out.println("打印3");
}
}
// 别自乱阵脚:任何一个方法体当中的代码都是遵循自上而下的顺序依次逐行执行的。
// 自上而下的顺序
/*
推测执行结果:
main begin
m1 begin
m2 begin
m3 begin
T's m3 method execute!
m3 over
m2 over
m1 over
main over
main方法最先执行,并且main方法是最后一个结束。
main结束,整个程序就结束了。
*/
public class MethodTest05{
public static void main(String[] args){
System.out.println("main begin");
// 调用m1方法
m1();
System.out.println("main over");
}
public static void m1(){
System.out.println("m1 begin");
// 调用程序不一定写到main方法中,不要把main方法特殊化。
// main方法也是一个普通方法。
m2();
System.out.println("m1 over");
}
// m2方法可以调用T类的m3()方法吗?
public static void m2(){
System.out.println("m2 begin");
T.m3();
System.out.println("m2 over");
}
}
class T{
public static void m3(){
System.out.println("m3 begin");
System.out.println("T's m3 method execute!");
System.out.println("m3 over");
}
}
/*
break;语句和return;语句有什么区别?
不是一个级别。
break;用来终止switch和离它最近的循环。
return;用来终止离它最近的一个方法。
*/
public class MethodTest06{
//main方法的返回值类型是void,表示没有返回值。
public static void main(String[] args){
for(int i = 0; i < 10; i++){
if(i == 5){
//break; // 终止for循环
return; // 终止当前的方法,和break;不是一个级别的。
//错误: 不兼容的类型: 意外的返回值
//return 10;
}
System.out.println("i = " + i);
}
System.out.println("Hello World!");
}
}
// 大家分析以下代码,编译器会报错吗?
public class MethodTest07{
public static void main(String[] args){
// 调用方法
int result = m();
System.out.println(result); // 1
// 调用x方法
int result1 = x(true);
System.out.println("result1 = " + result1);
// 再次调用x方法
int result2 = x(false);
System.out.println("result2 = " + result2);
}
//错误: 缺少返回语句
/*
public static int m(){
boolean flag = true; //编译器不负责运行程序,编译器只讲道理。
// 对于编译器来说,编译器只知道flag变量是boolean类型
// 编译器会认为flag有可能是false,有可能是true
if(flag){
// 编译器觉得:以下这行代码可能会执行,当然也可能不会执行
// 编译器为了确保程序不出现任何异常,所以编译器说:缺少返回语句
return 1;
}
}
*/
// 怎么修改这个程序呢?
// 第一种方案:带有else分支的可以保证一定会有一个分支执行。
/*
public static int m(){
boolean flag = true;
if(flag){
return 1;
}else{
return 0;
}
}
*/
// 第二种方案:该方案实际上是方案1的变形。
// return语句一旦执行,所在的方法就会结束。
/*
public static int m(){
boolean flag = true;
if(flag){
return 1;
}
return 0;
}
*/
/*
// 在同一个域当中,"return语句"下面不能再编写其它代码。编写之后编译报错。
public static int m(){
boolean flag = true;
if(flag){
return 1;
//错误: 无法访问的语句
//System.out.println("hello1");
}
// 这行代码和上面的代码hello1的区别是:不在同一个域当中。
//System.out.println("hello2");
return 0;
// 错误: 无法访问的语句
//System.out.println("hello3");
}
*/
// 三目运算符有的时候会让代码很简练。
public static int m(){
boolean flag = true;
return flag ? 1 : 0;
}
// 带有一个参数的方法。
public static int x(boolean flag){
return flag ? 1 : 0;
}
}
// 局部变量:只在方法体中有效,方法结束之后,局部变量的内存就释放了。
// JVM三块主要的内存:栈内存、堆内存、方法区内存。
// 方法区最先有数据:方法区中放代码片段。存放class字节码。
// 堆内存:后面讲。
// 栈内存:方法调用的时候,该方法需要的内存空间在栈中分配。
// 方法不调用是不会在栈中分配空间的。
// 方法只有在调用的时候才会在栈中分配空间,并且调用时就是压栈。
// 方法执行结束之后,该方法所需要的空间就会释放,此时发生弹栈动作。
// 方法调用叫做:压栈。分配空间
// 方法结束叫做:弹栈。释放空间
// 栈中存储什么?方法运行过程中需要的内存,以及栈中会存储方法的局部变量。
public class MethodTest08{
//主方法,入口
public static void main(String[] args){
//int a = 100;
// 这个赋值原理是:将a变量中保存的100这个数字复制一份传给b变量。
// 所以a和b是两个不同的内存空间,是两个局部变量。
//int b = a;
System.out.println("main begin");
int x = 100;
m1(x);
System.out.println("main over");
}
public static void m1(int i){ // i是局部变量
System.out.println("m1 begin");
m2(i);
System.out.println("m1 over");
}
public static void m2(int i){
System.out.println("m2 begin");
m3(i);
System.out.println("m2 over");
}
public static void m3(int i){
System.out.println("m3 begin");
System.out.println(i);
System.out.println("m3 over");
}
}
public class MethodTest09{
public static void main(String[] args){
//调用sum方法
int jieGuo = sum(10, 20);
System.out.println(jieGuo); // 30
// 上面两行代码能否合并为一行?
// 可以
System.out.println(sum(100, 200)); // 300
System.out.println(m()); // true
boolean flag = m();
if(flag){
System.out.println("真的。。。。。");
}
if(m()){
System.out.println("真的。。。。。");
}
}
public static boolean m(){
return true;
}
// 求和的方法
public static int sum(int a, int b){
return a + b;
}
}
day11回顾
1、方法是什么?
方法是一段可以完成某个特定功能的并且可以被重复利用的代码片段。
方法的出现,让代码具有了很强的复用性。
2、方法最难实现的是:
根据业务怎么进行方法的抽取。
方法的返回值类型定义为 什么?
方法的名字叫什么?
方法的形式参数列表定义为 什么?
....
一个方法就是一个独立的功能。
3、方法的定义
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
4、方法的每一个细节学习
4.1、修饰符列表:可选项,目前先写成:public static
4.2、怎么理解返回值?返回值是一个方法执行结束之后的结果。
4.3、返回值类型都可以指定哪些类型?
4.4、返回值和“return语句”的关系。
4.5、方法名只要是合法的标识符就行,首字母小写,后面每个单词首字母大写。见名知意。
4.6、形式参数列表
4.7、方法体:方法体当中的代码遵循自上而下的顺序依次逐行执行。
4.8、方法怎么调用?“类名.”什么时候可以省略?
实际参数列表,简称实参。(调用方法时传递的实际数据。)
实参和形参的关系是一一对应。
5、JVM的内存结构中三块比较重要的内存空间。
方法区:
存储代码片段,存储xxx.class字节码文件,这个空间是最先有数据的,
类加载器首先将代码加载到这里。
堆内存:
后面讲(面向对象)
栈内存:
stack栈当中存储什么?
每个方法执行时所需要的内存空间(局部变量)。
6、关于数据结构中的栈数据结构
原则:
后进先出
先进后出
栈数据结构相关的术语:
栈帧:永远指向栈顶部的元素(栈顶元素具有活跃权。)
栈顶元素
栈底元素
压栈,入栈,进栈,push
弹栈,出栈,pop
昨天还聊了一些:什么是数据结构?什么是算法?
有一本书:数据结构与算法。
数据结构和算法的选择很重要,选择对了程序的执行效率大大提升。
可以很好的优化程序。
7、分析程序运行过程中的内存变化
方法只定义不调用是不会执行的。
方法调用时:压栈 (在栈中给该方法分配空间)
方法执行结束时:弹栈(将该方法占用的空间释放,局部变量的内存也释放。)
day12 课堂笔记
1、方法重载overload
1.1、什么情况下我们考虑使用方法重载机制?
当功能相似的时候,建议将方法名定义为一致的,
这样代码美观,又方便编程。
注意:如果功能不相似,坚决要让方法名不一致。
1.2、代码满足什么条件的时候构成了方法重载?
条件1:在同一个类当中
条件2:方法名相同
条件3:形式参数列表不同(类型、个数、顺序)
注意:
方法重载和返回值类型无关,和修饰符列表无关。
1.3、方法重载的优点?
代码美观
方便代码的编写
/*
方法重载机制?
1、以下程序先不使用方法重载机制,分析程序的缺点???
以下程序没有语法错误,运行也是正常的,你就分析一下代码风格存在什么缺点!
sumInt、sumLong、sumDouble不是功能“相同”,是功能“相似”。
三个方法功能不同,但是相似,分别起了三个不同的名字,有什么缺点?
缺点包括两个:
第一个:代码不美观(不好看、不整齐)。【这是次要的】
第二个:程序员需要记忆更多的方法名称,程序员比较累。
*/
public class OverloadTest01{
//主方法
public static void main(String[] args){
int x = sumInt(10, 20);
System.out.println(x);
long y = sumLong(10L, 20L);
System.out.println(y);
double z = sumDouble(10.0, 20.0);
System.out.println(z);
}
// 定义一个计算int类型数据的求和方法
public static int sumInt(int a, int b){
return a + b;
}
// 定义一个计算long类型数据的求和方法
public static long sumLong(long a, long b){
return a + b;
}
// 定义一个计算double类型数据的求和方法
public static double sumDouble(double a, double b){
return a + b;
}
}
/*
使用方法重载机制。解决之前的两个缺点。
优点1:代码整齐美观。
优点2:“功能相似”的,可以让“方法名相同”,更易于以后的代码编写。
在java语言中,是怎么进行方法区分的呢?
首先java编译器会通过方法名进行区分。
但是在java语言中允许方法名相同的情况出现。
如果方法名相同的情况下,编译器会通过方法的参数类型进行方法的区分。
*/
public class OverloadTest02{
public static void main(String[] args){
// 对于程序员来说,只需要记忆一个方法名即可。
System.out.println(sum(10, 20));
System.out.println(sum(10L, 20L));
System.out.println(sum(10.0, 20.0));
}
// 定义一个计算int类型数据的求和方法
public static int sum(int a, int b){
System.out.println("int求和");
return a + b;
}
// 定义一个计算long类型数据的求和方法
public static long sum(long a, long b){
System.out.println("long求和");
return a + b;
}
// 定义一个计算double类型数据的求和方法
public static double sum(double a, double b){
System.out.println("double求和");
return a + b;
}
}
/*
方法重载(overload):
什么时候需要考虑使用方法重载?
在同一个类当中,如果“功能1”和“功能2”它们的功能是相似的,
那么可以考虑将它们的方法名一致,这样代码既美观,又便于
后期的代码编写(容易记忆,方便使用)。
注意:方法重载overload不能随便使用,如果两个功能压根不相干,
不相似,根本没关系,此时两个方法使用重载机制的话,会导致
编码更麻烦。无法进行方法功能的区分。
什么时候代码会发生方法重载?
条件1:在同一个类当中
条件2:方法名相同
条件3:参数列表不同
参数的个数不同算不同
参数的类型不同算不同
参数的顺序不同算不同
只要同时满足以上3个条件,那么我们可以认定方法和方法之间发生了
重载机制。
注意:
不管代码怎么写,最终一定能让java编译器很好的区分开这两个方法。
方法重载和方法的“返回值类型”无关。
方法重载和方法的“修饰符列表”无关。
*/
public class OverloadTest03{
public static void main(String[] args){
m1();
m1(100);
m2(10, 3.14);
m2(3.14, 10);
m3(100);
m3(3.14);
}
public static void m1(){
System.out.println("m1无参数的执行!");
}
// 这个方法的参数个数和上面的方法的参数个数不同。
public static void m1(int a){
System.out.println("m1有一个int参数执行!");
}
public static void m2(int x, double y){
System.out.println("m2(int x, double y)");
}
// 参数的顺序不同,也算不同。
public static void m2(double y, int x){
System.out.println("m2(double y, int x)");
}
public static void m3(int x){
System.out.println("m3(int x)");
}
// 参数的类型不同。
public static void m3(double d){
System.out.println("m3(double d)");
}
//分析:以下两个方法有没有发生重载?
// 编译器报错了,不是重载,这是重复了:呵呵。
/*
public static void m4(int a, int b){
}
public static void m4(int x, int y){
}
*/
// 这两个方法有没有发生重载呢?
// 这不是重载,这是方法重复了。
/*
public static int m5(){
return 1;
}
public static double m5(){
return 1.0;
}
*/
//这两个方法重载了吗?
// 这个方法没有修饰符列表
// 这不是重载,是重复了。
/*
void m6(){
}
// 这个有修饰符列表
public static void m6(){
}
*/
}
class MyClass{
// 不在同一个类当中,不能叫做方法重载。
public static void m1(int x, int y){
}
}
public class OverloadTest04{
public static void main(String[] args){
// 大家是否承认:println是一个方法名。
// println我承认是方法名了,但是这个方法谁写的?SUN公司的java团队写的。
// 你直接用就行。
// println()方法肯定是重载了。(不信,你可以翻阅一下SUN公司写的源代码看看。)
// 对于println()方法来说,我们只需要记忆这一个方法名就行。
// 参数类型可以随便传。这说明println()方法重载了。
System.out.println(10);
System.out.println(3.14);
System.out.println(true);
System.out.println('a');
System.out.println("abc");
System.out.println(100L);
System.out.println(3.0F);
// 调用m方法
m(100);
}
public static void m(int i){
}
}
// 目前我们正在学习的一个内容是:方法重载机制(overload)
public class S{
// 以下所有的p()方法构成了方法的重载。
// 换行的方法
public static void p(){
System.out.println();
}
// 输出byte
public static void p(byte b){
System.out.println(b);
}
// 输出short
public static void p(short s){
System.out.println(s);
}
// 输出int
public static void p(int i){
System.out.println(i);
}
// 输出long
public static void p(long l){
System.out.println(l);
}
// 输出float
public static void p(float f){
System.out.println(f);
}
// 输出double
public static void p(double d){
System.out.println(d);
}
// 输出boolean
public static void p(boolean b){
System.out.println(b);
}
// 输出char
public static void p(char c){
System.out.println(c);
}
// 输出String
public static void p(String s){
System.out.println(s);
}
}
public class T{
public static void main(String[] args){
// 调用TT的doSome?
TT.doSome();
}
}
/*
class TT{
public static void doSome(){
System.out.println("do something!!!!");
}
}
*/
public class TT{
public static void doSome(){
System.out.println("do something!!!!");
}
}
2、方法递归
2.1、需要理解什么是方法递归?
方法自身调用自身。
2.2、使用递归的时候,必须添加结束条件,没有结束条件,会发生栈内存溢出错误。
StackOverflowError
原因:一直压栈,没有弹栈,栈内存不够用。
2.3、会画出递归方法的内存结构图。
递归的过程当中可以将图画出来。
2.4、能够使用循环代替递归的尽量使用循环,循环的执行耗费内存少一些,
递归耗费内存相对多一些,另外递归使用不当很容易内存溢出,JVM停止工作。
当然,只有极少数情况下,只能用递归,其它代码解决不了问题。
2.5、当递归有结束条件,并且结束条件合法的时候,就一定不会内存溢出吗?
也不一定。可能递归的太深了。
2.6、分享了一些递归方面的经验
在实际的开发中遇到递归导致的栈内存溢出错误是怎么办?
第一步:先检查结束条件是否正确。
第二步:如果正确,可以调整JVM的栈内存大小。(java -X)
3、我们要一味地将变量缩减吗?代码缩减吗?这样好吗?
public class Test{
public static void main(String[] args){
/*
int i = 100;
System.out.println(i);
*/
System.out.println(100);
boolean flag = test();
if(flag){
...
}
// 缩减之后的
if(test()){
....
}
}
public static boolean test(){
return true;
}
}
太计较变量的数量会有什么后果呢?(运行效率不会低)
后果1:代码的可读性差。
后果2:可读性差也可以会牵连到代码的开发效率。
其实计算机内存不差这个。。。。。。
注意:在编码过程中,有一些变量名是必须要定义的。
因为在后面代码中还需要访问这个数据。重复的访问这个
数据。
/*
方法递归?
1、什么是方法递归?
方法自己调用自己,这就是方法递归。
2、当递归时程序没有结束条件,一定会发生:
栈内存溢出错误:StackOverflowError
所以:递归必须要有结束条件。(这是一个非常重要的知识点。)
JVM发生错误之后只有一个结果,就是退出JVM。
3、递归假设是有结束条件的,就一定不会发生栈内存溢出错误吗?
假设这个结束条件是对的,是合法的,递归有的时候也会出现栈内存溢出错误。
因为有可能递归的太深,栈内存不够了。因为一直在压栈。
4、在实际的开发中,不建议轻易的选择递归,能用for循环while循环代替的,尽量
使用循环来做。因为循环的效率高,耗费的内存少。递归耗费的内存比较大,另外
递归的使用不当,会导致JVM死掉。
(但在极少数的情况下,不用递归,这个程序没法实现。)
所以:递归我们还是要认真学习的。
5、在实际的开发中,假设有一天你真正的遇到了:StackOverflowError
你怎么解决这个问题,可以谈一下你的思路吗?
我来谈一下我的个人思路:
首先第一步:
先检查递归的结束条件对不对。如果递归结束条件不对,
必须对条件进一步修改,直到正确为止。
第二步:假设递归条件没问题,怎么办?
这个时候需要手动的调整JVM的栈内存初始化大小。
可以将栈内存的空间调大点。(可以调整大一些。)
第三步:调整了大小,如果运行时还是出现这个错误,
没办法,只能继续扩大栈的内存大小。
(java -X)这个可以查看调整堆栈大小的参数
*/
public class RecursionTest01{
// 入口
public static void main(String[] args){
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
// 目前这个递归是没有结束条件的,会出现什么问题?
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
/*
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
// 假设突然有一天,一个条件成立了,这个doSome结束了
if(某个条件成立了){
return;
}
}
*/
}
// 先不使用递归,请编写程序,计算1~n的和。
public class RecursionTest02{
public static void main(String[] args){
// 1~10的和
int retValue1 = sum(10);
System.out.println(retValue1);
// 1~3的和
int retValue2 = sum(3);
System.out.println(retValue2); // 6 (1 + 2 + 3)
}
// 单独编写一个计算1~n和的方法
public static int sum(int n){
int result = 0;
for(int i = 1; i <= n; i++){
result += i;
}
return result;
}
}
// 使用递归,请编写程序,计算1~n的和。
public class RecursionTest03{
public static void main(String[] args){
// 1~3的和
int n = 3;
int r = sum(n);
System.out.println(r); // 6
}
// 大家努力的去看,去听,自己写不出来没关系,关键是能不能看懂。
// 单独编写一个计算1~n和的方法
// 这个代码修改为递归的方式。
// 3 + 2 + 1
public static int sum(int n){
//n最初等于3
// 3 + 2 (2是怎么的出来的:n - 1)
//sum(n - 1);
if(n == 1){
return 1;
}
// 程序能执行到此处说明n不是1
return n + sum(n-1);
}
}
// 使用递归的方式计算N的阶乘
// 5的阶乘:5 * 4 * 3 * 2 * 1
// 用递归的方式实现一个。
// 使用for循环的方式实现一个。
public class RecursionTest04{
public static void main(String[] args){
int n = 5;
int jieGuo = jieCheng(n);
System.out.println(jieGuo); // 120
System.out.println(jieCheng2(5));
}
public static int jieCheng2(int n){
int result = 1;
for(int i = 2; i <= n; i++){
result *= i;
}
return result;
}
public static int jieCheng(int n){
// 5 * 4 * 3 * 2 * 1
if(n == 1){
return 1;
}
/*
int result = n * jieCheng(n - 1);
return result;
*/
return n * jieCheng(n - 1);
}
}
public class HelloWorld{
public static void main(String[] args){
//System.out.println("hello world!");
//错误: 找不到符号
//p("Hello World!");
S.p("Hello World!");
S.p(100);
S.p('a');
S.p(true);
S.p(100 + 200);
S.p(10 / 3);
// 调用hehe
HelloWorld.hehe();
hehe();
}
public static void hehe(){
System.out.println("呵呵");
}
}
public class Homework1{
public static void main(String[] args){
/*
// 计算5的阶乘
int n = 5;
int result = 1;
for(int i = n; i > 1; i--){
//System.out.println(i);
//result = result * i;
result *= i;
}
System.out.println(result);
*/
// 调用方法计算阶乘
int retValue1 = jieCheng(5);
System.out.println(retValue1); // 120
int retValue2 = jieCheng(6);
System.out.println(retValue2); // 720
}
// 提取一个方法出来,这个方法专门来计算某个数的阶乘
// 这个数不一定是5,可能是其他的值,可能是6,也可能是7,不确定
// 像这种不确定的数据,对于方法来说我们就可以定义为:形参。(形参类型定义为int)
// 该方法是为了完成阶乘的,最终是需要一个计算结果的,所以该方法应该有返回值。
// 将最后的结果返回给调用方。谁调用我,我就返回给谁。返回值类型定义为int
// 我这个方法可以计算任何数的阶乘。
public static int jieCheng(int n){
int result = 1;
for(int i = n; i > 1; i--){
result *= i;
}
return result;
}
}
/*
编写一个方法,输出大于某个正整数n的最小的质数
比如:这个正整数n是2
也就是要输出:大于2的最小的质数,结果就是3
比如:这个正整数n是9
也就是要输出:大于9的最小的质数,结果就是11
大于11的最小的质数是:13
思路:
首先,系统一定会先给你一个“正整数n”,然后你基于
这个n往后++,每加1得到的新数m判断一下是否为质数。
*/
public class Homework2{
public static void main(String[] args){
/*
// 假设目前系统给了一个正整数n,n为5
int n = 5;
// 请找出大于5的最小的质数
while(true){
n++; // n自加1
// 判断此时的n是否为质数
boolean flag = isZhiShu(n);
if(flag){
System.out.println(n);
break;
}
}
*/
// 对一个单独的方法进行测试
/*
boolean flag = isZhiShu(6);
System.out.println(flag ? "质数" : "非质数"); // true
*/
printZuiXiaoZhiShu(5);
printZuiXiaoZhiShu(10);
printZuiXiaoZhiShu(12);
printZuiXiaoZhiShu(100);
}
// 这方法就是用来打印最小质数的。
public static void printZuiXiaoZhiShu(int n){
while(true){
n++; // n自加1
// 判断此时的n是否为质数
boolean flag = isZhiShu(n);
if(flag){
System.out.println(n);
break;
}
}
}
// 定义一个专门的方法,来判断某个数字是否为质数
// 这个方法的形参是:被判断的数字num
// 这个方法的返回值类型是true表示是质数,是false表示非质数。
public static boolean isZhiShu(int num){
// 你怎么判断num是否是一个质数
// 质数只能被1和自身整除
for(int i = 2; i < num; i++){
if(num % i == 0){
return false;
}
}
//程序能够执行到此处说明num已经是质数了。
return true;
}
}
/*
编写一个方法,输出大于某个正整数n的最小的质数
比如:这个正整数n是2
也就是要输出:大于2的最小的质数,结果就是3
比如:这个正整数n是9
也就是要输出:大于9的最小的质数,结果就是11
大于11的最小的质数是:13
思路:
首先,系统一定会先给你一个“正整数n”,然后你基于
这个n往后++,每加1得到的新数m判断一下是否为质数。
*/
public class Homework22{
public static void main(String[] args){
printZuiXiaoZhiShu(7);
}
public static void printZuiXiaoZhiShu(int n){
while(!isZhiShu(++n)){
}
System.out.println(n);
}
public static boolean isZhiShu(int num){
for(int i = 2; i < num; i++){
if(num % i == 0){
return false;
}
}
return true;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix