面向对象设计进阶
一、封装
1、封装是指把一个对象的属性隐藏在对象内部,不允许外部对象直接访问内部信息。但是可以提供一些被外界访问的方法来操作属性。如果属性不想被外界访问,可以不提供给外界访问的方法。
2、封装类
对于简单类型数据,Java对它们进行了封装,使它们都有相应的封装类
如 int–Integer ,boolean—Boolean,char—Character
3、封装类的特点:
- 所有的封装类都是final类型
- JDK1.5允许基本类型和封装类型进行混合数学运算
二、类的继承
1、类的继承
-
面向对象最重要的特点之一,就是可以实现对类的复用
-
通过继承一个现有的类,可以使用已经定义的类中的方法和变量。新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性的继承父类。
-
类的方法可以被继承,但是类的构造器和用private修饰的属性及方法不能被继承
-
通过使用继承,可以快速的创建新的类,可以提高代码的重用、程序的可维护性,节省大量创建新类的时间,提高我们的开发效率。
2、继承需要满足的条件
- 只有在同一个包下的父类和子类之间才可以发生默认继承
- 一个类只可以继承一个父类,但一个父类可以被多个子类继承
3、继承的注意点:
- Object类是所有类的父类
- 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和私有方法子类无法访问,只是拥有 但无法访问;
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展;
- 子类可以用自己的方式实现父类的方法(重写)
4、一个子类只能继承一个父类。如果一个类继承了一个父类,但是“所有子类都继承Object类”,那么这是不是多继承呢?
不是的。如果一个类继承另一个类,那么是父类继承Object类,而这个子类直接继承父类 ,只是间接继承Object类。还是单继承。
三、多态
1、在Java中,对象变量是多态的。具体表现为父类的引用会指向子类的实例
-
一个类型为Aclass的变量既可以指向类型为Aclass的对象,又可以指向Aclass的任何子类的对象
-
如果子类重写了父类的方法,真正执行的是子类覆盖的方法
-
以多态的形式来传递参数,增强了参数类型的灵活性;
四、接口
1、接口(interface)是方法和常量值的定义的集合
- 接口和类类似,也可以从一个父接口中派生。extends
- 和类不同的是,一个接口可以继承多个父接口
2、实现接口 (implements)
- 多个无关的类可以实现同一个接口
- 一个类可以实现多个无关的接口
3、接口和抽象类比较
共同点:
- 都不能被实例化
- 都可以包含抽象方法
- 都可以有默认实现的方法
区别:
- 接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。而抽象类主要用于代码复用
- 一个类只能继承一个父类,但是可以实现多个接口;一个接口可以继承多个接口
五、访问控制
1、在Java中,可以在类、类的属性以及类的方法前面加上一些修饰符,来对类进行一些访问上的控制
2、访问控制的限制程度从高到低:
private–>default–>protected–>public
- default不是一个修饰符,只是用来表示一种不加任何修饰符时的状态
六、方法的覆盖
1、覆盖也叫作重写。是指,当从父类继承的方法不能满足子类的需求,子类可以对其进行改写,这个过程叫做方法的覆盖,也称为方法的重写,但父类的私有方法不能被子类覆盖(子类没有访问权限)
2、发生条件:
- 首先是两个类里且这两个类有继承关系
- 同一个方法子类只能重写一次
- 子类重写父类的方法,方法名要相同,参数签名个数、类型、顺序也要相同,返回类型也要相同;
- 子类中的覆盖方法不能使用比父类中被覆盖方法更严格的访问权限(子类中该覆盖方法的访问权限至少要和父类中相同或者更大)
- 子类重写父类的方法中,抛出的异常必须是重写的父类方法抛出的异常或者是子异常 ;子类重写方法中,不允许抛出比父类中更多的异常。子类重写的方法声明的不处理的异常一定要比父类少
3、关于重载
- 同一个类 中的方法名相同时,称为方法的重载
- 重载可以多次
- 方法名相同且参数签名不同(参数个数、类型、顺序任一不同即可)
- 返回值类型和权限没有要求
- 主方法也可以重载(虚拟机是通过方法名和参数类型找主方法,重载后也能找到main)
- 除了方法外,类的构造器也可以实现重载。类的构造器可以相互调用,调用方式是使用this关键字来实现
七、Super关键字
1、在Java类中使用super来引用父类的成分
- super可用于访问父类中定义的属性
- super可用于调用父类中定义的成员方法
- super可用于在子类构造器中调用父类的构造器
- super的追溯不仅于直接父类
2、调用父类构造器
- 在子类的构造器中可使用语句super(argument_list)调用父类的构造器
- 如果子类的构造器没有显式的调用父类构造器,也没有使用this关键字调用重载的其他构造器,则系统默认调用父类的无参构造器
- 如果子类构造器中既未显式的调用父类的构造器,而父类中又没有无参构造器,则编译出错
八、this关键字
1、用this代表其所在方法的当前对象的引用
- 在构造器中指对this所指对象的初始化
- 方法中指调用该方法对象的引用
2、this关键字的引用
- 在类本身的方法或构造器中引用该类的实例变量和方法
- 将当前对象的引用作为参数传递给其他方法或构造器
- 用来调用其他的重载的构造器
九、toString()
1、在Object类中,定义了一个toString()方法,用于返回一个表示这个对象的字符串。
- 通常在输出对象地址时会自动调用该方法
- 覆盖该方法能用来提供某对象的自定义信息
- 简单类型使用它们的封装类,可以转换成String
十、区分==和equals()
- ==和equals()都是用于相等型判断的操作符
- == 操作符用来判断两个引用是否指的同一个对象,或者两个简单类型的值是否相等
- 对于基本数据类型来说,==比较的是值
- 对于引用数据类型来说,==比较的是对象的内存地址(本质还是比较值,只不过引用数据类型中存的值就是对象的内存地址)
- equals()方法用来判断对象的内容是否相等,相等的条件在该类中定义
- Object类的equals()方法直接用==实现,不实用,所以很多类会覆盖Objects类中的equals方法。按照自己的需要,在equals()方法中定义对象相等的含义。
十一、高级类特性
1、static关键字
- static关键字用来修饰变量、方法和内部类,称为静态变量、静态方法、静态内部类
- static关键字声明一个属性或者方法是和类相关的,而不是和类的某个特定的实例相关。
- 如果访问控制权限允许,可以不必创建该类对象而是直接使用类名加“.”调用
- static不可用于修饰构造器
2、static自由块
- static除了用于修饰变量和方法外,还可以用于修饰类中的自由块
- 自由块就是在类中用{}包含起来的不属于任何方法和构造器的代码段
- 使用static来修饰的自由块只在类加载的时候执行一次,通常用于初始化静态变量
3、单例模式(Singleton)
- 单例模式是指在内存中只会创建一次对象的设计模式。
- 在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。
单例模式分为两种:
- 懒汉式:在真正需要使用对象时才去创建该单例类对象
懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化**(判空),**若已实例化直接返回该类对象。,否则则先执行实例化操作。
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
- 饿汉式:在类加载时就已经创建好该对象,在程序调用时直接返回该单例对象。
public class Singleton{
private static final Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return singleton;
}
}
4、final关键字
- final用于类、方法、变量前
- fianl类—不可被继承
- fianl变量–在初始化后不可改变变量值,用于常量定义。
- final方法–不可被覆盖
5、abstract类
-
可以使用abstract;来修饰一个类或者方法
-
用abstract修饰的类表示这个类是一个抽象类,用abstract修饰的方法表示这个方法是抽象方法
-
抽象方法是只有方法声明,而没有方法的实现
抽象类的注意点
- 抽象类里面不一定有抽象方法,但是有抽象方法的类一定是抽象类
- 抽象类不能被实例化
- 一个类实现了某个接口,但没有全部实现接口中的方法,那么这个类必须定义为抽象类
6、instanceof运算符
- 使用运算符instanceof可以得到对象的类型
7、内部类
- 允许一个类的定义出现在另一个类中,将处于另一个类中的寄生类成为内部类
- 内部类和外层封装它的类之间存在逻辑上的从属关系,逻辑上是一个整体
- 内部类对其封装类的内部成员有访问权限
- 类的名字只能在定义的范围内使用,除非使用有效的全名
- Inner类也可以定义在方法的内部
实例化内部类:
- 方法一
Outer.Inner in = new Outer().new Inner();
- 方法二:
Outer o = new Outer();
Outer.Inner I = o.new Inner();