面向对象高级特性
面向对象高级特性
1 抽象
1.1 为什么会有抽象类
- 当子类中都有一个共同的方法,每一个子类都有不同的实现,在父类中又要体现所有子类的共同的特点,所以要体现有这个方法,但是在父类中又无法给出具体的实现,那么这个时候就需要把这个方法声明为抽象的,而包含抽象方法的类,必须是抽象类
- 某个父类仅仅是表示一个抽象的概念,不希望它被实例化,这个时候父类中可能没有抽象方法,但是我们也把它声明为抽象类
1.2 如何声明抽象类
-
语法格式
- [public/缺省] abstract class 类名{ }
1.3 如何声明抽象方法
-
语法格式
-
[public/protected/缺省] abstract 返回值类型 方法名([形参列表]);
- 抽象方法是不能private,static,final修饰的
-
1.4 抽象类的特点
- (1)抽象类不能实例化 (2)抽象类可以包含抽象方法,也可以没有抽象方法。 如果一个类有抽象方法,那么这个类必须是抽象类, 如果一个抽象类没有抽象方法,那么它的用意是不想实例化,用它仅仅表示一个抽象的概念。 (3)抽象类生来就是用来被继承的,那么子类在继承它的时候,必须重写(实现)抽象父类的抽象方法, 否则该子类也得是抽象类。 (4)抽象类的变量与子类的对象构成多态引用。 (5)抽象类除了不能实例化,可以包含抽象方法,其他的和非抽象类是一样的, 可以有成员变量(类变量、实例变量)、构造器、代码块(静态代码块和非静态代码块) 方法(静态方法、非静态方法)
1.5 抽象类不能实例化,为什么要有构造器呢?
-
子类在继承该类时,一定要调用它的构造器,为属性初始化。
-
因为构造器的作用有两点
- (1)和new一起创建对象
- (2)为属性初始化
-
2 接口
2.1 接口即代表行为标准,功能标准
2.2 如何声明一个接口?
-
语法结构
- [public/缺省] interface 接口名{ }
2.3 如何实现接口?
-
语法结构
- [public/缺省] class 子类名 [extends 父类名] implements 接口名1,接口名2。。。{ //要实现接口的所有抽象方法 }
2.4 接口的特点
-
JDK1.7
- JDK1.7: (1)接口不能实例化 (2)接口只能有全局静态的常量和公共的抽象方法 (3)接口中不能有构造器,因为它没有属性需要初始化,又不能创建对象 (4)接口生来用来被实现的,那么实现类(像子类)在实现它时,必须实现(和重写要求一样)接口的 所有抽象方法,否则该实现类也得是抽象类 (5)一个类可以同时实现多个接口 (6)一个类还可以继承父类又实现接口,但是必须先继承后实现 (7)接口与接口之间是继承关系,一个接口可以继承多个接口 (8)接口与实现类的对象之间构成多态引用
-
JDK1.8
-
其他的和JDK1.7一样,不一样的是: JDK1.8之后,接口中除了全局静态的常量和公共的抽象方法以外,可以有静态方法和默认方法
-
接口中的静态方法
-
当接口的所有实现类,对这个方法的实现是一样的,这个方法就设计在接口中,设计为静态方法
-
如何调用
- 接口名.方法
-
-
接口中的默认方法
-
当接口的大多数实现类,对这个方法的实现是一样,那么这个方法的实现就可以在接口中提供默认实现,如果某个实现类觉得他不合适,只需要重写它即可
-
如何调用
-
实现类外
- 实现类对象.方法
-
实现类中
- 如果实现类要重写该默认方法,但是又想调用接口中的默认实现
- 接口名.super.方法
-
-
什么情况下需要重写
-
接口中的默认实现不适合该实现类
-
必须重写
- 一个类同时实现了多个接口,而多个接口中都相同的默认方法(方法名和形参列表都相同),这个时候实现类必须做出选择,要重写,如果需要保留其中一个的话,通过接口名.super.方法,保留它的默认实现
-
-
类优先原则
- 当一个类继承了父类,又实现了接口,而且父类中的某个方法与接口中的默认方法一样(方法名和形参列表),默认保留的是父类中的方法实现
-
-
-
3 枚举
3.1 枚举是指某个类型的对象是有限个,在类型中一一创建并列举它的对象
3.2 JDK1.5之前,如何解决
-
(1)构造器私有化
-
(2)通过常量的方式创建好所有对象
-
示例
class Week{
public static final Week MONDAY = new Week();
public static final Week TUESDAY = new Week();
public static final Week WEDNESDAY = new Week();
public static final Week THURSDAY = new Week();
public static final Week FRIDAY = new Week();
public static final Week SATURDAY = new Week();
public static final Week SUNDAY = new Week();
private Week(){
}
}
Week w = Week.MONDAY;
3.3 JDK1.5之后,如何解决
-
如何声明
- [修饰符] enum 枚举类型名{ 常量对象列表 }
- [修饰符] enum 枚举类型名{ 常量对象列表; 其他成员; }
-
特点
-
(1)枚举类型中的构造器都是私有化
-
(2)常量对象列表必须在首行,如果常量对象列表后面还有其他的代码,那么要用;结束
-
(3)枚举类型不能继承别的类型,因为它默认继承java.lang.Enum
-
它有一些方法
-
name()
- 返回常量对象名
-
ordinal()
- 返回常量对象的序号,从0开始
-
实现了java.lang.Comparable接口,重写compareTo(),按照常量对象的顺序排序
- 如果自己的枚举类中不适合,可以重写
-
toString()
-
返回常量对象名
- 可以重写
-
-
-
API中没有的方法
-
枚举类型名.values()
- 返回枚举常量对象组成的数组
-
枚举类型名.valueOf(常量对象的名称)
- 返回某一个指定的对象
-
-
-
(4)switch对枚举加入支持
- switch(枚举类型表达式){ case 常量对象名1: 语句; [break;] case 常量对象名2: 语句; [break;] case 常量对象名3: 语句; [break;] default: 语句; [break;] }
-
4 注解
4.1 概念
-
代码级别的注释
-
给代码读取的注释
-
不同普通的注释(给人看的)
- 单行注释
- 多行注释
-
4.2 四种
-
1、编译器的格式检查
- (1)@Override:告知编译器对该方法按照“重写”的要求进行格式检查
- (2)@SuppressWarnings:告知编译器抑制警告
- (3)@Deprecated:告知编译器某个元素是已过时,有人用了就弹出警告
-
2、文档注释
-
(1)@version
- 指定当前版本
-
(2)@author
- 指定作者
-
(3)@since
- 指定从哪个版本开始
-
(4)@see
- 另请参阅
-
(5)param
-
指定当前方法的形参信息
-
可以多个
-
只有方法有形参才能标记
-
格式:
- @param 形参名 形参类型 形参的描述信息
-
-
(6)@return
-
指定当前方法的返回值信息
-
一个方法只能有一个,如果方法是void,就不能标记@return
-
格式
- @return 返回值的类型 返回值的描述
-
-
(7)@exception
-
指定当前方法抛出异常的信息
-
可以多个
-
只有方法抛出异常才能标记
-
格式
- @exception 异常类型 异常的描述
-
-
结合javadoc.exe
-
-
3、JUnit的单元测试
-
白盒测试,程序员自己的测试,在程序员知道当前的代码的功能的
-
@Test
- 加在方法上
- 这个方法必须是公共的,无参,无返回值,不能是static
-
@Before
- 在@Test标记的方法之前运行
-
@After
- 在@Test标记的方法之后运行
-
-
4、各大框架等替代配置文件
4.3 注解的三个部分
-
1、声明
- 一般都是别人声明好的
-
2、使用
-
3、读取
- 例如:@Override等,由javac.exe
- 例如:@author,@param等,由javadoc.exe
- 例如:@Test等,由JUnit相关的类读取
- 例如:@WebServlet等,由Tomcat读取
- …
- 如果自己要读取,通过反射,而且只能读取@Retention(RetentionPolicy.RUNTIME)
4.4 注解的声明
-
(1)无参
-
声明格式
- @元注解 [修饰符] @interface 注解名{}
-
使用格式
- @注解名
-
-
(2)有参
-
声明格式
-
@元注解 [修饰符] @interface 注解名{ 配置参数 }
-
配置参数
-
格式
- 数据类型 参数名();
-
一个注解可以有多个配置参数
-
配置参数可以有默认值
- 数据类型 参数名() default 默认值;
-
配置参数的类型有要求
- 类型只能是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、以上所有类型的数组
-
-
-
-
使用格式
-
@注解(参数赋值)
-
如果配置参数有默认值,那么可以在使用时不需要赋值
-
如果配置参数只有一个,而且名称是value,那么可以在赋值时省略value=
-
参数赋值的格式
-
参数名 = 参数值
-
如果多个使用,分割
-
如果配置参数的类型是数组类型
- 如果只有一个元素,那么可以省略{}
- 如果是多个元素,那么需要{}
-
-
-
-
4.5 元注解
-
@Target
-
指定某个注解它的使用目标位置
-
如何指定它
-
它配置参数的类型是一个枚举数组
-
ElementType枚举类型
- 常量对象有:TYPE, FIELD,METHOD等
-
-
配置参数的名称是value
-
如果只有一个
- @Target(ElementType.METHOD)
-
如果是多个
- @Target({ElementType.METHOD,ElementType.FIELD,。。。。})
-
-
-
@Retention
-
指定某个注解的生命周期,可以保留到什么阶段
-
如何指定它
-
它的配置参数的类型是一个枚举类型
-
RetentionPolicy类型
-
常量对象有三个
- SOURCE,CLASS,RUNTIME
-
-
-
配置参数的名称是value
-
@Retention(RetentionPolicy.RUNTIME)
-
-
-
@Documented
- 表示是否javadoc读取
-
@Inherited
- 是否被子类继承
-
在java.lang.annotation包