Java基础(三)-Java三大特性

Java三大特性分别是封装、继承和多态


封装

  • 封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。封装是一种信息隐藏技术,在java中通过关键字private,protected和public实现封装。

  • 什么是封装?封装把对象的所有组成部分组合在一起,封装定义程序如何引用对象的数据,封装实际上使用方法将类的数据隐藏起来,控制用户对类的修改和访问数据的程度。 适当的封装可以让程式码更容易理解和维护,也加强了程式码的安全性。

封装的作用

  1. 对象的数据封装特性彻底消除了传统结构方法中数据与操作分离带来的种种问题,提高了程序的可复用性和可维护性,降低了程序员保持数据与操作内容的负担。
  2. 对象的数据封装特性还可以把对象的私有数据和公共数据分离开,保护了私有数据,减少了可能的模块间干扰,达到降低程序复杂性、提高可控性的目的。

封装的好处

  1. 良好的封装能够减少耦合
  2. 类内部的结构可以自由修改
  3. 可以对成员更精准的控制
public class Student {
	
	private String name;
	
	private int id;
	
	private String gender;

	public String getName() {
		return name;
	}

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

	public int getId() {
		return id;
	}

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

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	
}

上述代码就是最简单的对一个学生类属性的封装。当访问修饰符为private时,外部其他类是不能访问到该类的属性的,这时候需要提供"接口",也就是set和get方法,来对封装属性进行操作。

继承

  • Java继承是面向对象的最显著的一个特征。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。

  • Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。

  • 继承所表达的就是一种对象类之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法。若类B继承类A,则属于B的对象便具有类A的全部或部分性质(数据属性)和功能(操作),我们称被继承的类A为基类、父类或超类,而称继承类B为A的派生类或子类。

  • 实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有得特性。例如猫有抓老鼠、爬树等其他动物没有的特性。同时在继承关系中,继承者完全可以替换被继承者,反之则不可以,例如我们可以说猫是动物,但不能说动物是猫就是这个道理,其实对于这个我们将其称之为“向上转型”

  • 关于继承,需要注意下面三句话:

  1. 子类拥有父类非private的属性和方法
  2. 子类可以有自己的属性和方法,即子类可以对父类进行扩展
  3. 子类可以用自己的方式实现父类的方法

继承中的构造器

  • 除了上面提到的private修饰的属性和方法不可被继承外,父类的构造器同样不能被继承。但是能够被调用。
public class Student {
	
	private String name;
	
	private int id;
	
	private String gender;
	
	Student() {
		
		System.out.println("Student Constructor ..." );
	}
}
public class LiHua extends Student{
	
	LiHua() {
		//super("XiaoHong");
		System.out.println("Lihua Constructor...");
	}
	
	public static void main(String[] args) {
		
		LiHua li = new LiHua();
	}
}
  • 通过上面的例子可看出,构建的过程是从父类向外一层一层扩散的。上面的例子中并没有显式的引用父类构造器,Java编译器会默认给子类调用父类的构造器。
  • 默认调用父类构造器也是有条件的,那就是父类必须有默认构造器。如果父类没有默认构造器,我们就必须要使用super()来调用父类构造器,否则编译会出错:无法找到复合父类形式的构造器。
  • 对于继承而已,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要显示的指定父类的构造器,而且必须是在子类构造器中做的第一件事(第一行代码)

继承中的protected关键字

  • private访问修饰符,对于封装而言,是最好的选择,但这个只是基于理想的世界,有时候我们需要这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到protected。

  • 对于protected而言,它指明就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他却是可以访问的。

  • 诚然尽管可以使用protected访问修饰符来限制父类属性和方法的访问权限,但是最好的方式还是将属性保持为private(我们应当一致保留更改底层实现),通过protected方法来控制类的继承者的访问权限。

继承中的向上转型

  • 在上面的继承中我们谈到继承是is-a的相互关系,猫继承与动物,所以我们可以说猫是动物,或者说猫是动物的一种。这样将猫看做动物就是向上转型。
  • 将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。由于向上转型是从一个叫专用类型向较通用类型转换,所以它总是安全的,唯一发生变化的可能就是属性和方法的丢失。这就是为什么编译器在“未曾明确表示转型”活“未曾指定特殊标记”的情况下,仍然允许向上转型的原因。

谨慎继承

  • 上面介绍的一些继承的好处,下来介绍一下继承的缺陷:
  1. 父类变,子类必须变
  2. 继承破坏了封装,对于父类而言,他们的实现细节对于子类来说都是透明的
  3. 继承是一种强耦合关系
  • 所以说当我们使用继承的时候,我们需要确信使用继承确实是有效可行的办法。那么到底要不要使用继承呢?《Think in java》中提供了解决办法:问一问自己是否需要从子类向父类进行向上转型。如果必须向上转型,则继承是必要的,但是如果不需要,则应当好好考虑自己是否需要继承。

多态

  • 多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

  • 完整概念下的多态分为三种:

  1. 特殊多态,此类下包括函数重载以及类型转换多态
  2. 参数化多态,对应到Java里就是泛型
  3. 子类型多态,即通过类型继承关系获得的多态

在这里只介绍第三点

子类型多态

  • Java实现该类型多态有三个必要条件:继承、重写、向上转型。
  1. 继承:在多态中必须存在有继承关系的子类和父类。
  2. 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
  3. 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
  • 对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
  • Java中有两种形式可以实现多态。继承和接口。

基于继承实现的多态

  • 基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
  • 当子类重写父类的方法被调用时,只有对象继承链中的最末端的方法才会被调用。
  • 对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。

基于接口实现的多态

  • 在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
  • 继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。

经典案例

class A{
	
	public String show(D obj) {
		
		return ("A and D");
	}
	
	public String show(A obj) {
		
		return ("A and A");
	}
}

class B extends A{
	
	public String show(B obj) {
		
		return ("B and B");
	}
	
	public String show(A obj) {
		
		return ("B and A");
	}
}

class C extends B{
	
}

class D extends B{
	
}
  • 下面的输出结果是什么?
A a1 = new A();
	     A a2 = new B();
	     B b = new B();
	     C c = new C(); 
	     D d = new D(); 
	     System.out.println(a1.show(b));   1
	     System.out.println(a1.show(c));   2
	     System.out.println(a1.show(d));   3
	     System.out.println(a2.show(b));   4
	     System.out.println(a2.show(c));   5
	     System.out.println(a2.show(d));   6
	     System.out.println(b.show(b));    7
	     System.out.println(b.show(c));    8 
	     System.out.println(b.show(d));    9
  • 答案如下:
  1. A and A
  2. A and A
  3. A and D
  4. B and A
  5. B and A
  6. A and D
  7. B and B
  8. B and B
  9. A and D

分析

  • 运行时多态性是面向对象程序设计代码重用的一个最强大机制,动态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。
  • 方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
  • **当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。 **
  • 回到题目当中,1、2、3应该没问题,从4开始看,首先a2是B向上转型为A对象,此时a2中的shou(A a)被重写,show(D d)不受影响,因为向上转型,B中的show(B b)丢失,再将b、c、d套入其中,是不是迎刃而解呢?后面的题目亦一样。

多态的概括

  • 当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值