多态的概念
- 多态主要指同一种事物表现出来的多种形态
多态的语法格式
- 父类类型 引用变量名 = new 子类类型();
如Shape sr = new Rect()
多态的特点
- 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法
- 当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法
- 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类版本(动态绑定)
- 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。
用引用变量调用静态方法时,只取决于引用变量的类型,因为静态方法属于类层级,被所有对象共享,与对象无关
引用数据类型之间的转换
- 引用数据类型之间的转换方式有两种:自动类型转换和强制类型转换
- 自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型
- 强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也叫做向下转型或者显式类型转换
- 引用数据类型的转换必须发生在父子类之间,否则无法通过编译
- 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常
- 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型
多态的实际意义
- 多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的效果
抽象方法
- 抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体
- 具体格式如下:
访问权限 abstract 返回值类型 方法名(形参列表)
public abstract void cry();
抽象类
-抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象
抽象类和抽象方法的关系
- 抽象类中可以有成员变量,构造方法,成员方法和静态方法
- 抽象类中可以没有抽象方法,也可以有抽象方法
- 拥有抽象方法的类必修是抽象类,因此真正意义商的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类
抽象类的实际意义
- 抽象类的实际意义不在于创建对象而在于被继承
- 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。
- 在以后的开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法,若以后更换子类时,只需要将new关键字后面的子类类型修改而其他地方无需改变就可以立即生效,从而提高了代码的可维护性和可扩展性。
- 该方式的缺点就是:父类引用不能直接调用子类独有的方法,若调用则需要强制类型转换。
注意:
- private和abstract关键字不能共同修饰一个方法,因为私有方法不能被继承
- final 和abstract关键字不能共同修饰一个方法,因为final修饰的方法不能被重写
- static和abstract关键字不能共同修饰一个方法,static关键字修饰将方法提升为类层级,这将使得通过类可以直接调用抽象方法,而调用抽象方法是没有意义的
接口的基本概念
- 接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法
- 定义类的关键字是class,定义接口的关键字是interface
- 接口中不允许使用protected关键字修饰抽象方法,public关键字可以省略
- 直接用返回值 方法名() 声明方法时,系统默认为抽象方法,缺省方法体。
类与接口之间的关系
名称 | 关键字 | 关系 |
---|---|---|
类和类之间的关系 | 使用extends关键字表达继承关系 | 支持单继承 |
类和接口之间的关系 | 使用implements关键字表达实现关系 | 支持多实现 |
接口与接口之间的关系 | 使用extends 关键字表达继承关系 | 支持多继承 |
接口与抽象类的区别
- 定义抽象类的关键字是abstract class,定义接口是interface
- 继承抽象类的关键字是extends,而实现接口的关键字是implements
- 继承抽象类支持单继承,而实现接口支持多实现
- 抽象类中可以有构造方法,而接口中不可以有构造方法
- 抽象类中可以有成员变量,而接口中只可以有常量
- 抽象类中可以有成员方法,而接口中只可以有抽象方法(新特性之前)
- 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8以前的版本)
- 从Java8开始增加了新特性接口中允许出现非抽象方法(default) 和 静态方法(static),但非抽象方法需要使用default关键字修饰
- 从Java9开始增加了新特性,接口允许出现私有方法
内部类
- 当一个类的定义出现在另外一个类的类体中时,那么这个类叫做内部类(inner),而这个内部类所在类叫做外部类(outer)。
- 类中的内容:成员变量,成员方法,构造方法,静态成员,构造块和静态代码块,内部类
内部类的实际作用
- 当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
内部类的分类
- 普通内部类:直接将一个类的定义放在另一个类的类体中
- 静态内部类:使用static关键字修饰的内部类,隶属于类层级
- 局部内部类:直接将一个类的定义放在方法体的内部时
- 匿名内部类:就是指没有名字的内部类
普通(成员)内部类
- 访问修饰符 class 外部类的类名{
…访问修饰符 class 内部类的类名{
… … … 内部类类体;
… …}
…}
普通内部类的使用方式
- 普通内部类和普通类一样可以定义成员变量,成员方法以及构造方法
- 普通内部类和普通类引用可以使用final或者abstract关键字修饰
- 普通内部类还可以使用private或者protected关键字进行修饰
- 普通内部类需要使用外部类对象来创建对象
- 如果内部类访问外部类中与本类内部同名的成员变量或者方法时,需要使用this关键字。
静态内部类
- 访问修饰符 class 外部类类名{
… 访问修饰符 static class 内部类的类名{
… … 内部类的类体;
… }
}
静态内部类的使用方式
- 静态内部类不能直接访问外部类的非静态成员(静态内部类隶属于类层级)
- 静态内部类可以直接创建对象(不需要先创建外部类对象)
- 如果静态内部类访问外部类中与本类同名的成员变量或者方法时,需要使用类名.的方式访问。
局部(方法)内部类
- 访问修饰符 class 外部类的类名 {
… 访问修饰符 返回值类型 成员方法名 (形参列表){
… … class 内部类类名 { //不写访问修饰符
… … … 内部类类体;
… … }
… }
}
局部内部类的使用方式
- 局部内部类只能在该方法的内部可以使用
- 局部内部类可以在方法体内部直接创建对象
- 局部内部类不能使用访问控制符和static关键字修饰
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
参考 JDK8之前,匿名内部类访问的局部变量为什么必须要用final修饰.
回调模式
- 回调模式是指-- 如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。
开发经验
- 当接口/类类型的引用作为方法的形参时,实参的传递方法由两种
- 自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递
- 使用上述匿名内部类的语法格式得到接口/类类型的引用即可
匿名内部类的语法格式
- 接口/父类类型 引用变量名 = new 接口/父类类型(){ 方法的重写 };
匿名内部类的使用
枚举类
- 一年中所有的季节:春季,夏季,秋季,冬季
- 所有的性别:男,女
- 在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型。
枚举的定义
- 使用public static final表示的常量描述较为繁琐,使用enum关键字来定义枚举类取代常量,枚举类型是从Java5开始增加的 一种引用数据类型。
- 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final关键字共同修饰,因此采用枚举类型的方式调用。
- 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的
Enum类的概念与方法
- 所有的枚举类都继承自java.lang.Enum类,常用方法如下:
方法 | 作用 |
---|---|
static T[] values() | 返回当前枚举类中的所有对象 |
String toString() | 返回当前枚举类对象的名称 |
int ordinal() | 获取当前对象在枚举类中的索引位置 |
static T valueOf(String str) | 将参数指定的字符串名转为当前枚举类的对象 |
int compare To(E o) | 比较两个枚举对象在定义时的顺序 |
枚举类实现接口的方式
- 枚举类实现接口后需要重写抽象方法,而重写抽象方法的方式有两种:重写一个,或者每个对象都重写。
注解的基本概念
- 注解(Annotation) 又叫标注,是从Java5开始增加的一种引用数据类型。
- 注解本质上就是代码中的特殊标记,通过这些标记可以在编译,类加载,以及运行时执行指定的处理。
注解的语法格式
- 访问修饰符 @interface 注解名称 {
注解成员;
} - 自定义注解自动继承java.lang.annotation.Annotation接口
- 通过@注解名称的方式可以修饰包,类,成员方法,成员变量,构造方法,参数,局部变量的声明等。
注解的使用方式
- 注解体只有成员变量没有成员方法,而注解的成员变量以"无形参的方法"形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
- 如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八种基本数据类型,String类型,Class类型,enum类型及Annotation类型
元注解
- 元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其他的注解上面
- 元注解主要有@Retention,@Document, @Target, @Inherited, @Repeatable
元注解@Retention
- Retention 应用到一个注解上用于说明该注解的生命周期,取值如下:
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视
- Retention.CLASS注解只被保留到编译进行的时候,它并不会被加载到JVM中,默认方式
- Retention.RUNTIME注解可以保留到程序运行的时候,它会被加载进入JVM中,所以在程序运行时可以获取到它们
元注解@Documented
- 使用javadoc工具可以从程序源代码中抽取类,方法,成员等注释形成一个和源代码配套的API帮助文档,而该工具抽取时默认不包括注解内容
- @Documeted用于指定被该注解将被javadoc工具提取成文档
- 定义为@Documented的注解必须设置Retention值为RUNTIME
元注解@Target
- @Target用于指定被修饰的注解能用于哪些元素的修饰,取值如下:
元注解@Inherited
- @Inherited 并不是说注解本身可以继承,而是说如果一个超类被该注解标记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继承超类的注解。
元注解@Repeatable
- @Repeatable 表示自然可重复的含义,从Java8开始增加的新特性
- 从Java8开始对元注解@Target的参数类型ElementType枚举值增加了两个:
- 其中ElementType.TYPE_PARAMETER表示该注解能写在类型变量的声明语句中,如:泛型
- 其中ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中
常见的预制注解
- 预制注解就是Java语言自身提供的注解,具体如下