Java基础系列——面向对象之封装与构造(14)
封装
概念
在面向对象编程方法中,封装(英语:Encapsulation)是指,一种将抽象性函数接口的实现细节部分包装、隐藏起来的方法。同时,它也是一种防止外界调用端,去访问对象内部实现细节的手段,这个手段是由编程语言本身来提供的。封装被视为是面向对象的四项原则之一。
适当的封装,可以将对象使用接口的程序实现部分隐藏起来,不让用户看到,同时确保用户无法任意更改对象内部的重要数据,若想接触数据只能通过公开接入方法(Publicly accessible methods)的方式( 如:"getters" 和"setters")。它可以让代码更容易理解与维护,也加强了代码的安全性。
解释
在面向对象的语言里,封装往往指以下两个相关联但是独立的概念,有时候这两者是存在因果关系。
- 一种编程语言的机制,限制直接访问某些对象的部件。
- 一种编程语言的结构体,其将数据和操作该数据的方法绑在一起,提供了便利性。
一些编程语言的研究者和学者将定义①或者定义①+②作为辨认一门语言是否为面向对象语言的标准之一。一些编程语言提供了闭包作为封装,但是这种功能不属于面向对象的范畴。
在许多编程语言里,组件并不会自动隐藏并且能够被重写,因此,一些倾向于定义②的人会将信息隐藏(information hiding)作为一个单独的定义列举出来。
在使用类的大多面向对象的编程语言中,虽然封装是被支持的,但是仍有其他替代品可以选择。
信息隐藏
封装可以隐藏成员变量以及成员函数,对象的内部实现通常被隐藏,并用定义代替。举个例子,仅仅对象自身的方法能够直接接触或者操作这些成员变量。隐藏对象内部信息能供保证一致性,当用户擅自修改内部部件的数据,这可能造成内部状态不一致或者不可用。隐藏对象内部信息能阻止这种后果。一个众所周知的好处是,降低系统的复杂度和提高健壮性。
大多数语言(如:C++、C#、 Delphi、Java)通过设定等级去控制内部信息隐藏,经典的是通过保留字public 暴露信息和 private去隐藏信息。一些语言(如: Smalltalk 和 Ruby )只允许对象去访问隐藏信息。
通常,也是存在方法去暴露隐藏信息,如:通过反射(Ruby、Java、C#、etc.),名字修饰(Python)
示例如下:
public class Employee {
private BigDecimal salary = new BigDecimal(50000.00);
public BigDecimal getSalary() {
return salary;
}
public static void main() {
Employee e = new Employee();
BigDecimal sal = e.getSalary();
}
}
封装的实现
根据封装的定义,其实就是将该隐藏的东西(字段或方法)隐藏起来;将该暴露出来的东西(字段或方法)暴露出来。具体的实现是通过使用权限修饰符。
权限修饰父本身有3个,但是具体的访问级别是4个。如下所示:
|修饰符|类内部|同一个包|不同包的子类|同一个工程|
|:————:|:————:|:————:|:————:|:————:|
|private|Yes||||
|(缺省)|Yes|Yes|||
|protected|Yes|Yes|Yes||
|public|Yes|Yes|Yes|Yes|
具体示例:
public class Encapsulation {
// 成员变量在 实例化(创建类的对象)时会赋予默认值private String name;// 私有属性,只能在本类内部使用
private int age;
// 对于私有的属性,我们需要提供访问方法(get) 和 设值方法(set)
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<0){
System.out.println("输入正常的一个数吧");
}else if( age <150){
this.age = age;
}else{
System.out.println("滚蛋");
}
}
/**
* 访问方法:
* 1、 是以get为前缀,以属性名为后缀(属性名的第一个字母要变大写)
* 2、不需要任何参数
* 3、返回类型与属性的类型一致
* 4、内部需要返回对应的属性的值
* 5、按照封装的要求,返回方法被定义成 public*/
public String getName(){
return this.name;// 返回 this 的name
}
/**
* 设值方法:
* 1、 是以set为前缀,以属性名为后缀(属性名的第一个字母要变大写)
* 2、需要接受一个与属性类型相同的参数
* 3、不需要任何返回
* 4、内部将参数传入的值,赋值给对应的属性
* 5、按照封装的要求,返回方法被定义成 public
*/
public void setName(String name){
this.name = name;// 将参数传入的name 的值 设置到 我(this)的name中
}
}
构造
构造器(英语: Constructor,有时简称 ctor),别称:构造方法、构造函数、建构子)是一个类里用于创建对象的特殊子程序。它能初始化一个新建的对象,并时常会接受参数用以设定实例变量。
构造器跟一般的实例方法十分相似;但是与其它方法不同,构造器没有返回类型,不会被继承,且不会有范围修饰符。构造器的函数名称一般与它所属的类的名称相同。 它承担着初始化对象数据成员并创建类不变象的任务;在类不变象无效的时候它会失败。一个正确编写的构造器会使它生成的对象保持在一个有效状态。不可变对象必须在构造器内完成所有初始化。
Java语言允许构造器重载 – 一个类被允许拥有多个接受不同参数种类的构造器同时存在。不接收任何参数的构造器被称作“无参数构造器”。在 Java 语言中, 构造是创建对象的重要途径: 即便是工厂模式、 反射等等, 本质上也是依赖于构造的; 默认构造:当没有显式地书写构造时, 系统会自动为类添加一个无参构造;
在Java里,构造器和其他方法的主要差别在于:
- 构造器不具有任何显性返回类型。
- 构造器无法被直接“new” invokes them).
- 构造器无法被标示为synchronized, final, abstract, native, 或者 static。
Java 里的构造器会按照以下顺序完成下列工作:
- 将类变量初始到缺省值。(byte, short, int, long, float, 和 double 变量会默认设为它们相应的0值,booleans 会被设为 false, chars 会被设为空字符(“u0000”),对象引用会被设为 null)
- 引用父类的构造器,如果没有定义任何构造器。
- 将实例变量初始化到指定值。
- 执行构造器内的代码。
在 Java 中可以通过关键词 super 访问父类的构造器。
public class Example{
// Definition of the constructor.
public Example() {
this(1);
}
// Overloading a constructor
public Example(int input) {
data = input; // This is an assignment
}
// Declaration of instance variable(s).
private int data;
}
注意:构造本身是没有返回值的,但是new + 构造
是有返回值的。
- new 关键字在堆内存中开辟空间
- 为 指定的对象的各个字段赋予默认值。
- 执行 构造方法中的代码
- 将内存中的该对象的首地址返回;通常在前面使用等号进行赋值操作,将首地址赋予某一个具体的变量。