从零开始的Java学习生活(14)


面向对象编程(2)

面向对象语言有三大特性:封装、继承和多态。本文我们先来讲一讲封装性。

一、封装

在讲解**封装(encapsulation)**的概念之前,我们先学习一下private关键字。

(1)private

先看下面的代码:

有一个Student类

public class Student {
	//实例变量
	String name;	//姓名
	int age;		//年龄
	
	//实例方法
	public void study() {
		System.out.println(name + "正在努力学习Java面向对象的知识。");
	}
	
	public void doHomework() {
		System.out.println(name + "在努力的写作业。十万行代码成就你十万年薪");
	}
	
	public void showInfo() {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
}

Student类创建了2个对象。

	public static void main(String[] args) {
		
		Student stu1 = new Student();
		stu1.name = "马化腾";
		stu1.age = 22;
		stu1.showInfo();
		
		Student stu2 = new Student();
		stu2.name = "李彦宏";
		stu2.age = -20;
		stu2.showInfo();
	}

输出结果:

姓名:马化腾,年龄:22
姓名:李彦宏,年龄:-20

上述的输出结果是没有错的,程序也正常执行的。但是人的年龄是-20是有点违背逻辑的。

之所以出现这种问题,是因为外界可以直接操作属性。想要避免这种问题,最好的办法是不让外界直接操作属性,把属性隐藏起来,给外界提供访问属性的方法,这时就需要用到我们上文提到的private关键字了。

1. 通过private把属性隐藏起来

private单词的含义是私有的。private可以修饰类中的属性和方法,修饰属性的时候,表示属性私有,外界无法直接访问(所谓的直接访问是通过对象名.属性名访问),但是在本类中可以访问。

public class Student {
	//实例变量
	private String name;	//姓名
	private int age;		//年龄
	
	//实例方法
	public void study() {
		System.out.println(name + "正在努力学习Java面向对象的知识。");
	}
	
	public void doHomework() {
		System.out.println(name + "在努力的写作业。十万行代码成就你十万年薪");
	}
	
	public void showInfo() {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
}

上述代码实现了属性的私有,一旦是有,外界将不能使用对象名.属性名去访问对象的属性。
如果强行使用,就会像下图一样报错:
在这里插入图片描述

2. 通过setter、getter方法访问属性

那么如果我们想要获得private属性进行获取和赋值应该怎么办呢?我们有以下两种方法对private属性进行操作:

setter方法:为属性(实例变量)赋值的方法。

getter方法:获取属性(实例变量)值的方法。

由于getter、setter方法是我们特意为外界定义的方法,方便外界能访问属性,因此要有public修饰。

举个栗子:

public String getName() {
		return name;
	}

	public void setName(String n) {
		name = n;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int a) {
		age = a;
	}

需要注意的是:

setter方法既然是为属性赋值,就必须要有参数,而且参数的类型和属性的类型相同。setter方法的方法名是set+首字母大写的属性名。例如:属性名是name,setter方法的方法名是setName,属性名是age,setter方法的方法名是setAge。

getter方法既然是要获取属性的值,就必须有返回值,而且返回值的类型和属性的类型相同。getter方法的方法名是get+首字母大写的属性名。例如:属性名是name,getter方法的方法名是getName,属性名是age,getter方法的方法名是getAge。

提供了方法以后,外界就可以通过方法去访问属性。

那么,我们上文中关于马某人和李某人的代码就可以变成如下的形式:

public static void main(String[] args) {
		
		Student stu1 = new Student();
		stu1.setName("马化腾");
		stu1.setAge(22);
		stu1.showInfo();
		
		Student stu2 = new Student();
		stu2.setName("李彦宏");
		stu2.setAge(-20);
		stu2.showInfo();
	}

这时候有人会说了,你这输出没有任何的改变啊,我还多写这么多代码,你这不是坑人呢?

那我们来对这个setAge稍微改进,改进代码如下:

public void setAge(int a) {
		if(a < 0) {
			System.out.println("您输入的年龄有误。");
		}else {
			age = a;
		}
	}

聪明的同学应该已经懂了封装性的主要作用了,没懂得也不要着急,我们接着往下看。

3. setter/getter和直接访问的异同

相同点:都是在访问属性,包括赋值和取值。

不同点:1.直接访问属性优势是简单快捷,一步到位;劣势是有可能会出现数据错误。2.通过setter/getter访问属性优势是数据没有直接赋值给属性,在赋值之前可以做一些操作和处理;劣势是代码量略大。

在开发中属性一般情况下都定义private,对外提供pulic的getter和setter方法。

(2)this

讲解this之前,先看一下刚才写的setter、getter方法

	public String getName() {
		return name;
	}

