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()方法
        }
    }

     

     

  • 相关阅读:
    Vue路由跳转时修改页面标题
    Vue整合Quill富文本编辑器
    XML中的转义字符
    整合SSM框架环境搭建
    Android搞定权限申请
    Android实现秒开效果
    tail -f 与tail -F的区别
    druid 启动报错
    sqoop flume学习笔记
    20180911
  • 原文地址:https://www.cnblogs.com/SongHai/p/14074357.html
Copyright © 2011-2022 走看看