首页 > 其他分享 >003-方法

003-方法

时间:2024-03-12 20:44:41浏览次数:33  
标签:String int void 003 static 方法 public

方法

  • 方法:实现了代码复用
[修饰符列表] + 返回值 + 方法名 + (形式参数列表){
	方法体;
}

形式参数列表中每一个参数都是一个局部变量,方法结束之后内存释放;

形参的数据类型起决定性作用,形参对应的变量名是随意的

方法调用语句: 类名.方法名

public class MethodTest01 {
    public static void main(String[] args) {
        MethodTest01.pr1();
        MethodTest01.pr2();//若方法都在同一个类中,类名.是可以省略的
    }
    public static void pr1(){}
    public static void pr2(){}
}
class My{
    //若在一个类中调用另一个类的方法,类名.是不能省略的
}

方法调用时参数传递

public static void main(String[] args){
    Person p = new Person();
    p.age = 10;
    add(p);
    System.out.println(p.age); //11
}

public static void add(Person p){
    p.age++;
    System.out.println(p.age); //11
}

以上的两个p,在栈中属于两个不同的方法栈帧,但是指向了堆内存中的同一个对象,所以访问到了同一个实例变量

练习题

生成五位验证码:

StringBuilder builder = new StringBuilder();
char[] chs = new char[52];
for (int i = 0; i < 52; i++) {
	chs[i] = i < 26 ? (char)('A' + i) : (char)('a' + (i - 26)); //注意减26
}
Random random = new Random();
for (int i = 0; i < 4; i++) {
	builder.append(chs[random.nextInt(chs.length)]);
}
builder.append(random.nextInt(10));

内存结构

栈内存 堆内存 方法区
方法执行所需的空间及该方法的局部变量 对象及对象的实例变量 类加载器将字节码文件装在到JVM的时候,会将字节码文件存入方法区,存储的是代码片段
局部变量 对象 静态变量
  • 类先加载:方法区先有数据
  • new 实际上是在堆内存中开辟了一块空间
  • 栈:方法被调用时,该方法需要的内存空间在栈中分配

局部变量:只在方法体中有效,方法结束后局部变量的内存空间就被释放了

注意:

  1. 方法区最先有数据,方法区中存放代码片段,class字节码
  2. 栈内存:方法调用时,该方法所需的内存在栈中分配,方法不调用时不会在栈中分配内存的

image.png

栈内存 stack

存储:局部变量。

  1. 基本数据类型的局部变量,在栈内存中存储的是“数据值”。
  2. 引用数据类型的局部变量,在栈内存中存储的是“地址值”。

栈内存特点:

  1. 栈内存具备“先进后出”或“后进先出”的特点。
  2. 栈内存是一块连续的内存空间,由系统自动分配,效率高!
  3. 虚拟机会为每个线程创建一个栈内存,用于存放该线程执行方法的信息。

栈内存的组成:

073db95bf4e24f2fbfb3850b16a2fe9f.jpeg

堆内存heap

存储:数组或对象

  1. 在堆内存中创建数组或对象成功后,还可以在栈内存中定义一个局部变量,让该局部变量来存储创建在堆内存中数组或对象的首地址,这样该变量就引用了堆内存中的数组或对象。
  2. 数组和对象在没有变量指向(引用)它的时候,则数组或对象本身占用的堆内存空间就变成垃圾,然后就被Java虚拟机的自动垃圾回收器(GC)释放了该存储空间,这样该数组或对象就不能被使用了,否则就会抛出空指针异常(NullPointerException)。

堆内存特点:

  1. 虚拟机中只有一个堆内存,被所有的线程共享。
  2. 堆内存是一个不连续的内存空间,分配灵活,效率低!

方法重载

方法重载机制:功能相似的,可以让其方法名相同

编译器在区分的时候,会首先根据方法名进行区分;如果方法名相同的,再用参数类型进行区分 (也就是说返回值类型是无法区分的)

重载时通过参数的静态类型而不是实际类型进行区分;静态类型在编译期可知,在编译阶段,javac编译器就根据静态类型决定来调用哪个版本的方法。

静态分派发生在编译阶段,确定静态分派的动作实际上不是由虚拟机执行的。

满足三个条件:

  1. 在同一个类当中
  2. 方法名不同
  3. 参数列表不同
  • 方法重载与返回值类型修饰符列表无关

对于println方法来说,参数类型是随意的,说明println()是方法重载

System.out.println();

也可以手动对println方法进行封装:

class S{
    public static void p(){
        System.out.println();
    }
    public static void p(byte b){
        System.out.println(b);
    }
    public static void p(int b){
        System.out.println(b);
    }
    public static void p(long b){
        System.out.println(b);
    }
    public static void p(char b){
        System.out.println(b);
    }
    public static void p(String b){
        System.out.println(b);
    }
    public static void p(boolean b){
        System.out.println(b);
    }
    public static void p(float b){
        System.out.println(b);
    }
    public static void p(double b){
        System.out.println(b);
    }
}