	public void setName(String n) {
		name = n;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int a) {
		if(a < 0) {
			System.out.println("您输入的年龄有误。");
		}else {
			age = a;
		}
	}

上面方法中的参数并没有做到见名知意。如果做到见名知意,应改为:

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		if(age < 0) {
			System.out.println("您输入的年龄有误。");
		}else {
			age = age;
		}
	}

改成这样以后,确实见名知意了,但是程序的结果却不对了。

姓名:null,年龄:0
您输入的年龄有误。
姓名:null,年龄0

这是因为:在一个类中,如果局部变量和实例变量名称相同,在方法中使用变量的时候,使用的是局部变量,而不是实例变量。想要在方法中使用实例变量的话,需要使用this.实例变量名

所以我们将代码改成下面这样:

public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		if(age < 0) {
			System.out.println("您输入的年龄有误。");
		}else {
			this.age = age;
		}
	}

this的英文含义是这个,在代码中this是一个特殊的对象,它始终指的是调用方法的对象,即谁调用方法,this就是谁。看下图:

在这里插入图片描述在这里插入图片描述

可以通过打印内存地址的方式,来检验this究竟是谁。

this关键字

  1. this修饰的变量用于指代实例变量。方法的形参如果与实例变量同名,不带this的变量是形参,而不是实例变量。方法的形参如果和实例变量不同名,不需要用this修饰。
  2. this代表的就是调用方法的那个对象。

3)构造方法

构造方法是一种特殊的方法,它是创建对象时调用的方法,用于在创建对象的时候对属性进行初始化。

Student stu1 = new Student();//Student()就是一个构造方法。
1. 构造方法的特点
  1. 构造方法只能用在对象创建的时候。
  2. 构造方法的作用是对属性进行初始化。
  3. 构造方法的方法名必须和类名相同。
  4. 构造方法没有返回值,连void都不能写。
  5. 如果自己没有提供构造方法,系统会默认生成一个无参数的构造方法。
  6. 如果自己提供了任何一个构造方法,系统将不再生成无参数的构造方法。
  7. 构造方法可以重载。
2. 构造方法的书写格式
public 类名(参数列表){
    
}
3. 构造方法示例
	public Student() {
		
	}

	public Student(String name) {
		this.name = name;
	}
	
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

上面的三个方法都是构造方法。

4. 构造方法的使用
public static void main(String[] args) {
	
	Student stu1 = new Student("马化腾",22);
	stu1.showInfo();
	
	Student stu2 = new Student("李彦宏");
	stu2.setAge(20);
	stu2.showInfo();
	
	Student stu3 = new Student();
	stu3.setName("马云");
	stu3.setAge(25);
	stu3.showInfo();
}

在开发过程中,我们通过会至少给2个构造方法。其中一个是无参构造方法,另外一个是全参的构造方法。除此以外根据需求添加别的构造方法。

(4)标准的Java类

根据上文内容,我们可以得到一个标准的Java类,这种类包括了一个类实现特殊功能的最基本的需求。

1. 标准Java类的定义原则
  1. 属性用private修饰
  2. 提供属性对应的setter、getter方法
  3. 提供1个或多个构造方法
  4. 提供正常的功能性方法
2. 标准Java类示例
public class Circle {
	//属性
	private double r;	//半径
	
	public double getR() {
		return r;
	}

	public void setR(double r) {
		this.r = r;
	}

	public Circle() {
		
	}
	
	public Circle(double r) {
		this.r = r;
	}

	//实例方法
	public double perimeter() {
		return 2 * Math.PI * r;
	}
	
	public double area() {
		return Math.PI * r * r;
	}
}

使用圆的时候:

	public static void main(String[] args) {
		// 使用无参构造创建对象
		Circle c1 = new Circle();
		c1.setR(10);
		c1.perimeter();
		c1.area();
		
		// 使用有参构造创建对象
		Circle c2 = new Circle(4);
		c2.perimeter();
		c2.area();
	}

(6)封装

封装:隐藏对象的内部细节,对外提供接口(访问方式)。

**封装的原则:**将类的某些信息隐藏在类内部,不允许外界直接访问,而是给外界提供接口(方法)。外界通过接口访问内部的数据以及类的功能。

  1. getter、setter封装了实例变量。

  2. 方法封装了功能的实现细节。

  3. 类封装了属性和方法。

封装的好处:

  1. 通过方法来控制实例变量的操作,提高了代码的安全性。

  2. 把代码用方法进行封装,提高了代码的复用性。

总结

本文我们讲解了面向对象三大特性之一的封装性,封装性在我们以后的学习中极大地精简了我们的代码,减少了重复,并且对于学习来说也方便他人阅读代码。并且通过方法控制实例变量的操作,极大地提高了代码的安全性(但肯定不是100%安全)。接下来我们会对继承性进行讲解,感谢观看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值