• java方法


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

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

    但是,直接把field用public暴露给外部可能会破坏属性的封装。可能会被重新定义,比如:

    Person ming = Person();
    ming.name = “ming”;
    ming.age = 18;

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

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

    示例:

    package com.imooc.objectoriented;
    
    class Person {
        private String name;
        private int age;
    }
    
    public class ObjectMethod {
        public static void main(String[] args) {
            Person ming = new Person();
            ming.name = "mingwang";
            ming.age = 26;
            System.out.println(ming.name);
        }
    }

    打印结果:

    现在既然我们无法从外部读取对象的属性,那么我们该如何进行访问了?
    我们可以在对象内部设置一些方法,这样就可以通过内部方法来访问对象的属性值。

    package com.imooc.objectoriented;
    
    class Person {
        private String name;
        private int age;
    
        public String getName() {
            return this.name;
        }
    
        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;
        }
    }
    
    public class ObjectMethod2 {
        public static void main(String[] args) {
            Person ming = new Person();
            ming.setName("mingwang");
            ming.setAge(18);
            System.out.println(ming.getName());  //mingwang
            System.out.println(ming.getAge());   //18
        }
    }

    这样我们就可以间接的查询和修改private字段。
    还可以检查传入的参数,参数超出了范围,可以直接报错。
    这样外部代码就没有任何机会把age设置成不合理的值。

    当然我们还可以对参数进行检查:

    public void setName(String name) {
        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("invalid name");
        }
        this.name = name;
    }

    在python和go中,虽然没有public和private这两个字段,都有类似的处理方式。
    在python中,类中属性的封装与Java基本类似,在go语言中,没有class,但是可以用方法来绑定对象。

    定义方法

    修饰符  方法返回类型  方法名(方法参数列表) {
            若干方法语句
            return 方法返回值;
    }

    方法返回值通过return语句实现,如果没有返回值,返回类型设置为void,可以省略return;

    private方法

    public方法可以定义变量、方法和类。private也是可以,只是外部就无法访问了。

    如果定义private无法从外部来访问,那么这种定义方式还有任何意义吗?
    答案是否定的,存在即是必然,既然外部无法访问,那么就从内部进行访问。
    示例如下:

    package com.imooc.objectoriented;
    
    class PersonMan {
        private String name;
        private int birth;
    
        public void setBirth(int birth) {
            this.birth = birth;
        }
        //创建公开方法,返回年纪
        public int getAge() {
            return calcAge(1992);
        }
        //创建私有方法,获取年纪
        private int calcAge(int currentYear) {
            return this.birth - currentYear;
        }
    }
    
    public class ObjectPrivate {
        public static void main(String[] args) {
            PersonMan ming = new PersonMan();
            ming.setBirth(2019);
            System.out.println(ming.getAge());
        }
    }

    由于对象PersonMan全部定义的都是private属性,因此是无法直接从外部赋值的。
    在python中,由类创建对象的时候就会给属性赋值。

    在此处,封装了一个类的对外接口,调用着不需要清楚PersonMan内部是否实现了age字段。

    this变量

    在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。
    但是如果没有命名冲突,可以省略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) {
           ... 
        }
    }

    定义参数时,参数类型在前,参数名称在后。
    在python中,变量属于动态定义,因此不需要注意参数类型与参数名称的顺序。
    在go中,变量名称在前,变量类型在后。
    Java与go在形式上面的最大差别,java类型在前,名称在后,Go名称在前,类型在后。

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

    Person ming = new Person();
    ming.setNameAndAge("ming");  //参数个数不对
    ming.setNameAndAge(12,"ming")  //参数类型不对

    可变参数

    可变参数用类型...定义,可变参数相当于数组类型(与python中,args*/kwargs**类似):

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

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

    Group g = new Group();
    g.setNames("kebi", "maoxian", "ming")  //传入三个参数
    g.setNames("kebi", "ming")  //传入两个参数

    在python中,也有类似功能,称为参数的处理与逆过程。
    在Go语言中,也有类似变参的传参方法,比如func test(s string, a ...int)

    貌似这个也没什么用,好像可以使用String[]来替换String...:

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

    这里setNames需要传入一个数组,而不是一个一个的参数。
    这样你在传参的时候,需要先构建String[],比较麻烦。

    Group g = new Group();
    g.setNmaes(new String[] {"ming","kebi","song"})  //需要传入一个String[]

    还有一个需要注意的问题,在使用可变参数的时候可以保证无法传入null,
    因为传入0个参数时,接受到的实际值是一个空数组而不是null。

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

    参数绑定

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

    package com.imooc.objectoriented;
    
    class PersonWoman {
        private int age;
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    public class ArgsBind {
        public static void main(String[] args) {
            int n = 18;
            PersonWoman fang = new PersonWoman();
            fang.setAge(n);
            System.out.println(fang.getAge());  //18
            n = 27;
            System.out.println(fang.getAge());  //18
        }
    }

    当我们改变n的值的时候,并不会影响对象的age属性。
    原因是setAge方法获取的参数,复制了n的值,因此age和n的值互不影响。

    因此基本类型参数的传递,是调用时传值的复制,双方各自的后续修改,互不影响。
    但是上面的结论并不绝对。

    package com.imooc.objectoriented;
    
    class ArgsPerson {
        private String[] names;
    
        public void setNames(String[] names) {
            this.names = names;
        }
    
        public String getNames() {
            return this.names[0] + " " + this.names[1] + " " + this.names[2];
        }
    }
    
    public class ArgsBind2 {
        public static void main(String[] args){
            ArgsPerson seven = new ArgsPerson();
            String[] fullName = new String[] {"ming", "kai", "mao"};
            seven.setNames(fullName);
            System.out.println(seven.getNames());  //ming kai mao
            fullName[0] = "xin";
            System.out.println(seven.getNames());  //xin kai mao
    
        }
    }

    当我们修改了fullname的值时,names的值也随之被改变了。
    因此,引用类型参数的传递,调用方的变量和接收方的参数变量,指向的是同一个对象,
    任意一方发生变化,都会影响对方。

  • 相关阅读:
    [python]百度语音rest api
    [vim]插件ctrlp
    [vim]插件NerdTree
    [Flask Security]当不能通过认证的时候制定跳转
    MongoDB 安装
    c/c++封装成python包
    mysql的常用操作
    python基础知识的学习和理解
    docker系列之三:docker实际应用
    docker系列之二:构建docker容器
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/12499829.html
Copyright © 2020-2023  润新知