面向对象
面向过程和面向对象的区别
- 面向过程思想(线性思维)
- 步骤清晰简单,第一步做什么,第二步做什么
- 面向过程适合处理一些较为简单的问题
- 面向对象思想(分类思维)
- 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考,最后,才对分类下的细节进行面向过程的思索
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题
- 对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理
什么是面向对象
- 面向对象编程(Object-Oriented Programming,OOP)
- 面向对象编程的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据
- 抽象
- 三大特性
- 封装
- 继承
- 多态
- 从认识论角度考虑,是先有对象后有类(对象:具体的事物。类:是抽象的,是对对象的抽象)
- 从代码运行角度考虑,是先有类后有对象。类是对象的模板
类与对象的关系
- 类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物
- 对象是抽象概念的具体实例
创建与初始化对象
- 使用new关键字创建对象
- 使用new创建时,除了分配内存空间外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
- 类中的构造器也称为构造方法,是在进行创建对象时必须要调用的。并且构造器有以下两个特点:
- 必须和类的名字相同
- 必须没有返回类型,也不能写void
- 构造器必须要掌握
类与对象的创建
-
类的创建:
-
对象的创建:
构造器详解
特征:
- 和类名相同
- 没有返回值
说明:
- 一个类一经创建就会存在一个方法,这个方法就是构造器(默认初始化的构造器为无参构造器)
如Person类的无参构造器为:
public Person{
}
- 使用new关键字,本质是在调用构造器
- 构造器也有初始化对象的值的作用
- 一旦定义了有参构造器,无参构造器必须显示定义
- Alt + Insert可以快速创建构造器
创建对象内存分析
图示如下:
封装
封装说明:
- 该露的露,该藏的藏:我们程序设计追求**“高内聚,低耦合”**。高内聚就是类的内部数据操作自己完成,不允许外部干涉;低耦合:仅暴露少量方法给外部使用
- 封装(数据的隐藏):通常,应禁止直接访问一个对象中数据的实际表现,而应通过操作接口来访问,这称为信息隐藏
- 封装特点:属性私有( get / set:Alt + Insert可以快速建立set和get )
- 封装的作用:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护性增加
继承
继承说明
- 继承的本质是对某一批类的抽象,从而对现实世界更好的建模
- 继承是类与类之间的一种关系。除此之外,类与类之间的关系还有依赖,组合,聚合等
- 有继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示
- 子类和父类之间,从意义上讲,应该具有"is a"的关系(如:学生 is a 人)
- 子类会继承父类的所有方法(private的无法继承)
- Ctrl + H打开继承关系
- extends的意思是“扩展”。子类是父类的扩展
继承的语句:publlic class Student extends Person{ } 此语句表达Student类继承Person类
- Java中的类只有单继承,没有多继承(一个子类只能有一个父类)
- 在Java中,所有的类都默认直接或间接继承Object类
super
- super说明:
- 用super可调用父类的属性及方法
在子类中调用父类发print方法:super.print()
- 子类的构造方法(构造器)默认调用父类的构造方法(构造器)
在Student子类中的构造方法默认调用Person父类中的构造方法:
public Student(){
super();
}
- super注意点:
- super调用父类的构造方法(构造器),必须在构造方法的第一个
- super必须只能出现在子类的方法或构造方法中(构造器)
- super和this不能同时调用构造方法(这两个都必须在构造器的第一个)
- super和this
- 代表的对象不同
this:调用本身这个对象
super:代表父类对象的应用 - 前提
this:没有继承也可以使用
super只能在继承的条件下才能使用 - 构造方法
this();是本类的构造方法
super();是父类的构造方法
- 代表的对象不同
方法重写
- 重写的前提:
需要有继承关系,且是子类重写父类的方法 - 重写都是方法的重写,和属性无关
- 重写只与非静态方法有关,与静态方法无关
- 重写的特点:
- 方法名必须相同
- 参数列表必须相同
- 子类方法与父类一致,但方法体不同
- 修饰符:范围可以扩大但不能缩小(public > protected > default > private,即子类的修饰符可以比父类大)
- 抛出的异常:范围可以缩小,但不能扩大
- 为什么需要重写:
父类的功能,子类不一定需要,或者不能满足子类 - 快速创建重写:Alt + Insert 中的 override
多态
多态的说明:
- 多态即同一方法可以根据发送对象的不同而采取多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用的类型不确定
多态存在的条件:
- 有继承关系
- 子类重写父类方法(static , final , private 都不能重写)
- 父类引用指向子类对象
注:多态是方法的多态,与属性无关
-
多态的实际运用:
-
instanceof
用法:A instanceof B
判断A(对象)是否为B(类)的实例,返回值为Boolean型,是就返回true,否则返回false
注:A指向的类型与B有继承关系,返回true -
类型之间的转换
- 子类转化为父类,向上转型,自动转换(可能会丢失自己本来的一些方法)
- 父类转换为子类,向下转型,需强制转换(可能会丢失被子类重写的方法)
- 目的是为了方便方法的调用,减少重复代码
static关键字
-
static在Java中叫静态。
-
static方法就是没有this的方法。在static方法内部不能调用非静态方法,但是可以调用静态方法。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法(类名.static方法)。这实际上正是static方法的主要用途。
-
static随着对象的产生同时产生,且只执行一次
额外:静态代码块 > 隐藏代码块 > 构造方法
抽象类
- abstract修饰符可以修饰方法,也可以修饰类,被修饰的方法或者类被称为抽象方法或者抽象类
- 抽象类中可以没有抽象方法,但有抽象方法的类一定要声明为抽象类
- 抽象类不能使用new关键字来创建对象,它是用来让子类继承的
- 抽象方法:只有方法的声明,没有方法的实现,它是用来让子类实现的
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
接口
- 接口就是规范,定义的是一组规则
- 接口的本质就是契约,如同现实的法律,制定好之后人们去遵守
- 接口与类的区别:
- 普通类:只有具体实现
- 抽象类:有具体实现和规范(抽象方法)
- 接口:只有规范(不能自己写方法)
- 面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口(设计模式研究的就是如何去合理的抽象)
- 接口中的所有定义都是抽象的:
如在接口中定义一个类:void add (String name)
这个定义相当于:public abstract void add (String name)
public abstract 是默认添加的
- 接口中定义属性都为常量(public static final),通常不会定义属性
- 接口是多继承,一个子类可以继承多个接口,继承时必须重写接口中定义的方法
- 接口不能被实例化,接口中没有构造方法
内部类
- 内部类就是在一个类的内部再定义一个类
- 内部类包括
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
- 内部类需要外部类实例化后才能使用
- 内部类可以获取外部类的属性和方法(包括私有)
异常(Exception)
异常指的是在程序运行过程中发生的异常事件
异常的简单分类
- 检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常(如打开一个不存在的文件夹),这些异常在编译时不能被简单忽略
- 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略
- 错误(ERROR):错误不是异常,而是脱离程序员控制的问题。错误常在代码中被忽略(如,当栈溢出时,一个错误发生了,它们在编译时也检查不到)
异常体系结构
- Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类
- 在Java API中已经定义了许多异常类,这些异常分为两大类,错误(Error)和异常(Exception)
Error
- Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者执行的操作无关
- Java虚拟机(JVM)运行错误,当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError错误。这些异常发生时,JVM一般会选择线程终止
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError),链接错误(LinkageError)。这些错误都是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况
Exception
- 在Exception分支中有一个重要的子类RuntimeException(运行时异常)
- ArrayIndexOutOfBoundsException(数组下标越界异常)
- NullPointerException(空指针异常)
- ArithmeticException(算术异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)
以上等异常是不检查异常,程序中可以选择捕获处理,也可以不处理
- 这些异常一般是由逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常发生
- Error与Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,JVM一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常
异常处理机制:
-
抛出异常
-
捕获异常
-
异常处理的5个关键字
- try , catch , finally , throw , throws
-
捕获异常的语句:
-
捕获多个异常,要按从小到大的顺序捕获
-
选中语句,按快捷键Ctrl + Alt + T:快速创建捕获异常语句
-
抛出异常
主动抛出异常用throw,通常在方法内使用,在方法上抛出异常用throws
自定义异常
- 自定义异常,只需要继承Exception类
如 public class Xc extends Exception { }
异常的实际使用
- 处理运行时异常时,采用逻辑去合理规避,同时辅以try-catch处理
- 在多重catch块后面,可以加一个catch(Exception)来处理可能被遗漏的异常
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常
- 尽量去处理异常,切忌只是简单地调用printStackTrace()去打印输出
- 具体如何处理异常,要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句块去释放占用的资源