大学生入门:初识方法及其易踩坑的点

        在java学习过程中,我们不难发现有很多重复使用的功能代码块,每次使用如果都要重新写一遍,岂不是很麻烦,就算是“ cv ”大法,感觉也不是很方便,那么, 有什么办法可以解决这个问题呢?

        方法!

        java中,一段可重用的,用于执行特定功能的代码块叫做方法 ,它可以接收参数、返回结果,并且可以被多次使用。

一、方法的基本结构

[修饰符] 返回值类型 方法名([参数列表]) [throws 异常类型] {
    // 方法体
}

        [throws 异常类型]在IO、网络、数据库等底层操作中很常见,但是业务层出现频率不高,更倾向于try-catch捕获并处理,而不是抛出,作为初学者我们暂时可以不做研究,可以不写,后续需要用的时候在做详细学习

        我们现在主要研究一下它的其他组成部分:

1、修饰符:

        public:公用方法,可以被任何类访问

        protected:受保护的方法,可以在包内和子类中访问

        private:私有方法,只能在定义它的类中访问

        默认(不写):包访问权限,仅在同一个包内可以访问

权限宽松到严格:public -> protected -> 默认(不写) -> private

2、返回值类型

        方法必须声明返回值类型,就算没有也要使用void

3、方法名

        遵循小驼峰命名,eg:arrAvg(...){...}

4、参数列表

        可以有多个参数,但是参数类型必须明确

5、方法体

        实现功能逻辑的代码块

接下来我们看一下方法中最重要的兄弟俩:重载和重写

二、方法的重载

        在同一个类中定义的多个方法,它们方法名相同,而形参列表不同(数据类型不同、数量不同、顺序不同),这样就构成了方法的重载,与返回值类型无关

        eg:

//数据类型不同
public int add(int a, int b){
    return a + b;
}

public double add(double a, double b){
    return a + b;
}

//形参数量不同
public int add(int a, int b){
    return a + b;
}

public int add(int a, int b, int c){
    return a + b + c;
}

//形参顺序不同
public void print(int a, double b){
    System.out.println("int double");
}

public void print(double a, int b){
    System.out.println("double int");
}

        但是不推荐只是参数顺序不同构成的重载,避免引起调用歧义差劲的代码可读性

三、方法的重写

        子类继承父类的时候,可以重写父类的方法,从而提供不同的实现

eg:

class Animal {
    public void makeSound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark");
    }
}

        子类重写的方法名和参数列表必须和父类相同

        返回值类型不能比父类更宽

        访问权限不能比父类更严格(eg:父类protected,子类不能是private)

四、main方法

        这是java中特殊的方法,它是程序的入口点,我们前面提到的jvm启动时会寻找并执行这个方法。

        ——它的签名是固定的,必须是public static void main(String[] xxx)

        ——每个程序有且仅有一个入口方法

                这里指的是一个应用程序,一个项目中可以有多个main,但是只能把一个设为程序的入口,其他可以是测试入口,比如用我们之前提到的java命令,在终端中运行,eg:

                java Application                //运行应用程序

                java TestClass                  //运行测试

        ——自动调用,由jvm执行,不需要手动调用

五、静态方法

        ——使用static关键字修饰的方法,属于类,不属于对象

        ——可以通过类名直接调用,无需创建对象

public class Test {
    public static void main(String[] args) {
        // 静态方法可以直接通过类名调用
        MyClass.staticMethod();
        
        // 实例方法需要先创建对象
        MyClass obj = new MyClass();
        obj.instanceMethod();
    }
}

        ——不能直接访问非静态成员的变量和方法

public class Example {
    private int instanceVar = 10;
    private static int staticVar = 20;
    
    public static void staticMethod() {
        // System.out.println(instanceVar);  // ❌ 编译错误!不能访问实例变量
        System.out.println(staticVar);       // ✅ 可以访问静态变量
        
        // instanceMethod();                 // ❌ 编译错误!不能调用实例方法
        staticMethod2();                     // ✅ 可以调用其他静态方法
    }
    
    public static void staticMethod2() {
        System.out.println("另一个静态方法");
    }
    
