Java从入门到放弃(二十):方法

类与字段

一个类可以定义多个字段,这些字段用于存储对象的状态信息。例如,我们可以为Person类定义两个字段:nameage

class Person {
    public String name;
    public int age;
}

然而,将字段设置为public会使它们对外公开,这可能会破坏类的封装性。为了保护字段不被外部代码直接访问和修改,我们通常会将字段声明为private

class Person {
    private String name;
    private int age;
}

这样做的好处是,我们可以控制对这些字段的访问,确保对象的状态不会被外部代码随意改变,从而维护了对象的完整性和一致性。

方法的定义和参数

方法的定义遵循以下语法:

修饰符 返回类型 方法名(参数列表) {
    // 方法体
    return 返回值;
}

方法可以有返回值,也可以没有。如果没有返回值,则返回类型为void

方法的参数允许我们传递值给方法。调用方法时,必须按照参数的定义顺序传递相应的值。

this变量

当我们在方法中访问一个与实例字段同名的局部变量时,Java会优先考虑局部变量。为了访问实际的实例字段,我们需要使用this关键字。例如:

class Person {
    private String name;

    public String getName() {
        // 这里不需要使用this,因为name没有同名的局部变量
        return name; // 访问实例字段name
    }
    
    public void setName(String name) {
        // 这里的name是方法参数,与实例字段name同名
        // 为了区分它们,我们需要使用this来指代实例字段
        this.name = name; // 设置实例字段name的值
    }
}

在上面的setName方法中,我们通过this.name明确地告诉编译器我们想要操作的是实例字段name,而不是方法参数name。在没有命名冲突的情况下,this是可以省略的。例如,在getName方法中,由于没有局部变量与实例字段name同名,我们可以直接使用name而不需要this.name

方法的使用

当我们将字段设置为private后,外部代码将无法直接访问这些字段。为了能够对这些字段进行赋值和读取,我们需要定义公共的方法(public methods)。

public class Main {
    public static void main(String[] args) {
        Person ming = new Person();
        ming.setName("Xiao Ming"); // 使用方法设置name
        ming.setAge(12); // 使用方法设置age
        System.out.println(ming.getName() + ", " + ming.getAge()); // 使用方法获取并打印name和age
    }
}

class Person {
    private String name;
    private int age;

    // 获取name的方法(访问器)
    public String getName() {
        return this.name;
    }

    // 设置name的方法(修改器)
    public void setName(String name) {
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("invalid name");
        }
        this.name = name.strip(); // 去除首尾空格
    }

    // 获取age的方法(访问器)
    public int getAge() {
        return this.age;
    }

    // 设置age的方法(修改器)
    public void setAge(int age) {
        if (age < 0 || age > 100) {
            throw new IllegalArgumentException("Age must be between 0 and 100.");
        }
        this.age = age;
    }
}

在这个例子中,setNamesetAge是修改器方法,它们允许外部代码设置nameage字段的值。同时,getNamegetAge是访问器方法,它们允许外部代码获取这些字段的值。通过这些方法,我们可以在内部进行逻辑检查,确保传入的参数是有效的,从而避免了不合理的值被赋给字段。

方法参数

当定义一个方法时,我们可以指定每个参数的类型和顺序。例如,setNameAndAge方法接受两个参数,第一个是String类型,第二个是int类型。

class Person {
    ...
    public void setNameAndAge(String name, int age) {
        ...
    }
}

在调用这个方法时,必须提供两个参数,类型也要匹配:

Person ming = new Person();
ming.setNameAndAge("Xiao Ming", 30); // 正确调用,提供了两个参数

可变参数

Java允许使用可变参数,这是一种特殊的参数,可以接受任意数量的参数。可变参数使用省略号(...)来定义,实际上是一个数组。

class Group {
    private String[] names;

    public void setNames(String... names) {
        this.names = names; // 将可变参数names赋值给数组names
    }
}

使用可变参数,可以简化方法调用,不需要手动创建数组:

Group g = new Group();
g.setNames("Xiao Ming"); // 传入1个String
g.setNames("Xiao Ming", "Xiao Hong"); // 传入2个String
g.setNames(); // 传入0个String,names数组将被设置为空数组

参数绑定

基本类型的参数传递是通过值的复制来实现的。这意味着方法接收的是参数值的一个副本,而不是参数本身。因此,方法内部对参数的任何修改都不会影响到原始变量。

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        int n = 15;
        p.setAge(n);
        System.out.println(p.getAge()); // 输出 15
        n = 20;
        System.out.println(p.getAge()); // 输出仍然是 15,因为n的修改不影响p的age字段
    }
}

在这个例子中,n的值被复制给了setAge方法的参数。即使n的值之后被改变,p对象的age字段保持不变,因为它们是独立的副本。

与基本类型不同,引用类型的参数传递实际上是对引用的传递。这意味着方法接收的是对象引用的副本,而不是对象本身的副本。

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        String[] fullname = new String[] { "Homer", "Simpson" };
        p.setName(fullname);
        System.out.println(p.getName()); // 输出 "Homer Simpson"
        fullname[0] = "Bart";
        System.out.println(p.getName()); // 输出 "Bart Simpson",因为fullname和p.name指向同一个数组
    }
}

在这个例子中,fullname数组的引用被传递给了setName方法。因此,当fullname数组的内容被修改后,p对象的name字段也会受到影响,因为它们指向同一个数组。

字符串(String类型)在Java中是不可变的(immutable)。这意味着一旦字符串被创建,它的内容就不能被改变。

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        String bob = "Bob";
        p.setName(bob);
        System.out.println(p.getName()); // 输出 "Bob"
        bob = "Alice";
        System.out.println(p.getName()); // 输出仍然是 "Bob",因为字符串内容不可变
    }
}

在这个例子中,尽管bob变量的引用被改变了,指向了一个新的字符串,但这不影响p对象的name字段,因为setName方法保存的是字符串的引用,而不是字符串本身。由于字符串内容不可变,p.getName()方法返回的仍然是原始的字符串内容”Bob”。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