面向对象-2
11.权限修饰符
权限修饰符是用来控制一个成员能够被访问的范围的
可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制
四种权限修饰符作用范围从小到大(private > 缺省 > protected > public)
| 修饰符 | 同一个类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
|---|---|---|---|---|
| private | ✔ | |||
| 缺省 | ✔ | ✔ | ||
| protected | ✔ | ✔ | ✔ | |
| public | ✔ | ✔ | ✔ | ✔ |
12.final关键字
final的作用
- final关键字是最终的意思可修饰(方法,变量,类)
- 修饰方法:表明该方法是最终方法,不能被重写。
- 修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)
- 修饰类:表明该类是最终类,不能被继承
final修饰变量的注意点
- final修饰的变量是基本类型,那么变量存储的数据值不能发生改变
- final修饰的变量是引用类型,那么变量存储的地址值不能发生改变,但是地址指向的对象的内容是可以发生变化的
13.枚举
枚举的概述
- 枚举是java中的一种特殊类型
- 枚举的作用:是为了做信息的标志和信息的分类
定义枚举的格式
修饰符 enum 枚举名称{
第一行都是罗列枚举类实例的名称,建议全部大写
}
枚举的特征
- 枚举类都是继承了枚举类型:java.lang.Enum
- 枚举都是最终类,不可以被继承
- 枚举类的构造器都是私有的,枚举类对外不能创建对象
选择常量做信息标志和分类虽然可以实现可读性,但是入参值不受约束,代码相对不够严谨;枚举做信息标志和分类,代码可读性好,入参约束严谨,代码优雅,是最好的信息分类技术,建议使用
public enum Season {
SPRING,SUMMER,AUTUMN,WINTER;
}
14.抽象类
抽象类概述
- 某个父类知道其所有子类要完成某功能,但是每个子类完成的情况都不一样,父类就只定义该功能的基本要求,具体实现由子类完成,这个类就可以是一个抽象类,抽象类其实就是一种不完全的设计图
抽象类必须使用abstract修饰
- 格式:修饰符 abstract class 类名{}
抽象方法
- 抽象类中定义的子类必须完成的功能的基本要求
- 没有方法体,只有方法签名,必须abstract修饰
- 格式:修饰符 abstract 返回值类型 方法名称(形参列表);
抽象类的使用总结与注意事项
- 抽象类是用来被继承的,抽象方法是交给子类重写实现的
- 一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类
抽象类特征
- 有得有失:得到了抽象方法,失去了创建对象的能力
- 类有的成员(成员变量、方法、构造器)抽象类都具备
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类
- 不能用abstract修饰变量、代码块、构造器
- final和abstract是互斥关系
14.1模板方法模式
使用场景:当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候
模板方法模式实现步骤
- 把功能定义成一个所谓的模板方法,放在抽象类中,模板方法中只定义通用且能确定的代码
- 模板方法中不能决定的功能定义成抽象方法让具体子类去实现
- 模板方法建议使用final关键字修饰,因为模板方法是让子类直接使用,不是让子类重写的,一旦重写,模板方法就无效了
模板方法的好处
- 模板方法极大提高了代码的复用性
- 模板方法已经定义了通用结构,模板不能确定的定义成抽象方法
- 使用者只需关心自己需要实现的功能
15.接口
接口概述
- 接口就是体现规范的,其中用抽象方法定义的一组行为规范,接口时更加彻底的抽象
- 体现了现实世界中"如果你是这类事物…则必须完成某些行为…"的思想
格式
接口用关键字interface来定义
public interface 接口名{
//常量
//抽象方法
}
jdk8之前接口中只能是抽象方法和常量,没有其他成分,jdk8之后接口中可以定义方法,可以定义默认方法和静态方法,默认方法必须要用default关键字修饰,且只有在接口被实现之后才能调用,静态方法要用static关键字修饰,只能用接口名.方法名的形式来调用。
接口不能实例化(创建对象)
接口中的成员变量都是public修饰的,写不写都是,因为规范的目的是为了公开化
/**
* 定义了默认方法和静态方法的接口
*/
public interface InterNew {
default void defaultMethod(){
System.out.println("接口默认方法被执行~~");
}
static void staticMethod(){
System.out.println("接口静态方法被执行~~");
}
}
/**
* 接口的实现类
*/
public class InterNewImpl implements InterNew {
}
public class Demo {
public static void main(String[] args) {
InterNewImpl interNew = new InterNewImpl();
//调用接口的默认方法
interNew.defaultMethod();
//调用接口的静态方法
InterNew.staticMethod();
}
}
运行结果

