java之面向对象三大特征(封装,继承,多态)
一.封装
封装是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类提供的对外方法进行内部信息的操作和访问。
封装可以达到以下目的:
1)隐藏类的实现细节
2)让使用者只能通过事先预定的方法访问数据,从而可以在该方法了加入控制逻辑,限制对成员变量的不合理访问
3)可进行数据检查,从而有利于保证数据信息的完整性
4)便于修改,提高代码的可维护性。
为了实现良好的封装,需要从两方面考虑:
1)把对象的成员变量和实现细节隐藏起来,不允许外部直接访问
2)把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作
使用访问控制符修饰
Java提供了三个访问控制符:private,protected,public,分别代表了三个访问控制级别。还有一个不加任何访问控制符的访问控制级别。
private(当前类访问权限)→ default (包访问权限)→ protected (包内访问,子类访问权限)→ public(公开访问权限)
访问修饰符使用的基本原则:
1)绝大部分成员变量使用private修饰,,只有一些static修饰的,类似全局变量的成员变量才可能考虑public修饰。除此之外,有些方法只用于辅助实现该类的其他方法,这些方法成为工具方法,工具方法也应该使用private修饰。
2)如果某个类主要用作其他类的父亲,该类里绝大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用
protected修饰这些方法。
3)希望暴露出来给其他类使用的方法应该使用public修饰。因此,类的构造器通过使用public修饰,从而允许在其他地方创建该类的实例。因为外部类通常希望被其他类自由调用,所以大部分外部类使用public修饰。
深入构造器
1)当程序员调用构造器时,该系统为该对象分配内存空间,这时对象就已经被创建了,只是这个对象不能被外部程序访问,只能在该构造器中通过this来引用
2)如果构造器B完全包含了构造器A的代码,如果通过new关键字来调用构造器,会导致程序重重新创建一个对象,但可以使用this调用相应的构造器,示例如下:
public class Apple{ public String name;
public String color;
public double weight; public Apple(){} public Apple(String name,String color){
this.name=name;
this.color=color; } public Apple(String name,String color,double weight){
this(name,color); //通过this调用另一个重载构造器的初始化代码
this.weight=weight; } }
二.类的继承
Java通过extends关键字来实现类的继承,实现继承的类称为子类,被继承的类叫父类。有的也称其为超类,基类。父类和子类的关系是一种一般和特殊的关系。
因为子类是一种特殊的父类,所以父类的范围要比子类要大,例如水果类范围要比苹果大,所以可以认为父类是大类,子类是小类。
值得指出的是,Java的子类不能获得父类的构造器。
下面是子类继承父类的示范:
public class Fruit(){ public double weight; public void info(){
System.out.println("我是一个水果,重"+weight+"g");
} }
接下来定义Fruit类的子类,代码如下:
public class Apple extends Fruit(){ public static void main(String[] args){
Apple a=new Apple();
a.weight=56;
a.info();
} }
上面程序,Apple基本是一个空类,只包含了一个main方法,创建了Apple对象之后,可以访问该对象的weight实例变量和info实例方法,这就是继承的作用,可以理解为继承了父类的遗产。
Java类只能有一个直接父类,但可以有多个甚至无限个间接父类,Oblect是所有类的父类,要么间接父类要么直接父类
重写(Override)父类的方法
子类扩展了父类,子类是一个特殊的父类,大部分时候,子类总是以父类为基础,额外增加了成员变量和方法。但有一种情况例外,子类根据自己的需要,重写父类的方法,重写也叫覆盖,两者是同一个概念。
方法的重写遵循“两同两小一大”的原则,两同指方法名相同,形参列表相同;两小指子类方法返回值类型比父类方法返回值类型更小或相等。子类方法声明抛出的异常类应比父类方法声明抛出的异常更小或相等;一大是子类方法比的访问权限应比父类的访问权限更大或相等。
一些注意点:
1)覆盖方法要么都是类方法要么都是实例方法。
2)子类覆盖了父类方法后,子类对象无法访问父类中被覆盖的方法,当可以在子类方法中调用,可以使用super(父类
实例)关键字或者父类类名或对象引用名作为调用者调用被覆盖的方法
3)如果父类方法具有private修饰,则子类无法访问和重写该方法。如果子类也定义了遵循“两同两小一大”规则的方法依旧不是重写,只能说是定义了一个新方法。
super限定
需要在子类中调用父类被覆盖的实例方法,则可以使用super限定调用父类被覆盖的方法。
super是Java提供的一个关键字,用于限定该对象调用它从父类继承的到的实例变量或方法。正如this不能出现在static修饰的方法中一样,super也不能出现在static修饰的方法中。
如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承的到的实例变量,而不是该类自己定义的实例变量。
如果子类定义了和父类同名的实例变量,则会发生子类实例变量隐藏父类实例变量情形,这种情况下,子类直接访问实例变量默认访问到子类实例变量无法访问到父类被隐藏的实例变量。这时候,在子类的实例方法中可以使用super关键字来访问父类被隐藏的实例变量。
super调用父类的构造器
子类不会获得父类的构造器,但子类构造器里可以调用父类构造器的初始化代码,类似于前面讲的一个构造器调用另一个重载的构造器。使用super调用父类构造器必须出现在子类构造器执行体的第一行,所以this调用和super调用不会同时出现。
子类调用父类构造器分以下几种情况:
1)子类构造器执行体在第一行使用super显示调用父类构造器,系统会根据super调用里传入的实参调用父类对应的构造器
2)子类构造器执行体的第一行代码使用this显示调用本类中重载的构造器,系统会根据this调用里传入的实参列表调用本类
对应的另一个构造器,执行本类另一个构造器即会调用父类构造器
3)子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类无参的构造器
三.多态
Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定。运用时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态(Polymorphism)。
先看以下程序:
class BaseClass
{
public int book = 6;
public void base(){
System.out.println("父类的普通方法");
}
public void test(){
System.out.println("父类被覆盖的方法");
} } class SubClass extends BaseClass
{
public String book = "轻量级JavaEE企业应用实战";
public void test(){
System.out.println("子类覆盖父类的方法");
} public void sub(){
System.out.println("子类的普通方法");
} public static void main(String[] args)
{
BaseClass bc = new BaseClass();
System.out.println(bc.book);
bc.base();
bc.test(); System.out.println();
SubClass sc = new SubClass();
System.out.println(sc.book);
sc.sub();
sc.test(); System.out.println();
BaseClass ploymophicBc = new SubClass(); //编译时类型与运行时类型不一致
System.out.println(ploymophicBc.book);
ploymophicBc.base();
ploymophicBc.test();
// ploymophicBc.sub(); 编译会出错,无法调用
} }
输出:
---------- 运行java程序 ----------
6
父类的普通方法
父类被覆盖的方法
轻量级JavaEE企业应用实战
子类的普通方法
子类覆盖父类的方法
6
父类的普通方法
子类覆盖父类的方法
输出完成 (耗时 0 秒) - 正常终止
从上面可以看出,编译时类型与引用类型不一致时,调用的是子类覆盖后的方法。
因为子类其实是一种特殊的父类,因此Java允许把一个子类对象直接付给一个父类引用变量,无需任何类型转换,或者成为向上转型,由系统自动完成。
当把子类对象直接赋给父类引用变量时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这可能出现:相同的变量,调用同一个方法时呈现出不同的行为特征
引用变量的强制类型转换
编写Java程序时,引用变量只能调用编译时类型的方法,而不能调用运行时类型的方法,但它实际所引用的对象确实包含该方法。如果需要让这个引用变量调用它运行时类型的方法,则必须把他强制类型转换成运行时类型,强制类型转换格式是(type)valiable。
强制类型转换不是万能的,需要注意:
1)基本类型之间的转换只能在数值类型之间进行,包括整型,字符型,浮点型。不能与布尔型类型进行转换
2)引用类型之间的转换只能在具有继承关系的两个类型之间进行。如果没有继承关系,强制类型转换会编译出错
在进行强制类型转换之前,先用instanceof运算符判断是否可以成功转换,从而避免ClassCastException异常,这样可以使程序更加健壮。,用法如下:
if(objpri instanceof String){
String str = (String)objPri;
}
四.继承与组合
继承和组合都是实现类复用的重要手段,但继承的一大坏处是破坏程序的封装性,采用组合来实现类复用有更好的封装性能。
为了保证父类有良好的封装性,不会被子类随意改变,设计父类通常遵循以下规则:
1)尽量隐藏父类的内部数据。尽量把父类的所有成员变量都设计成private访问类型,不要让子类直接访问父类的成
员变量。
2)不要让子类可以随意访问,修改父类的方法。父类中那些仅为辅助其他的工具方法,应该使用private访问修饰符
控制修饰,让子类无法访问该方法;如果父类中的方法需要被外部调用,则必须以public修饰,但又不希望被子类
重写该方法,可以使用final修饰符来修饰该方法;如果希望父类的某个方法被子类重写,但不希望被其他类自由
访问,则可以使用protected来修饰该方法。
3)尽量不要在父类构造器中调用要被子类重写的方法。
如下程序:
class Base
{
public Base(){
test();
}
public void test(){
System.out.println("被子类重写的方法");
}
}
class Sub extends Base
{
private String name;
public void test(){
System.out.println("子类重写父类的方法,其name字符串长度"+name.length());
} public static void main(String[] args)
{
//这一行引发空指针异常
Sub s = new Sub();
} }
如果想把某些类设置成最终类,既不能当成父类,则可以使用final修饰这个类。除此之外,使用private修饰这个类的所有构造器,从而保证子类无法调用该类的构造器。也就无法继承该类。对于把所有的构造器都使用private修饰的父类,可另外提供一个静态方法,用于创建该类的实例。
到底何时需要派生新的子类呢?不仅保证子类是一种特殊的父类,而且需要具备以下两个条件之一。
1)子类需要额外增加属性,而不仅仅是属性值的改变
2)子类要增加自己独有的行为方式(包括增加新的方法和重写父类的方法)
到底该用继承还是改用组合呢?继承是对已有的类进行一番改造,以此获得特殊的版本,换而言之,就是将一个较为抽象的类改造成适用于某些特定需求的类。如果两个类是整体、部分的关系,就应该采用组合关系来实现复用,例如人和手臂。总之,继承要表达的是一种“is a”的关系。而组合表达的是(has a)的关系。
java之面向对象三大特征(封装,继承,多态)的更多相关文章
- JAVA的三大特征 封装继承多态- 简单总结
简单总结一下 封装-即从很多类的抽取相同的代码 写在一个类里. 好处是 代码的重用,安全. 继承-减少代码的书写. 其好处也是 代码的重用. 多态- 把不同的子类对象都当作父类来看,可以屏蔽不同子类对 ...
- 深入理解Java面向对象三大特性 封装 继承 多态
1.封装 封装的定义: 首先是抽象,把事物抽象成一个类,其次才是封装,将事物拥有的属性和动作隐藏起来,只保留特定的方法与外界联系 为什么需要封装: 封装符合面向对象设计原则的第一条:单一性原则,一个类 ...
- Java中面向对象三大特征
也就是说在这里"人"是多态的, 在不同的形态时,特征行为是不一样的, 这里的"人", 同时有两种形态,一种是教师形态,一种是学生形态,所对应的特征行为分别是&q ...
- Java的OOP三大特征之一——继承
Java的OOP三大特征之一——继承 子类继承父类的特征和行为(属性和方法),使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 特点:在继承关系中,父类更通用.子类 ...
- Java基础-面向对象第二特征之继承(Inheritance)
Java基础-面向对象第二特征之继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承的概述 在现实生活中,继承一般指的是子女继承父辈的财产.在程序 ...
- Java三大特性(封装,继承,多态)
Java中有三大特性,分别是封装继承多态,其理念十分抽象,并且是层层深入式的. 一.封装 概念:封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据 ...
- OOP三大核心封装继承多态
OOP支柱 3 个核心:封装 继承 多态 封装就是将实现细节隐藏起来,也起到了数据保护的作用. 继承就是基于已有类来创建新类可以继承基类的核心功能. 在继承中 另外一种代码重用是:包含/委托,这种重用 ...
- 【JavaSE】面向对象三大特征——封装、继承、多态
前言:本文主要介绍思想 封装 封装这一概念并不仅存在与面向对象中,甚至说封装这一概念不仅限于编程中,其实生活中的封装无处不在.比如 需求:你到银行取钱 参数:你只需要提供银行卡和密码 返回值:柜员会将 ...
- -1-2 java 面向对象基本概念 封装继承多态 变量 this super static 静态变量 匿名对象 值传递 初始化过程 代码块 final关键字 抽象类 接口 区别 多态 包 访问权限 内部类 匿名内部类 == 与 equal
java是纯粹的面向对象的语言 也就是万事万物皆是对象 程序是对象的集合,他们通过发送消息来相互通信 每个对象都有自己的由其他的对象所构建的存储,也就是对象可以包含对象 每个对象都有它的类型 也就是 ...
- java四大特性理解(封装继承多态抽象)
封装: 封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口.面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治.封装的对象,这些对象通过一个受保护的接口访问其他对象.封装是一 ...
随机推荐
- 利用base64展示图片
其实很简单,格式如下: <img src="data:image/jpg;base64,具体的编码值" /> 支持的类型有: data:,文本数据 data:text/ ...
- 常用命令——sed详解
以下内容参考:http://qifuguang.me/2015/09/21/sed命令详解/ sed是stream editor的简称,也就是流编辑器.它一次处理一行内容,处理时,把当前处理的行存储在 ...
- 直接拿来用!最火的Android开源项目(转)
摘要:对于开发者而言,了解当下比较流行的开源项目很是必要.利用这些项目,有时能够让你达到事半功倍的效果.为此,CSDN特整理了GitHub上最受欢迎的Android及iOS开源项目,本文详细介绍了20 ...
- bedtools 的安装与使用
1) 安装 bedtools 提供了3种安装方式 从google code 下载源代码进行安装 利用系统中的包管理工具进行安装, 比如cnetos 下的yum, ubuntu下的apt-get, ma ...
- CSAPP chapter2 记录(bit_level_coding)
p_154 //5x/8 define MSB_BIT (~(~)) int mul5div8(int val) { int sign = (val & MSB_BIT) == MSB_BIT ...
- js焦点轮播图
汇集网上焦点轮播图的实现方式,自己试了下,不过鼠标悬浮停止动画和鼠标离开动画播放好像没生效,不太明白,最后两行代码中,为什么可以直接写stop和play.不用加括号调用函数么?求懂的大神指点! 所用知 ...
- asp.net mvc forms身份认证
web.config配置 <authentication mode="Forms"> <forms loginUrl="~/Login/Index&qu ...
- fireworks切图
下载安装完成后打开软件 打开一张图片 首选参数的撤销次数改成999 按住空格键 鼠标会变成小手的形状 这时候可以拖拽图像 找到切片工具 记住缩放比例的快捷键 ctrl+空格 放大某个区域 切的时候按住 ...
- [extjs] ExtJS 4.2 开发环境搭建
到官网下载Extjs ,现在最新版的是Ext5.1. 这里用ext4.2演示开发.http://extjs.org.cn/. EXT4.1 在线API 项目结构中ext4.2导入的资源文件: 第一个页 ...
- tiny6410移植opencv
1.错误1, 解决办法:取消一下两个选项: 2.错误2, 解决办法: 原因是找不到pthread链接库,打开文件夹下的CmakeCache.txt进行修改 3.错误3, 解决办法: