zoukankan      html  css  js  c++  java
  • Java面向对象——方法(廖雪峰)

    一个class可以包含多个field,例如,我们给Person类就定义了两个field

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

    但是,直接把fieldpublic暴露给外部可能会破坏封装性。比如,代码可以这样写:

    Person ming = new Person();
    ming.name = "Xiao Ming";
    ming.age = -99; // age设置为负数 

    显然,直接操作field,容易造成逻辑混乱。为了避免外部代码直接去访问field,我们可以用private修饰field,拒绝外部访问:

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

    试试private修饰的field有什么效果:

    fieldpublic改成private,外部代码不能访问这些field,那我们定义这些field有什么用?怎么才能给它赋值?怎么才能读取它的值?

    所以我们需要使用方法(method)来让外部代码可以间接修改field

    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;
        }
    }

    观察上述代码,calcAge()是一个private方法,外部代码无法调用,但是,内部方法getAge()可以调用它。

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

    this变量

    在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。因此,通过this.field就可以访问当前实例的字段。

    如果没有命名冲突,可以省略this。例如:

    class Person {
        private String name;
    
        public String getName() {
            return name; // 相当于this.name
        }
    }

    但是,如果有局部变量和字段重名,那么局部变量优先级更高,就必须加上this

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

    方法参数

    方法可以包含0个或任意个参数。方法参数用于接收传递给方法的变量值。调用方法时,必须严格按照参数的定义一一传递。例如:

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

    调用这个setNameAndAge()方法时,必须有两个参数,且第一个参数必须为String,第二个参数必须为int

    Person ming = new Person();
    ming.setNameAndAge("Xiao Ming"); // 编译错误:参数个数不对
    ming.setNameAndAge(12, "Xiao Ming"); // 编译错误:参数类型不对

    可变参数

    可变参数用类型...定义,可变参数相当于数组类型:

    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

     

    参数绑定

    调用方把参数传递给实例方法时,调用时传递的值会按参数位置一一绑定。

    那什么是参数绑定?

    我们先观察一个基本类型参数的传递:

    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;
        }
    }

    运行代码,从结果可知,修改外部的局部变量n,不影响实例page字段,原因是setAge()方法获得的参数,复制了n的值,因此,p.age和局部变量n互不影响。

    结论:基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。

    我们再看一个传递引用参数的例子:

    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"还是"Alice"?
        }
    }
    
    class Person {
        private String name;
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    总结:字符串类型属于引用类型,String bob = ''Bob'';传入方法,name = "Bob",没有问题。当bob = "Alice"时,字符串变量bob有原来的Bob改指向Alice,但传入方法的"Bob"对象并没有改变,所以输出的仍为Bob。

    引用类型参数绑定01与02的比较
    01中参数为一个字符串类型的数组,改变数组中任意一项的值,都会导致这个数组对象发生改变。而02中仅仅是改变了变量的指向,并没有改变起先传入方法中的对象,因此结果不变。

     https://blog.csdn.net/sleepingposture/article/details/102912838

  • 相关阅读:
    获取具有指定扩展数据的所有实体的Id,并存入Id数组中
    FastDFS单机版安装教程
    Git简要开发流程
    Delay延迟队列
    HTTP调用接口方法
    Tomcat为什么要使用Facde模式对Request对象进行包装?
    SpringBoot注解
    <th:>标签使用
    Git命令速查表
    IDEA中对Git的常规操作(合并,提交,新建分支,更新)
  • 原文地址:https://www.cnblogs.com/William-xh/p/13625014.html
Copyright © 2011-2022 走看看