接口的用法
- 接口是用来被类实现(implements)的,实现接口的类被称为实现类,实现类可以理解成所谓的子类
格式
修饰符 class 实现类 implements 接口1,接口2,接口3……{
}
接口可以被类单实现,也可以被类多实现
一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类。
接口和接口之间的关系
- 类和类之间的关系是单继承(一个类只能继承一个父类),类和接口之间的关系是多实现(一个类可以实现多个接口)。
- 接口和接口之间的关系是多继承(一个接口可以同时继承多个接口)。
接口多继承的作用:整合多个接口为同一个接口,便于子类实现。
接口的注意事项
- 接口不能创建对象
- 一个类实现多个接口,多个接口中有同样的静态方法不冲突
- 一个类继承了父类,同时又实现了接口,父类和接口中有同名方法,默认调用父类的
- 一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可
16.多态
同类型的对象,执行同一个行为,会表现出不同的行为特征
多态的常见形式
- 父类类型 对象名称 = new 子类构造器;
- 接口 对象名称 = new 实现类构造器;
多态成员访问特点
- 方法调用:编译看左边,运行看右边
- 变量调用:编译看左边,运行也看左边(多态侧重行为多态)
多态的实现前提
- 有继承/实现关系;有父类引用指向子类对象;有方法重写
优势
- 在多态形式下,右边对象可以实现解耦合,便于扩展和维护
- 定义方法的时候,使用父类作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利
public abstract class Shape {
public String name = "形状";
public abstract void area();
}
public class Circle extends Shape{
public String name = "圆形";
@Override
public void area() {
System.out.println("面积为Πr^2");
}
}
public class Rectangle extends Shape{
public String name = "矩形";
@Override
public void area() {
System.out.println("面积为长乘宽");
}
}
public class Test {
public static void main(String[] args) {
//多态的形式 父类类型 对象名称 = new 子类构造器
Shape s1 = new Circle();
System.out.println(s1);//变量:编译看左边,运行看右边
s1.area();//方法:编译看左边,运行也看左边
Shape s2 = new Rectangle();
System.out.println(s2);
s2.area();
}
}
运行结果

public class Test2 {
public static void main(String[] args) {
Circle c = new Circle();
calc(c);
Rectangle r = new Rectangle();
calc(r);
}
public static void calc(Shape s){
s.area();
}
}
运行结果

弊端
-
但是多态情况下不能使用子类的独有功能(可以使用类型转换)
自动类型转换(从子到父):子类对象赋值给父类类型的变量指向
强制类型转换(从父到子): -
子类 对象变量 = (子类)父类类型的变量
-
作用:可以解决多态下的劣势,可以实现调用子类独有的功能
-
如果转型后的类型和对象真实类型不是同一种类型,那么运行的时候会报异常
-
转换前使用instanceof判断当前对象的真实类型,再进行强制转换
-
变量名 instanceof 类名;
-
判断关键字左边的变量指向的对象的真实类型,是否为右边的类型或其子类型,是则返回true
17.内部类
内部类就是定义在一个类里面的类,里面的类可以理解成寄生,外部类可以理解成宿主
public class People {
//内部类
public class heart {}
}
内部类的使用场景、作用
- 当一个事物的内部,还有一个部分需要完整的结构进行描述,而这个内部的完整结构又只为外部事物提供服务,那么整个内部的完整结构可以选择内部类来设计
- 内部类通常可以方便访问外部成员,包括私有的成员
- 内部类提供了更好的封装性,内部类本身就可以用private protected等修饰,封装性可以做到更多控制
内部类分类
- 静态内部类
- 成员内部类
- 局部内部类
- 匿名内部类
17.1静态内部类
有static修饰,属于外部类本身
它的特点和使用与普通类是完全一样的,类有的成分都有,只是在别的类里面
public class Outer {
//静态成员内部类
public static class inner{
}
}
静态内部类创建对象的格式
public class Test {
public static void main(String[] args) {
Outer.Inner in = new Outer.Inner();
}
}
静态内部类可以直接访问外部类的静态成员,不能直接访问外部类的实例成员,必须用外部类的对象访问
17.2成员内部类
无static修饰,属于外部类的对象
public class Outer{
//成员内部类
public class Inner{
}
}
成员内部类创建对象格式
格式:外部类名.内部类名 = new 外部类构造器.() new 内部类构造器();
范例:Outer.Inner in = new Outer().new Inner();
成员内部类中可以直接访问外部类的静态成员,实例方法中可以直接访问外部类的实例成员
在成员内部类中访问所在外部类对象 外部类名.this
17.3局部内部类
局部内部类放在方法、代码块、构造器等执行体中
17.4匿名内部类
本质上是一个没有名字的局部内部类,定义在方法中、代码块中
方便创建子类对象,最终目的是为了简化代码编写
new 类|抽象类名|接口名(){
重写方法
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal() {
@Override
public void run() {
System.out.println("动物在跑");
}
};
a. run();
}
}
abstract class Animal{
public abstract void run();
}
运行结果

- 匿名内部类是一个没有名字的内部类
- 匿名内部类写出来就会产生一个匿名内部类的对象
- 匿名内部类的对象类型相当于是当前new的那个类型的子类型

浙公网安备 33010602011771号