11初级 - 封装与访问控制

236 阅读5分钟

面向对象的三大特征

  • 封装,继承和多态

封装及其必要性

  • 安利一.灯泡开关
  • home.java
package com.github.hcsp;

public class Home {
    public static void main(String[] args) {
        // 直接调用他的打开方法,这种称为低耦合,只通过少的接口做改变
        Light light = new Light();
        light.turnOn();

        // 调用他的打开细节,这种称为高耦合,高耦合更加难以扩展
        Light light2 = new Light();
        light2.打开电路1();
        light2.打开电路2();
        light2.打开电路3();
    }
}
  • Light.java
package com.github.hcsp;

public class Light {
    public void turnOn() {
        打开电路1();
        打开电路2();
        打开电路3();
    }

    public void 打开电路3() {}
    public void 打开电路2() {}
    public void 打开电路1() {}

}

人的案例

package com.github.hcsp;

public class Person {
    public Integer id;
    public String name;
    // 增加需求:如果年龄小于0,则为0,若年龄大于100,则为100,如果外面有100个地方就要改100次
    public int age;
}
  • 通过接口的方式,其他人就不需要改变
package com.github.hcsp;

public class Person {
    private Integer id;

    private String name;
    // 增加需求:如果年龄小于0,则为0,若年龄大于100,则为100
    private int age;

    public void setId(Integer id) {
        this.id = id;
    }

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

    public void setAge(int age) {
        if (age < 0) {
            this.age = 0;
        } else if (age > 100) {
            this.age = 100;
        } else {
            this.age = age;
        }
    }
}
  • 总结:1.如果不使用封装,所有属性都用public去暴露就很难去改变

访问控制符

  • java有四种访问控制符
    • public,所有的人都能访问
    • protected,只有子类可以访问和同一个包的才能访问,包可提供封装的边界,
      • 包之间没有任何的嵌套关系
      • 通过子类去访问
package com.github.hcsp.controlflow.Sub;

import com.github.hcsp.Person;

public class PersonSubClass extends Person {
    public PersonSubClass() {
        this.id = 1;
    }
}
  • 包级私有,不加任何访问限定符就是包级私有,同一个包可以看到
  • private,只有自己能访问,封装的时候一般都用private

getter、setter方法与JavaBean约定

  • javaBean里面getter就是得到一个方法,setter就是设置一个方法,快捷键preference-keymap-搜索generate,默认快捷键control + n
  • javabean就是一个有getter和setter的对象,如果有getter和setter就认为这个java bean 存在某个属性,字符串和布尔值的设置方法不同
  • 这是最重要的约定
// 非布尔
getter: getX 属性
// boolean
getter: isX 属性
setter: setX 属性
  • 永远可以自动生成

为什么要有javaBean

  • json对象和java对象相互转换
  • 序列化就是把一个内存对象转换成字节流,字符串等人能看的东西,反序列化就是字符串转成内存的对象
  • fastJSON案例
package com.github.hcsp;

import com.alibaba.fastjson.JSON;

public class Cat {
    private String name;
    private boolean cute;

    public String getName() {
        return name;
    }

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

    public boolean isCute() {
        return cute;
    }

    public Cat(String name, boolean cute) {
        this.name = name;
        this.cute = cute;
    }

    public void setCute(boolean cute) {
        this.cute = cute;
    }

    public static void main(String[] args) {
        Cat cat = new Cat("喵",  true);
        System.out.println(JSON.toJSONString(cat));
        String s = "{\"cute\":true,\"name\":\"喵\"}";
        cat = JSON.parseObject(s, Cat.class);
        System.out.println("cat = " + cat);
    }

}
  • 结论:在java中转换json,只看getter和setter方法,不看实际的属性。
  • javaBean的好处提供了封装,为软件的演进提供了很大的保证

设计模式实战:静态工厂方法

  • 推荐书籍effective java,作者 Joshua Bloch,第三版
  • 静态工厂方法,最大的优点有名字,清楚告诉自己在做什么,描述自己做什么
  • 为什么不写注释,注释不会被编译,如果过时了还不如不写,错误注释的情况比没有注释更糟糕
  • 重构的一大原则就是取消注释,写成方法
  • 静态工厂方法的第二个好处是不一定要返回对象
  • 静态工厂方法的第三个方法是可以返回对象的子类,以提高静态方法的灵活性
  • 第四个好处,每次调用返回不同的对象,根据输入的参数去创建不同的对象,不需要创建新的对象,好处是省时间和内存
package com.github.hcsp;

import com.alibaba.fastjson.JSON;
import com.sun.org.apache.xpath.internal.operations.Bool;

public class Cat {
    private static final Cat INVALID_CAT = new Cat("Invalid cate", true)
    private String name;
    private boolean cute;

    public String getName() {
        return name;
    }

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

    public boolean isCute() {
        return cute;
    }

    public static Cat newCuteCat(String name) {
        if (name == null || name.isEmpty()) {
            return INVALID_CAT;
        } else if (name.contains("white")) {
            return new WhiteCat(name, true);
        }
        return new Cat(name, true);
    }

    public static class WhiteCat extends Cat {
        public WhiteCat(String name, boolean cute) {
            super(name, cute);
        }
    }

    public static Cat newUnCuteCat(String name) {
        return new Cat(name, false);
    }

    public Cat(String name, boolean cute) {
        this.name = name;
        this.cute = cute;
    }

    public void setCute(boolean cute) {
        this.cute = cute;
    }

    public static void main(String[] args) {
        Cat cat = new Cat("", true);
        Boolean b = new Boolean(true);
    }

}
  • 第五个好处:加载写这个类时还不存在的猫

设计模式实战:静态工厂方法的缺点

  • 没有办法去子类化,就是一个普通的方法
  • 很难让开发者找到,由于名字重新命名了
  • JDK中的很多静态工厂的例子布尔值的 valueOf
  • Integer类有相应的parseInt

静态工厂方法创建的原则

  • 原先的构造器私有化

类的访问控制符

  • 常见的两个public和什么都不加就是高级私有
  • public 任何类都可以访问
  • final 不是访问限定符

如何强行的去访问一个高级私有的类

  • 创建相同的包路径,即可使用,生产环境中不建议

2.png

  • jvm 的高级限制的突破就是通过同名包实现

1.png

Java模块系统简介

  • jdk8 最大的访问限制就是包,JDK9可以把多个包当成module导出
  • jdk9太新了,2017年出的,
  • jdk8没有办法阻止,只能通过约定,比如internal包下的就是不能让外部访问的

3.png

builder模式

  • 解决属性过多,创建构造器过长的问题
  • 要安装插件builderGenerator
  • 生成builder
  • 使用bulder,builder是非常常用的模式
package com.github.hcsp;

public class Main {

    private static Object Person;

    public static void main(String[] args) {
        Person = PersonBuilder.aPerson()
                .withFirstName("")
                .withLastName("")
                .withAddress("").build();
    }
}