面向对象——三大特征(封装 继承 多态)Java学习(8)

23 篇文章 0 订阅

封装

什么是封装?

封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。

提起封装,大家并不陌生。将具体功能封装到方法中,学习对象时,也提过将方法封装在类中,其实这些都是封装。
面向对象上说的封装,是一种特指:
将类的属性私有化(不再为外界提供直接访问属性的方式),
提供对应的getter和setter方法来访问和设置属性。

封装表现

  1. 函数就是一个最基本封装体
  2. 类其实也是一个封装体

封装的好处

  1. 提高了代码的复用性。
  2. 隐藏了实现细节,还要对外提供可以访问的方式。便于调用者的使用。这是核心之一,也可以理解为就是封装的概念。
  3. 提高了安全性。

private关键字

public class TestPerson {
	public static void main(String[] args) {
		Person p = new Person();
		p.age = -20;
		p.name = "人妖";
		p.show();
		}
	}
	class Person {
		int age;
		String name;
	public void show() {
		System.out.println("age=" + age + ",name" + name);
	}
}
  • 通过上述代码发现,虽然我们用Java代码把Person描述清楚了,但有个严重的问题,就是Person中的属性的行为可以任意访问和使用。这明显不符合实际需求。

可是怎么才能不让访问呢?需要使用一个Java中的关键字也是一个修饰符 private(私有权限修饰符)。只要将Person的属性和行为私有起来,这样就无法直接访问。

class Person {
	private int age;
	private String name;
	public void show() {
	System.out.println("age=" + age + ",name" + name);
	}
}
  • 年龄已被私有,错误的值无法赋值,可是正确的值也赋值不了,这样还是不行,那肿么办呢?按照之前所学习的封装的原理,隐藏后,还需要提供访问方式。只要对外提供可以访问的方法,让其他程序访问这些方法。同时在方法中可以对数据进行验证。
  • POJO(Plain Ordinary Java Object):经典的java类 一般对成员属性的访问动作:修改器(设置set),访问器(获取 get),因此对私有的变量访问的方式可以提供对应的 setXxx或者getXxx的方法。
class Person {
	private int age;
	private String name;
	public void show() {
		System.out.println("age=" + age + ",name" + name);
	}
	public void setAge(int a) {
		if (a < 0 || a > 130) {
			System.out.println(a + "不符合年龄的数据范围");
			return;
		}
		age = a;
	}
	public int getAge() {
		return age;
	}
}

总结:

  • 类中不需要对外提供的内容都私有化,包括属性和行为。
  • 以后再描述事物,属性都私有化,并提供setXxx getXxx方法对其进行访问

注意:私有仅仅是封装的体现形式而已

继承

继承由来

class Student {
	String name;
	int age;
	void study(){
		System.out.println("study");
		}
	}
class Worker{
	String name;
	int age;
	void work(){
		System.out.println("work");
	}
}

通过代码演示描述多个事物。多个事物之间发现有共同的属性和行为。那么代码的复用性很差,那么怎么办呢?
可以将相同的代码进行抽取,抽取出来后放在单独的类中。

class Student {
	void study(){
		System.out.println("study");
		}
	}
class Worker{
	void work(){
		System.out.println("work");
	}
}
class Person{
	String name;
	int age;
}

代码抽取到了Person类中,但是Student和Worker类与Person类没有任何关系,那么Student和Worker类如何能使用到Person中的name和age属性。
为了让类与类之间能有关系,需要使用Java中提供的继承这种机制。继承需要用到关键字extends。

class Person {
	String name;
	int age;
}
class Student extends Person{
	public void study(){
		System.out.println(name+"同学正在学习。。。。");
	}
}
class Worker extends Person{
	public void work(){
	System.out.println(name+"工人正在工作。。。。");
	}
}
public class TestPerson{
	public static void main(String[] args) {
		Student s = new Student();
		s.name = "小明";
		s.study();
		Worker w = new Worker();
		w.name = "张三";
		w.work();
	}
}

