13-方法及构造

北城余情 提交于 2019-11-28 17:46:34
方法是java语言中非常基本的一个组成。
一个class可以包含多个field但是,直接把field用public暴露给外部可能会破坏封装性,使用private修饰field,可以拒绝外部访问。
class Person {
    private String name;
    private int age;
}

把field从public改成private,外部代码不能访问这些field,需要使用方法(method)来让外部代码可以间接修改field。
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());
    }
}

class Person {
    private String name;
    private int age;

    public String getName() {
        return this.name;
    }//this表示实例本身

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        if (age < 0 || age > 100) {
            throw new IllegalArgumentException("invalid age value");
        }//超出范围抛出异常
        this.age = age;
    }
}

虽然外部代码不能直接修改private字段,但是,外部代码可以调用类中定义的方法setName()和setAge()来间接修改private字段。在方法内部,我们就有机会检查参数对不对。所以,一个类通过定义方法,就可以给外部代码暴露一些操作的接口,同时,内部自己保证逻辑一致性。

定义方法
外部代码通过public方法操作实例,内部代码可以调用private方法。
修饰符 方法返回类型 方法名(方法参数列表) {
    若干方法语句;
    return 方法返回值;
}
//返回类型void 无需return


private方法
相比于public方法,private方法和private字段一样,不允许外部调用,定义private方法的理由是内部方法是可以调用private方法的。例如:
public class Main {
    public static void main(String[] args) {
        Person ming = new Person();
        ming.setBirth(2008);
        System.out.println(ming.getAge());
    }
}

class Person {
    private String name;
    private int birth;

    public void setBirth(int birth) {
        this.birth = birth;
    }

    public int getAge() {
        return calcAge(2019); // 调用private方法
    }

    // private方法:
    private int calcAge(int currentYear) {
        return currentYear - this.birth;
    }
}


这个Person类没有定义age字段,获取age时,通过方法getAge()返回的是一个实时计算的值,并非存储在某个字段的值。这说明方法可以封装一个类的对外接口,调用方不需要知道也不关心Person实例在内部到底有没有age字段。

this变量
在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。如果没有命名冲突,可以省略this,但是,如果有局部变量和字段重名,那么局部变量优先级更高,就必须加上this:
class Person {
    private String name;

    public void setName(String name) {//局部变量 name
        this.name = name; // 前面的this不可少,少了就变成局部变量name了
    }
}


可变参数
可变参数用 类型... 定义,可变参数相当于数组类型:
class Group {
    private String[] names;
//可变字符型
    public void setNames(String... names) {
        this.names = names;
    }
}
//调用
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[]类型,但调用方需要自己先构造String[],而且调用方可以传入null,
而可变参数可以保证无法传入null,因为传入0个参数时,接收到的实际值是一个空数组而不是null。
Group g = new Group();
g.setNames(new String[] {"Xiao Ming", "Xiao Hong", "Xiao Jun"}); 
// 传入1个String[]
Group g = new Group();
g.setNames(null);
//传入null


参数绑定
基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。
public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        int n = 15; // n的值为15
        p.setAge(n); // 传入n的值
        System.out.println(p.getAge()); // 15
        n = 20; // n的值改为20
        System.out.println(p.getAge()); // 15
    }
}

class Person {
    private int age;

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}



引用类型参数的传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方。
public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        String bob = "Bob";
        p.setName(bob); // 传入bob变量
        System.out.println(p.getName()); // "Bob"
        bob = "Alice"; // bob改名为Alice
        System.out.println(p.getName()); // "Bob"
    }
}

class Person {
    private String name;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}



构造方法
构造方法就是在创建实例的同时初始化实例中的字段。
public class Main {
    public static void main(String[] args) {
        Person p = new Person("Xiao Ming", 15);
        System.out.println(p.getName());
        System.out.println(p.getAge());
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }//构造方法
    
    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

构造方法的名称就是类名,构造方法的参数没有限制,在方法内部,也可以编写任意语句。但是,和普通方法相比,构造方法没有返回值(也没有void),调用构造方法,必须用new操作符。如果一个类没有定义构造方法,编译器会自动生成一个默认构造方法,它没有参数,也没有执行语句,默认构造方法,初始化实例的时候:引用类型的字段默认是null,数值类型的字段用默认值,int类型默认值是0,布尔类型默认值是false。手动编写构造方法后,就不会在自动生成默认构造。
class Person {
    public Person() {
    }
}//编译器自动生成的默认构造方法


多构造方法
可以定义多个构造方法,在通过new操作符调用的时候,编译器通过构造方法的参数数量、位置和类型自动区分。
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {//方法1
        this.name = name;
        this.age = age;
    }

    public Person(String name) {//方法2
        this.name = name;
        this.age = 12;
    }

    public Person() {//方法3
    }
}
/*
如果调用new Person("Xiao Ming", 20);,会自动匹配到构造方法1
如果调用new Person("Xiao Ming");,会自动匹配到构造方法2
如果调用new Person();,会自动匹配到构造方法3
*/

一个构造方法可以调用其他构造方法,这样做的目的是便于代码复用。调用其他构造方法的语法是this(…)
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {//方法1
        this.name = name;
        this.age = age;
    }

    public Person(String name) {//方法2
        this(name, 18); // 调用方法1
    }

    public Person() {//方法3
        this("Unnamed"); // 调用方法2
    }
}


方法重载
在一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法,也称为方法重载(Overload)。
注意:方法重载的返回值类型通常都是相同的。
class Hello {
    public void hello() {
        System.out.println("Hello, world!");
    }

    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public void hello(String name, int age) {
        if (age < 18) {
            System.out.println("Hi, " + name + "!");
        } else {
            System.out.println("Hello, " + name + "!");
        }
    }
}

String类提供了多个重载方法indexOf(),可以查找子串:
int indexOf(int ch):根据字符的Unicode码查找;
int indexOf(String str):根据字符串查找;
int indexOf(int ch, int fromIndex):根据字符查找,但指定起始位置;
int indexOf(String str, int fromIndex)根据字符串查找,但指定起始位置。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!