调用的时候就可以:

public class OverLoadTest01 {
    public static void main(String[] args) {
        S.p(10);
        S.p(10.0);
        S.p(true);
    }
}

注意:源码当中一个方法以;结尾并且用native关键字修饰 表示调用了底层C++写的dll程序

构造方法重载

构造方法默认支持方法重载,因为方法名必须和类名保持一致

但是注意,方法重载要求参数列表不同,也就是说:

public Person(String name){
    
}
public Person(String age){
    
}

这两个构造方法是不能重载的,因为参数名称不同并不是参数列表不同。

构造方法虽然在没有返回值类型,但是执行结束之后会返回会该对象的内存地址,也就是用定义好的 引用 来接受

char类型参数的方法重载

public static void main(String[] args) {  
	sayHi('a');  
}  
  
public static void sayHi(int i){  
  
}  
  
public static void sayHi(char c){  
  
}

这时调用的是char类型参数的sayHi方法,如果注释调这个方法,只保留int类型的sayHi,编译运行都是没问题的,因为 'a' 除了代表一个字符之外,还可以代表数字97

以下程序是没有问题的:

public static void main(String[] args) {  
	sayHi('a');   //char自动转换为int
}  
public static void sayHi(int i){  
	System.out.println(i);  
}  
  
// public static void sayHi(char c) {  
//  
// }

但是如果注释int类型参数的方法,在main方法中就不能将int类型赋值给char类型:

public static void main(String[] args) {  
	sayHi(97);  //java: 不兼容的类型: 从int转换到char可能会有损失 
}  
/* public static void sayHi(int i){  
System.out.println(i);  
}*/  
  
public static void sayHi(char c) {  
  
}

编译器只知道传递的参数是int类型的,不知道具体的值

byte、short类型参数的重载

public class Overload {  
	public static void sayHello(byte arg){  
		System.out.println("hello byte");  
	}  
	  
	public static void sayHello(short arg){  
		System.out.println("hello short");  
	}  
	  
	public static void main(String[] args) {  
		sayHello(1);  
	}  
}

编译报错:

java: 对于sayHello(int), 找不到合适的方法
    方法 Overload.sayHello(byte)不适用
      (参数不匹配; 从int转换到byte可能会有损失)
    方法 Overload.sayHello(short)不适用
      (参数不匹配; 从int转换到short可能会有损失)

因为字面量默认被当作int类型处理,int类型不能自动转型到byte或short,要解决这个问题,就要指明参数的静态类型:

sayHello((byte) 1);  
sayHello((short) 1);

可变长参数

例如:

public static void test(int...num){
        
    }

表示test方法可以接受0 - n个int类型的参数,也就是可以不传参数,也可以传多个参数

public static void main(String[] args) {
    test();
    test(1);
    test(1,2,3,4);
}
public static void test(int...num){
    System.out.println("test method execute");
}

注意:可变长参数列表只能出现1个,并且只能出现在参数列表的最后一个位置上

另外,可变长参数可以当作数组处理:

public static void test(int...num){
    for (int i = 0; i < num.length; i++) {
        System.out.print(num[i]);
    }
    System.out.println();
}

可变长参数可以是任何类型的值

class Group {
    private String[] names;

    public void setNames(String... names) {
        this.names = names;
    }
}

上面的setNames()就定义了一个可变参数。调用时,可以这么写:

Group g = new Group();
g.setNames("Xiao Ming", "Xiao Hong", "Xiao Jun"); // 传入3个String
g.setNames("Xiao Ming", "Xiao Hong"); // 传入2个String
g.setNames("Xiao Ming"); // 传入1个String
g.setNames(); // 传入0个String

完全可以把可变参数改写为String[]类型:

class Group {
    private String[] names;

    public void setNames(String[] names) {
        this.names = names;
    }
}

但是,调用方需要自己先构造String[],比较麻烦。例如:

Group g = new Group();
g.setNames(new String[] {"Xiao Ming", "Xiao Hong", "Xiao Jun"}); // 传入1个String[]

另一个问题是,调用方可以传入null

Group g = new Group();
g.setNames(null);

而可变参数可以保证无法传入null,因为传入0个参数时,接收到的实际值是一个空数组而不是null

方法递归

归化递归

方法递归三要素:

  • 递归公式
  • 递归终结点
  • 递归方向必须走向终结点

计算 n!

归化递归都可以根据以上三要素计算出递归过程

递归公式:f(n) = f(n - 1) * n

递归终结点:f(1) = 1

递归方向必须走向终结点:从 f(10) 递向f(1),所以递归公式是f(n) = f(n - 1) * n

public static int factorial(int n){  
    if (n == 1)  
        return 1;  
    return factorial(n - 1) * n;  
}

猴子摘桃

猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。

递归公式:f(n + 1) = f(n) / 2 - 1

递归终结点:f(10) = 1

递归方向:f(1) 递归到 f(10) ,所以要改变递归公式为 f(n) = 2 * f(n + 1) + 2

