Java零基础_学Java必备的学习笔记(十二)Java封装

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战java

✔上一篇Java零基础系列文章咱们说到了Java对象的建立及使用,今天来讲说Java封装

封装是面向对象的三大特征之一,什么是封装?封装有什么好处?怎么封装,代码怎么写?这是这篇文章学习的内容。安全

什么是封装?

封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操做封装在一块儿,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽量地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其余对象只能经过包裹在数据外面的已经受权的操做来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节,但能够经过该对象对外提供的接口来访问该对象。markdown

在现实世界当中咱们能够看到不少事物都是封装好的,好比“鼠标”,外部有一个壳,将内部的原件封装起来,至于鼠标内部的细节是什么,咱们不须要关心,只须要知道鼠标对外提供了左键、右键、滚动滑轮这三个简单的操做。对于用户来讲只要知道左键、右键、滚动滑轮都能完成什么功能就好了。为何鼠标内部的原件要在外部包装一个“壳”呢,起码内部的原件是安全的,不是吗。app

再如“数码相机”,外部也有一个壳,将内部复杂的结构包装起来,对外提供简单的按键,这样每一个人均可以很快的学会照相了,由于它的按键很简单,另外照相机内部精密的原件也受到了壳儿的保护,不容易坏掉。ide

根据以上的描述,能够得出封装有什么好处呢?oop

封装以后就造成了独立实体,独立实体能够在不一样的环境中重复使用,显然封装能够下降程序的耦合度,提升程序的扩展性,以及重用性或复用性,例如“鼠标”能够在A电脑上使用,也能够在B电脑上使用。另外封装能够隐藏内部实现细节,站在对象外部是看不到内部复杂结构的,对外只提供了简单的安全的操做入口,因此封装以后,实体更安全了。post

封装的代码实现两步:学习

  • 第一步:属性私有化测试

  • 第二步:1个属性对外提供两个set和get方法。外部程序只能经过set方法修改,只能经过get方法读取,能够在set方法中设立关卡来保证数据的安全性。ui

在强调一下: set和get方法都是实例方法,不能带static。

不带static的方法称为实例方法,实例方法的调用必须先new对象。

set和get方法写的时候有严格的规范要求:(你们要按照规矩来)

set方法长这个样子:

public void set+属性名首字母大写(1个参数){
	xxx = 1个参数;
}
get方法长这个样子:
public 返回值类型 get+属性名首字母大写(无参){
	return xxx;
}

复制代码

咱们来看一段代码,在不进行封装的前提下,存在什么问题:

public class MobilePhone {
	//电压:手机正常电压在3~5V
	double voltage;
}
复制代码
public class MobilePhoneTest {
	public static void main(String[] args) {
		MobilePhone phone = new MobilePhone();
		phone.voltage = 3.7;
		System.out.println("手机电压 = " + phone.voltage);
		phone.voltage = 100;
		System.out.println("手机电压 = " + phone.voltage);
	}
}
复制代码

运行结果以下图所示:

图1:未进行封装的程序测试

以上程序MobilePhone类未进行封装,其中的电压属性voltage对外暴露,在外部程序当中能够对MobilePhone对象的电压voltage属性进行随意访问,致使了它的不安全,例如手机的正常电压是3~5V,可是以上程序已经将手机电压设置为100V,这个时候显然是要出问题的,但这个程序编译以及运行仍然是正常的,没有出现任何问题,这是不对的。

为了保证内部数据的安全,这个时候就须要进行封装了,封装的第一步就是将应该隐藏的数据隐藏起来,起码在外部是没法随意访问这些数据的,怎么隐藏呢?咱们可使用java语言中的private修饰符,private修饰的数据表示私有的,私有的数据只能在本类当中访问。请看程序:

public class MobilePhone {
	//电压:手机正常电压在3~5V
	private double voltage;
}
复制代码
public class MobilePhoneTest {
	public static void main(String[] args) {
		MobilePhone phone = new MobilePhone();
		phone.voltage = 3.7;
		System.out.println("手机电压 = " + phone.voltage);
		phone.voltage = 100;
		System.out.println("手机电压 = " + phone.voltage);
	}
}
复制代码

以上程序编译报错了,请看下图:

图2:private修饰的数据没法在外部程序中直接访问

经过以上的测试,手机对象的电压属性确实受到了保护,在外部程序中没法访问了。但从当前状况来看,voltage属性有点儿太安全了,一个对象的属性没法被外部程序访问,天然这个数据就没有存在的价值了。因此这个时候就须要进入封装的第二步了:对外提供公开的访问入口,让外部程序统一经过这个入口去访问数据,咱们能够在这个入口处设立关卡,进行安全控制,这样对象内部的数据就安全了。