继承的好处

  1. 继承的出现提高了代码的复用性,提高软件开发效率。
  2. 继承的出现让类与类之间产生了关系,提供了多态的前提。

单继承与多继承

继承让类与类之间产生了关系,那到底什么时候使用继承呢?
使用继承,必须保证类与类之间有所属(is a)关系,即xxx是zzz中的一种。例如:苹果是水果中的一种,狗是犬科中的一种
Java只支持单继承,不支持多继承。一个类只能有一个父类,不可以有多个父类。

class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//报错

Java支持多层继承(继承体系)

class A{}
class B extends A{}
class C extends B{}

多态

多态由来

class Dog{
	public void eat(){
		System.out.println("啃骨头");
	}
	public void lookHome(){
		System.out.println("看家");
	}
}
class Cat{
	public void eat(){
		System.out.println("吃鱼");
	}
	public void catchMouse()
		System.out.println("抓老鼠");
	}
}
class DuoTaiDemo{
	public static void main(String[] args) {
/*有多个狗和猫对象都要调用吃饭这个行为
这样会导致d.eat();代码重复性非常严重
Dog d = new Dog();
d.eat();
为了提高代码的复用性,可以将d.eat();代码进行封装
public static void method(Dog d)
{
d.eat();
}
然后创建对象,直接调用method方法即可
method(new Dog());
method(new Dog());
但当创建Cat对象时,同样需要调用eat方法,同样可以将eat方法进行封装
public static void method(Cat c)
{
c.eat();
}
*/
	}
}

后期当有了猪对象时,那么同样要封装eat方法,当每多一个动物,都要单独定义功能,封装方法让动物的对象去做事,会发现代码的扩展性很差。如何提高代码的扩展性呢?发现既然是让动物去eat,无论是dog,还是cat,eat是他们的共性,那么将eat进行抽取,抽取到父类中。

abstract class Animal{
//由于每一个小动物的eat方式都不一样,因此在父类中无法准确描述eat的具体行为
//因此只能使用抽象方法描述,从而导致这个类也为抽象类
	abstract public void eat();
}

当有了Animal抽象类之后,狗和猫只要继承这个类,实现他们特有的eat方法即可。

class Dog extends Animal{
	public void eat(){
		System.out.println("啃骨头");
}
	public void lookHome(){
			System.out.println("看家");
	}
}
//描述猫,猫有吃饭,抓老鼠行为
class Cat extends Animal{
	public void eat(){
		System.out.println("吃鱼");
}
	public void catchMouse(){
		System.out.println("抓老鼠");
	}
}

既然Dog属于Animal中一种,Cat也属于Animal中一种,那么不用具体面对具体的动物,而只要面对Animal即可。

Dog d = new Dog();
Animal a = new Dog();
Cat c = new Cat();
Animal aa = new Cat();

通过上述代码发现,Animal类型既可以接受Dog类型,也可以接受Cat类型,当再让动物去做事时,不用面对具体的动物,而只要面对Animal即可。因此上述method方法可以修改为:

public static void method(Animal a){
	a.eat();
}
  • method(Animala)可以接受Animal的子类型的所有小动物,而method方法不用在关心是具体的哪一个类型。即就是只建立Animal的引用就可以接收所有的Dog和Cat对象进来,让它们去eat。从而提高了程序的扩展性。
  • 其实上述代码就已经形成了多态 父类的引用或者接口的引用指向了自己的子类对象。
Dog d = new Dog();//Dog对象的类型是Dog类型。
Animal a = new Dog();//Dog对象的类型右边是Dog类型,左边Animal类型。

多态的好处

提高了程序的扩展性。

多态的弊端

通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。

多态的前提

  1. 必须有关系:继承,实现。
  2. 通常都有重写操作

当父类的引用指向子类对象时,就发生了向上转型,即把子类类型对象转成了父类类型。向上转型的好处是隐藏了子类类型,提高了代码的扩展性。但向上转型也有弊端,只能使用父类共性的内容,而无法使用子类特有功能,功能有限制

本文都是通过学习和查阅资料所得,如有错误请大佬们批评指正。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值