面向对象-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的那个类型的子类型
posted @ 2022-03-13 18:44  呵嗷嚎  阅读(41)  评论(0)    收藏  举报