public static int monkey (int day){  
    if(day == 10)  
        return 1;  
    return 2 * monkey(day + 1) + 2;  
}

上台阶

小明一次可以爬一阶或两阶楼梯,20层楼有几种走法?

由以上内容可知:

$$
F(20) = F(19) + F(18)
$$
走到20层楼的走法 = 走到19楼再走向20楼的走法 + 走到18楼再走向20楼的走法是一致的。

  • 走到19楼再走向20楼的走法:上一阶
  • 走到18楼再走向20楼的走法:上两阶,因为从18楼上一阶的走法和19楼再走向20楼的上一阶走法重复了

递归公式为:f(n) = f(n - 1) + f(n - 2)

递归终结点为:f(1) = 1 到1楼有一层走法 和 f(2) = 2 到2楼有两层走法

递归方向:f(20)f(1) f(2)

非归化递归

见[[011-IO#统计每种文件个数并打印|统计每种文件个数并打印 BFS]]

标签:String,int,void,003,static,方法,public
From: https://www.cnblogs.com/euneirophran/p/18069229

相关文章

  • 轻松掌握锁冲突问题的排查方法——《OceanBase诊断系列》之八
    1.前言OceanBase数据库通过两阶段封锁机制确保读写事务并发控制的正确性。在高冲突场景下,事务处理中经常会遇到行锁冲突的问题。然而,许多OceanBase用户对于何时发生锁冲突,锁冲突的表现如何,以及如何排查锁冲突的原因,甚至于定位具体的行与锁冲突的会话。本文为读者提供一个系统......
  • 面试必考的 3 种类型检测方法,分享给你
    如果现在给你一个变量,你能快速检测出是哪种类型么?1.检测基本类型typeof 是一个用于检测数据类型的操作符,返回一个表示数据类型的字符串。可以用于检测数字、字符串、布尔等基本数据类型:typeof42;//"number"typeof"Hello";//"string"typeoftrue;......
  • 自动生成hashcode和equals方法
    右键一键生成importjava.util.Objects;publicclassStudent{privateStringname;privateintage;publicStudent(){}publicStudent(Stringname,intage){this.name=name;this.age=age;}publicStringgetName(){......
  • FANUC发那科数控采集方法
    Overview本文介绍如何使用FANUC官方提供的开发套件FOCAS1/2采集编程语言:C++API说明:https://www.inventcom.net/fanuc-focas-library/general/fwlib32创建项目1.新建vs2022中的c++控制台项目2.添加头文件Fwlib32.h3.配置动态链接库项目-属性-链接器-常规-附加库目录(填入.l......
  • tomcat无法启动的解决方法
    一:双击startup.bat但闪退我们可以用记事本打开startup.bat在末尾添加一个pause这样它就会新建一个窗口停在错误的地方二:根据报错信息改正这一步如果有乱码可以进入tomcat的conf目录下logging.properties找到java.util.logging.ConsoleHandler.encoding=utf-8这行更改......
  • 【计算机网络01】网卡——链接5G热点网速较慢问题解决方法。
    计算机网络:网卡一、网卡带宽查询二、高速带宽设置一.在电脑连接手机热点的时候,查询网络属性,找到网络频带是2.4GHz,带宽是72(Mbps):查找原因,发现是手机热点页面中AP频带设置的原因,AP频带设置成了2.4GHz:二.更改手机热点页面中AP频带,将AP频带设置成了5GHz频段:再在电......
  • Android 发布aar远程依赖出现扩展方法无法找到问题
    原文:Android发布aar远程依赖出现扩展方法无法找到问题-Stars-One的杂货小窝起因最近在整合自己的工具类库,偶然发现之前写的扩展方法使用远程依赖却是提示找不到但我有个aar库却是正常的,于是看了下这两者的区别,发现是build.gradle多了下面这个导致的问题packagingOptio......
  • github官网访问不到的解决方法
    解决方案: 1)在键盘同时按住win+R输出cmd 2)在命令行窗口输入ping github.com 获取GitHub的官网IP    3)配置hosts文件,绕过DNS解析过程  打开电脑C:\Windows\System32\drivers\etc下的hosts文件编辑(需要管理员权限,右键,管理员权限打开),新增如下一行配置:20.205.243......
  • 不同环境下拼接外链的方法
    截取浏览器urlfunctiongetBowserUrl(path){letresult='';if(path){//获取当前URLvarcurrentURL=window.location.href;//使用URLAPI来解析URLvarurlObject=newURL(currentURL);//如果URL中有端口号,它......
  • A接口实现类中a方法调用了c方法,B接口的实现类b方法也需调用A接口的实现类中的c方法,在j
    1.情景展示在实际开发过程中,往往会存在这样的情况:在A接口的实现类a方法实现了某个功能,现在B接口的实现类b方法也需要实现此功能,两者大致相同。为了提高代码的复用性,我们可以把A接口的实现类a方法的具体实现过程进行封装成c方法,供A、B两个接口的实现类调用。2.具体分析第一......