对于“一个”属性来讲,咱们对外应该提供几个访问入口呢?一般状况下咱们访问对象的某个属性,不外乎读取(get)和修改(set),因此对外提供的访问入口应该有两个,这两个方法一般被称为set方法和get方法(请注意:set和get方法访问的都是某个具体对象的属性,不一样的对象调用get方法获取的属性值不一样,因此set和get方法必须有对象的存在才能调用,这样的方法定义的时候不能使用static关键字修饰,被称为实例方法。实例方法必须使用“引用”的方式调用。还记得以前咱们接触的方法都是被static修饰的,这些方法直接采用“类名”的方式调用,而不须要建立对象,在这里显然是不行的)。请看如下代码:

public class MobilePhone {

	//电压:手机正常电压在3~5V
	private double voltage;
	public MobilePhone(){

	}
	public void setVoltage(double _voltage){
		if(_voltage < 3 || _voltage > 5){
			//当电压低于3V或者高于5V时抛出异常,程序则终止
			throw new RuntimeException("电压非法,请爱护手机!");
		}
		//程序若是能执行到此处说明以上并无发生异常,电压值合法
		voltage = _voltage;
	}
	public double getVoltage(){
		return voltage;
	}
}
复制代码
public class MobilePhoneTest {
	public static void main(String[] args) {
		MobilePhone phone = new MobilePhone();
		phone.setVoltage(3.7);
		System.out.println("手机电压 :" + phone.getVoltage());
		phone.setVoltage(100);
		System.out.println("手机电压 :" + phone.getVoltage());
	}
}
复制代码

运行结果以下图所示:

图3:对封装以后的测试

经过以上程序,能够看出MobilePhone的voltage属性不能在外部程序中随意访问了,只能调用MobilePhonesetVoltage()方法来修改电压,调用getVoltage()方法来读取电压,在setVoltage()方法中编写了安全控制代码,当电压低于3V,或者高于5V的时候,程序抛出了异常,不容许修改电压值,程序结束了。只有合法的时候,才容许程序修改电压值。(异常机制在后续的内容中会学到,不要着急。)

总之,在java语言中封装的步骤应该是这样的:

须要被保护的属性使用private进行修饰,给这个私有的属性对外提供公开的set和get方法,其中set方法用来修改属性的值,get方法用来读取属性的值。而且set和get方法在命名上也是有规范的,规范中要求set方法名是set + 属性名(属性名首字母大写),get方法名是get + 属性名(属性名首字母大写)。

其中set方法有一个参数,用来给属性赋值,set方法没有返回值,通常在set方法内部编写安全控制程序,由于毕竟set方法是修改内部数据的,而get方法不须要参数,返回值类型是该属性所属类型(先记住,之后讲:另外set方法和get方法都不带static关键字,不带static关键字的方法称为实例方法,这些方法调用的时候须要先建立对象,而后经过“引用”去调用这些方法,实例方法不能直接采用“类名”的方式调用。)

例如如下代码:

public class Product {
	private int no;
	private String name;
	private double price;
	public Product(){
		
	}
	public Product(int _no , String _name , double _price){
		no = _no;
		name = _name;
		price = _price;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int _no) {
		no = _no;
	}
	public String getName() {
		return name;
	}
	public void setName(String _name) {
		name = _name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double _price) {
		price = _price;
	}
}
复制代码
public class ProductTest {
	public static void main(String[] args) {
		Product p1 = new Product(10000 , "小米5S" , 2000.0);
		System.out.println("商品编号:" + p1.getNo());
		System.out.println("商品名称:" + p1.getName());
		System.out.println("商品单价:" + p1.getPrice());
		p1.setNo(70000);
		p1.setName("小米6");
		p1.setPrice(2100.0);
		System.out.println("商品编号:" + p1.getNo());
		System.out.println("商品名称:" + p1.getName());
		System.out.println("商品单价:" + p1.getPrice());
	}
}
复制代码

运行结果以下图所示:

图4:set和get方法测试

有的小伙伴可能会有这样的疑问:构造方法中已经给属性赋值了,为何还要提供set方法呢?

由于,这是两个彻底不一样的时刻,构造方法中给属性赋值是在建立对象的时候完成的,当对象建立完毕以后,属性可能仍是会被修改的,后期要想修改属性的值,这个时候就必须调用set方法了。

相关文章
相关标签/搜索