    public void instanceMethod() {
        System.out.println(instanceVar);     // ✅ 实例方法可以访问实例变量
        System.out.println(staticVar);       // ✅ 实例方法也可以访问静态变量
        staticMethod();                      // ✅ 实例方法可以调用静态方法
    }
}

                诶,那有没有间接访问的办法呢?

                有的兄弟有的

                1、创建类的实例对象(最常见)

public class Example {
    private int instanceVar = 100;
    private String name = "张三";
    
    // 静态方法
    public static void staticMethod() {
        // ❌ 直接访问 - 编译错误
        // System.out.println(instanceVar);
        
        // ✅ 间接访问 - 通过创建对象实例
        Example obj = new Example();
        System.out.println(obj.instanceVar);  // 输出: 100
        System.out.println(obj.name);         // 输出: 张三
    }
    
    public static void main(String[] args) {
        staticMethod();
    }
}

                2、通过参数传递对象实例

public class Person {
    private String name;
    
    public Person(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    // 静态方法通过参数访问非静态成员
    public static void printPersonInfo(Person person) {
        System.out.println("姓名: " + person.getName());  // 通过参数访问
    }
    
    public static void main(String[] args) {
        Person p = new Person("李四");
        printPersonInfo(p);  // 输出: 姓名: 李四
    }
}

                3、在静态方法内部创建并使用对象

public class Calculator {
    private int result = 0;
    
    public void add(int value) {
        result += value;
    }
    
    public int getResult() {
        return result;
    }
    
    public static void performCalculation() {
        // 在静态方法中创建对象并使用
        Calculator calc = new Calculator();
        calc.add(10);
        calc.add(5);
        System.out.println("计算结果: " + calc.getResult());  // 输出: 计算结果: 15
    }
    
    public static void main(String[] args) {
        performCalculation();
    }
}

        ——不能使用this和super关键字

六、构造方法

        ——方法名和类名相同

        ——没有返回值类型,void也不能写

        ——可以重载

eg:

public class Person {
    public Person() {
        // 默认构造方法
    }

    public Person(String name) {
        // 带参构造方法
    }
}

七、易踩坑的点

1、方法声明

        ——返回值类型 和实际return的值类型一定要相同

        ——形参列表中数据类型变量名不可以少

2、方法调用

        ——普通方法可以调用普通方法,但是不能调用main方法

        ——方法必须先定义再使用

        ——实际参数类型一般要和形参类型一致(除非可以隐式类型转换,但是不建议)

3、重载——关于形参顺序不同

        这种情况不是重载:

        重载和变量名无关,重点是变量的数据类型

public int add(int a, int b){
    return a + b;
}

public int add(int b, int a){
    return b + a;
}

4、静态方法被对象调用的错误理解

        虽然 对象调用静态方法是合法的,但是这样会误导大家,以为是实例方法,其实本质还是类调用的静态方法,平时一定注意避免这种写法!

        不仅创建不必要的对象浪费性能,还会产生误导性,导致代码可读性差

public class MyClass {
    public static void staticMethod() {
        System.out.println("静态方法");
    }
}

public class Main {
    public static void main(String[] args) {
        // 推荐方式:通过类名调用
        MyClass.staticMethod();
        
        // 不推荐但合法:通过对象调用静态方法
        MyClass obj = new MyClass();
        obj.staticMethod();  // 可以工作,但不建议这样做
    }
}

5、误以为对象是引用传递(传递地址)

        java中所有参数传递都是值传递,包括对象引用也是传递引用的值(副本)

public static void changeValue(StringBuilder sb) {
    // sb是原引用的一个副本,指向同一个对象
    sb = new StringBuilder("new");  // 修改的是副本引用,指向新对象
    // 原来的sb引用没有改变
}

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder("old");  // sb指向"old"对象
    System.out.println("调用前: " + sb.toString());  // 输出: old
    
    changeValue(sb);  // 传递sb引用的值(地址副本)
    
    System.out.println("调用后: " + sb.toString());  // 输出: old(未改变)
}

6、 方法重载——歧义问题

public void print(int nums) {}
public void print(double nums) {}

// 调用
print(1);  // 编译错误:不明确的方法调用

当调用print(1)时,1是int,可以匹配int,也可以自动类型转换匹配double,编译器选择困难了

今天的分享就到这里,欢迎大家补充斧正

你可能感兴趣的:(大学生入门:初识方法及其易踩坑的点)