zoukankan      html  css  js  c++  java
  • Java基础之:OOP——封装

    Java基础之:OOP——封装

    面向对象编程OOP(Object Oriented Programming)的三大特征之一:封装

    封装就是把类的一部分属性或方法等"隐藏"起来,若外部想要访问必须要通过封装类提供的方法才能对数据进行操作。通过封装我们可以将一些重要的数据放在内部保护起来。

    封装的优点

    1. 隐藏方法实现的细节。

    2. 对数据进行验证,保证数据的安全合理。(例:Person类的age属性只能在1-120之间)

    封装的实现

    使用private访问修饰符 ,修饰属性或方法。对外界提供public修饰的方法对内部"隐藏"数据进行操作。

    简单案例

    Person类:


    public class Person {
        public String name;
        private int age;
        private double salary;
        private String job;
    ​
        
        //构造器 + Set : 需要满足约束条件
        public Person(String name, int age, double salary, String job) {
            setName(name);
            setAge(age);
            setSalary(salary);
            setJob(job);
        }
        
        //重写toString方法  
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", salary=" + salary + ", job=" + job + "]";
        }
        
        public void setName(String name) {
            if (name.length() >= 2 && name.length() <= 6) {
                this.name = name;
            } else {
                System.out.println("姓名长度2-6,默认值小范");
                this.name = "小范";
            }
        }
    ​
        public void setAge(int age) {
            if (age >= 1 && age <= 120) {
                this.age = age;
            } else {
                System.out.println("年龄范围1-120,默认值18");
                this.age = age;
            }
        }
    ​
        public void setSalary(double salary) {
            if (salary <= 1000000 && salary >= 1) {
                this.salary = salary;
            }else {
                System.out.println("工资范围1-1000000,默认值10000");
                this.salary = 10000;
            }
        }
    ​
        public void setJob(String job) {
            this.job = job;
        }
    ​
        public double getSalary() {
            return salary;
        }
        
        public double getAge() {
            return age;
        }
        
        public String getJob() {
            return job;
        }
    }

    Test类:

     

    public class Test {
    ​
        public static void main(String[] args) {
            //使用set get 方式
            Person person = new Person();
            person.setAge(120);
            person.setJob("teacher");
            person.setName("aaaaaaa");
            person.setSalary(12000);
            System.out.println("name: " + person.name);
            System.out.println("age:" + person.getAge());
            System.out.println("job:" + person.getJob());
            System.out.println("salary:" + person.getSalary());
            
            Person person = new Person("aaaaa", 8888,130000,"teacher");
            //重写了toString方法之后
            System.out.println(person.toString());
            
            //没有重写toString方法 则会返回  全类名 + 十六进制HashCode地址
            A a = new A();
            System.out.println(a);  //如果不写toString方法, 默认也是返回toString
            System.out.println(a.toString());   //返回十六进制
            System.out.println(a.hashCode());   //返回十进制
        }
        
    }
    ​
    class A{
        
    }
    ​

    说明:

    1. Person类:

      1. 使用private修饰符封装了 name,age,salary,job属性。

      2. 通过setXxx() 与 getXxx() 的方法实现给属性赋值以及访问属性值的功能。

      3. 这里注意不一定方法名一定是set和get,但一定都是使用public修饰的。

      4. 可以看到在setAge和setSalary时,都做了if判断。通过这种方面实现了外部输入数据的过滤,对内部的数据进行了保护。避免出现不符合语义的数据进入,例如Age = 2000,salary = -10000。

      5. 在Person类中我们还使用了有参构造器与set方法结合使用。这样既可以便捷的使用构造器给对象赋值,又可以使用set方法的数据保护机制。

      6. 重写了toString方法,"@Override"这个符号现在不用考虑,之后会讲到。具体同String方法说明在Test类中体现。

    2. Test类:

      1. 使用封装类的第一种方式,使用无参构造器,然后通过Person类提供的set方法为对象赋值。

      2. 数据输出时,也通过get方法去访问内部数据。可以看到这种方式实现时,代码量会比较大。

      3. 使用封装类的第二种方式,使用有参构造器,直接给对象赋值。

      4. 再使用toString方法输出对象的各属性信息。关于toString()方法的说明:

        1. 我们使用了一个测试类A来演示,在输出对象信息时会默认的调用toString方法。

        2. 若不对toString方法进行重写,输出的内容为:全类名 + 十六进制HashCode地址

        3. 由于我们在Person类中对toString方法进行了重写,所以会Person类的对象在输出时会按照我们定义的方式输出。

        4. 重写的概念会在之后的博客中给出。

    案例总结

    1. 在对封装起来的属性写保护机制的时候,尽量在输入数据出错时附带一个默认值,这样可以保证整个程序不会出现"0"或"null"等无意义数据存在。

    2. 对象赋值可以灵活的选择set方法和有参构造器两种方式。

    3. 输出对象信息时,尽量使用toString方法,可以使用 "System.out.println(对象名);"的方式,简洁明了。这里实际上是 "System.out.println(对象名.toString());" 只不过toString方法默认隐藏。

     

    接下来我们看两个对于封装类的实际应用,为了代码方便阅读这里将各个类写在了一起,但在实际开发中应该保证一个类一个文件,所有类在同一个包下。

    应用案例1

    定义一个Person类 {name, age, job}, 初始化Person 对象数组,有3个person对象, 并按照 age 从 大到小进行排序,提示,使用冒泡排序.

    public class Test {
        public static void main(String[] args) {
            Person[] person = new Person[3];
            // 初始化对象数组
            person[0] = new Person("小范", 20, "老师");
            person[1] = new Person("小黄", 18, "店长");
            person[2] = new Person("小雨", 19, "舞蹈老师");
    ​
            // 遍历显示Person数组
            for (int i = 0; i < person.length; i++) {
                System.out.println(person[i]); // 默认就带有toString方法
            }
    ​
            sort(person); // 排序
            System.out.println("===========排序后=============");
    ​
            for (int i = 0; i < person.length; i++) {
                System.out.println(person[i].toString());
            }
        }
    ​
        // 冒泡排序
        private static void sort(Person[] person) {
            // 临时对象
            // Person temp = new Person(); 自己的思路
    ​
            // 冒泡排序 自己的思路
    //      for (int i = 0; i < person.length - 1; i++) {
    //          for (int j = 0; j < person.length - 1 - i; j++) {
    //              if (person[j].getAge() > person[j + 1].getAge()) {
    //                  // 使用 temp 对象 ,临时保存 , 将堆中的内容进行改变
    //                  temp.setName(person[j].getName());
    //                  temp.setJob(person[j].getJob());
    //                  temp.setAge(person[j].getAge());
    //                  
    //                  person[j].setName(person[j + 1].getName());
    //                  person[j].setJob(person[j + 1].getJob());
    //                  person[j].setAge(person[j + 1].getAge());
    //
    //                  person[j + 1].setName(temp.getName());
    //                  person[j + 1].setJob(temp.getJob());
    //                  person[j + 1].setAge(temp.getAge());
    //              }
    //          }
    //      }
    ​
            // 冒泡 韩老师的思路
            Person temp = null;
    ​
            // 冒泡排序 韩老师的思路
            for (int i = 0; i < person.length - 1; i++) {
                for (int j = 0; j < person.length - 1 - i; j++) {
                    if (person[j].getAge() > person[j + 1].getAge()) {
                        // 使用 temp 对象 ,临时保存 ,使用引用地址来进行交换
                        temp = person[j];
                        person[j] = person[j + 1];
                        person[j + 1] = temp;
                    }
                }
            }
        }
    ​
    }
    ​
    class Person {
        private String name;
        private int age;
        private String job;
    ​
        public String getName() {
            return name;
        }
    ​
        public void setName(String name) {
            this.name = name;
        }
    ​
        public int getAge() {
            return age;
        }
    ​
        public void setAge(int age) {
            this.age = age;
        }
    ​
        public String getJob() {
            return job;
        }
    ​
        public void setJob(String job) {
        this.job = job;
        }
    ​
    // 有参构造器
       public Person(String name, int age, String job) {
        this.name = name;
        this.age = age;
        this.job = job;
        }
    ​
    // 无参构造器
      public Person() {
        }
    ​
    // 输出打印Person信息
       public String toString() {
        return "Person [name=" + name + ", age=" + age + ", job=" + job + "]";
        }
    ​
    }
    

     

    应用案例2

    计算圆的面积,圆柱的体积。

    public class Test {
        public static void main(String[] args) {
            Circle circle = new Circle();
            Cylinder cylinder = new Cylinder();
            
            circle.setRadius(2.5);
            System.out.printf("圆半径:%.2f  圆面积:%.2f
    ",circle.getRadius(),circle.findArea());
            
            cylinder.setLength(3.1);
            System.out.printf("圆柱高:%.2f  圆柱体积:%.2f
    ",cylinder.getLength(),cylinder.findVolume(circle));
        }
    }
    ​
    /*
     *  class Circle(圆)
     *  -radius :double 
        Circle(): 构造方法,将radius 私有属性初始化为1
        +setRadius(double radius) : void
        +getRadius(): double
        +findArea():double  计算圆的面积
    ​
     */
    class Circle{
        private double radius;
    ​
        public Circle() {       //构造器
            this.radius = 1;
        }
    ​
    ​
        public double getRadius() {
            return radius;
        }
    ​
        public void setRadius(double radius) {
            this.radius = radius;
        }
        
        public double findArea() {
            return radius * radius * Math.PI; //Math.PI 返回 3.14.....
        }
    }
    ​
    /*
     *   class Cylinder(圆柱)
     *   -length:double //高度
     *  Cylinder():  构造方法,将length属性初始化为1
        +setLength(double length):void
        +getLength():double
        +findVolume() :double   计算圆柱体积
     *   
    */
    class Cylinder{
        private double length;
        
        public Cylinder(double length) {
            this.length = length;
        }
    ​
        
        public Cylinder() {
            this(1);    //调用上面的有参构造,将length初始化为1
        }
    ​
    ​
        public double getLength() {
            return length;
        }
    ​
        public void setLength(double length) {
            this.length = length;
        }
        
        public double findVolume(Circle circle) {   //使用Circle对象作为参数传递
            return circle.findArea() * length;  //直接使用findArea()方法
        }
    }

     

     

  • 相关阅读:
    streamsets 集成 cratedb 测试
    streamsets k8s 部署试用
    streamsets rest api 转换 graphql
    StreamSets sdc rpc 测试
    StreamSets 相关文章
    StreamSets 多线程 Pipelines
    StreamSets SDC RPC Pipelines说明
    StreamSets 管理 SDC Edge上的pipeline
    StreamSets 部署 Pipelines 到 SDC Edge
    StreamSets 设计Edge pipeline
  • 原文地址:https://www.cnblogs.com/SongHai/p/14074357.html
Copyright © 2011-2022 走看看