找回密码
 立即注册
注册 登录
×
热搜: 活动 交友 discuz
查看: 109|回复: 1

高级面向对象编程

[复制链接]

1

主题

6

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2022-11-9 16:34:52 | 显示全部楼层 |阅读模式
类变量和类方法

类变量/静态变量

类变量也叫静态变量/静态属性,是该类所有对象共享的变量,该类中任一对象去访问得到的都是相同的值;任何一个该类的对象去修改它时,修改的也是同一个变量

  • 类变量可以通过类名直接访问
  • 存放位置:jdk7之前--变量放在方法区的静态域中;jdk8及以后--变量放在堆中class对象的最后(在类中加载后,会在堆中生成一个相应类的class对象)

    • static变量是同一类所有对象共享的
    • static变量在类加载时生成的


定义:

  • 访问修饰符 static 数据类型 变量名;
  • static 访问修饰符 数据类型 变量名;
访问:静态变量访问修饰符的访问权限和范围和普通属性是一样的

  • 类名.类变量名 或 对象名.类变量名
类变量使用注意事项和细节讨论


  • 什么时候使用?

    • 当需要让某个类的所有对象都共享一个变量时,就可以考虑使用



  • 类变量和实例变量区别?

    • 类变量是该类所有对象共享的
    • 实例变量时每个对象独享的



  • 加上static成为类变量或静态变量,否则成为实例变量/普通变量/非静态变量
  • 类变量可以通过类名.类变量名 或 对象名.类变量名访问
  • 类变量的生命周期随类的的加载开始,类的消亡而销毁
类方法/静态方法

定义:

  • 访问修饰符 static 数据返回类型 方法名(){};
  • static 访问修饰符 数据返回类型 方法名(){};
访问:
类名.类方法名 或 对象名.类方法名
类方法使用场景:

  • 当方法中不涉及任何和对象相关的成员时,可以将方法设计成静态方法,提高开发效率  -- 希望不创建实例也可以调用某个方法(当做工具来使用)时,静态方法是非常合适的
类方法使用注意事项和细节讨论


  • 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区
  • 类方法中不允许使用和对象有关的关键字,比如this和super。普通方法可以
  • 类方法中只能访问静态变量或静态方法;普通成员方法既可以访问非静态成员,也可以访问静态成员
静态方法只能访问静态变量或静态方法,普通方法可以访问静态和非静态成员
main方法语法

语法:public static void main(String[] args){}

  • java虚拟机需要调用类的main方法,所以访问权限必须是public
  • java虚拟机在执行main()时不必创建对象,所以该方法必须是static
  • 该方法接收String类数组参数,该数组中保存执行java命令时传递给所运行类的参数
  • String[] args怎么来的?--当程序执行时,所传入的参数即构成String数组,执行顺序按输入顺序进行
注意:

  • 在main方法中,可以直接调用main所在类的静态成员
  • 但不能直接访问该类中的非静态成员,必须创建该类的一个实例后才能访问
代码块

定义:代码块又称初始化块,属于类中的成员,类似于方法,将逻辑语句封装在方法体重,通过{}包围起来
    和方法不同,它没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类或创建对象时隐式调用
语法:[修饰符]{代码};
注意:

  • 修饰符可选,但只能写static  2.代码块有静态代码块和普通代码块两类
    3. 逻辑语句可以为任何逻辑语句 4.";"可以写,也可以省略
优点:1.相当于另一种形式的构造器,可以做初始化操作
            2.如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码重用性

  • 代码块可作构造器的补充,将同类多个构造器中相同的语句放进代码块
  • 无论调用哪个构造器,在创建对象时,都会先调用代码块内容
  • 代码块调用的顺序优先于构造器
代码块使用注意事项和细节讨论


  • static代码块也叫静态代码块,对类进行初始化,随着类的加载而执行,且只执行一次;普通代码块,每创建一个对象就执行
  • 类什么时候被加载[重要!]

    • 1.创建对象实例时(new)
    • 2.创建子类对象实例,父类也会被加载(先父类,再子类)
    • 3.使用类的静态成员时



  • 普通代码块在创建对象实例时,会被隐式的调用,创建一次就调用一次;

    • 如果只是使用类的静态成员时,普通代码块不会被执行



  • 创建一个对象时,在一个类中调用的顺序是:

  • 调用静态代码块和静态属性初始化(两者优先级一致)
  • 调用普通代码块和普通属性初始化(两者优先级一致)
  • 调用构造方法


  • 构造器的最前面其实隐含了super()和调用普通代码块
  • 当创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:

    • 父类静态代码块和静态属性(优先级一样)
    • 子类静态代码块和静态属性(优先级一样)
    • 父类普通代码块和普通属性初始化(优先级一样)
    • 父类构造方法
    • 子类普通代码块和普通属性初始化(优先级一样)
    • 子类构造方法



  • 静态代码块只能直接调用静态成员,普通代码块可以调用任意成员
单例设计模式


  • 类的单例设计模式就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,且该类只提供一个取得其对象实例的方法
  • 有两种单例模式:1) 饿汉式--没有调用实例但可能创建了    2) 懒汉式--使用才创建
  • 实现步骤 [饿汉式单例模式]

    • 构造器私有化  -- 防止直接new
    • 类的内部创建静态对象
    • 向外暴露一个静态的公共方法 如getInstance()
    • 缺点:可能造成创建了对象但没有使用,造成资源浪费



  • 实现步骤 [懒汉式单例模式]

    • 构造器私有化  -- 防止直接new
    • 类的内部创建静态对象
    • 提供一个静态的公共方法 ,返回一个Cat对象
    • 只有当用户使用公共方法时才返回对象,后面再次使用时会返回上次创建的对象,从而保证单例



  • 饿汉式和懒汉式

    • 饿汉式在类加载时就创建了对象实例;懒汉式在使用时才创建
    • 饿汉式不存在线程安全问题;懒汉式存在
    • 饿汉式存在浪费资源的可能;懒汉式不存在

final关键字

final可以修饰类、属性、方法和局部变量
final使用场景:

  • 当不希望类被继承时,可以使用
  • 当不希望父类的某个方法被子类覆盖/重写(override)时,可以使用
  • 当不希望类的某个属性值被修改时,可以使用
  • 当不希望某个局部变量被修改时,可以使用  --  称为局部常量
final使用注意事项和细节讨论


  • final修饰的属性又叫常量,一般用xx_xx_xx来命名
  • final修饰的属性必须在定义时就赋值,且之后不能再修改,赋值位置如下

    • 定义时,如public final double TAX_RATE=0.08
    • 在构造器中
    • 在代码块中



  • 若final是修饰的是静态属性,则赋值初始化位置只能在

    • 定义时
    • 在静态代码块中



  • final类不能被继承,但是可以实例化对象
  • 如果类不是final类但含有final方法,虽然该方法不能重写,但可以被继承
  • 如果一个类已经是final类,则没有必要再将方法修饰为final方法
  • final不能修饰构造器
  • final和static往往搭配使用效率更高(不会导致类加载),底层编译器做了优化
  • 包装类(Integer, Double, Float等都是final), String也是final类
抽象类

当父类某些方法需要声明但又不确定如何实现时,可以将其声明为抽象方法(没有实现,即没有方法体),这个类就是抽象类

  • 用abstract关键字修饰的类叫做抽象类

    • 访问修饰符 abstract 类名{}



  • abstract修饰方法时,该方法叫抽象方法

    • 访问修饰符 abstract 返回类型 方法名(参数列表) //没有方法体



  • 一般而言,抽象类会被继承,由其子类实现具体功能
抽象类使用注意事项和细节讨论


  • 抽象类不能被实例化
  • 抽象类不一定要包含abstract方法,还可以有实现的方法
  • 一旦类包含了abstract方法,则类必须声明为abstract
  • abstract只能修饰类和方法,不能修饰属性和其他
  • 抽象类可以有任意成员 -- 抽象类也是类,如非抽象方法、构造器、静态属性等
  • 抽象方法不能有主体,即不能实现
  • 如果一个类继承抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为抽象类
  • 抽象方法不能使用private、final和static来修饰,因为这些关键字和重写相违背

    • 抽象方法的方法体需要子类实现, 上述三个修饰符则定义了类不能被重写


模板设计模式

模板方法模式是类的行为模式,准备一个抽象类,将部分逻辑以具体方法及构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。
模式中的角色:

  • 抽象类:实现模板方法,定义算法骨架
  • 具体类:实现抽象类中的抽象方法,以完成完整的算法
一般需求:

  • 有多个类,完成不同的job
  • 要求能得到各自的完成时间
模板模式优缺点:

  • 优点:通过把不变的行为搬移到超类,去除子类中的重复代码。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
  • 缺点:每个不同实现都需要定义一个子类,会导致类的个数增加,设计更加抽象
  • 适用场景:在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。
接口

定义:给出一些没有实现的方法,封装到一起,到某个类要是用时,再根据具体情况把这些方法写出来
注意:如果一个类implement实现接口,则需要将接口的所有抽象方法都实现
语法:
interface 接口名{
    //属性
    //方法(1.抽象方法 2.默认实现方法 3.静态方法)
}

class 类名 implements 接口{
    自己属性;
    自己方法;
    必须实现的接口的抽象方法;
}

  • 在jdk7.0前接口中所有的方法都没有方法体
  • jdk8.0后接口类可以有静态方法,默认方法, (即接口中可以有方法的具体实现)
接口使用注意事项和细节讨论


  • 接口不能被实例化
  • 接口中所有的方法是public方法,接口中的抽象方法可以不用abstract修饰
  • 一个普通类实现接口,就必须将改接口的所有方法都实现
  • 抽象类实现接口,可以不用实现接口的方法
  • 一个类同时可以实现多个接口,即可以拥有接口中的属性
  • 接口中的属性只能是final的,而且是public static final 修饰符
  • 接口中属性的访问形式:接口名.属性名
  • 接口不能继承它的类,但可以继承多个别接口

    • 接口和接口 -- 继承
    • 类和接口 -- 实现



  • 接口的修饰符 只能是public和默认
接口和继承的异同:

当子类继承父类,就自动拥有分类的功能;如果子类需要扩展功能,可以通过实现接口的方式扩展  --  实现接口是对java单继承机制的一种补充

  • 接口和继承解决的问题不同

    • 继承 -- 解决代码的复用性和可维护性
    • 接口 -- 设计各种规范,让其他类实现这些方法



  • 接口比继承更加灵活

    • 继承满足is-a的关系;接口满足like-a的关系



  • 接口在一定程度上实现代码解耦
接口的多态性


  • 多态参数InterfacePolyParameter -- 接口可以接收实现接口的不同类的对象实例
  • 多态数组InterfacePolyArr -- 数组可以接收实现接口的不同类的对象实例
  • 接口存在多态传递InterfacePolyPass -- 当A类实现了AA接口 而AA接口继承BB接口,则A类也实现了BB接口
小结:类的五大成员
1. 属性    2.方法    3.构造器    4.代码块    5.内部类
内部类

定义:一个内的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类。内部类最大的特点是可以访问私有属性,并且可以体现类与类之间的包含关系
语法:
class Outer{//外部类
    class Inner{//内部类
   
    }
}
class Other{//外部其他类

}内部类的分类


  • 定义在外部类局部位置上 (比如在方法内)

    • 局部内部类 (有类名)
    • 匿名内部类 (没有类名,重点)



  • 定义在外部类的成员位置上

    • 成员内部类 (没有static修饰)
    • 静态内部类 (使用static修饰)


局部内部类

局部内部类是定义在外部类的局部位置,比如方法中,并且有类名

  • 可以直接访问外部类的所有成员,包括私有
  • 不能添加访问修饰符,因为它就是一个局部变量,局部变量不能使用修饰符但可以使用final修饰
  • 作用域仅仅在定义它的方法或代码块中
  • 局部内部类  访问  外部类成员

    • 访问方式:直接访问



  • 外部内  访问  局部内部类的成员

    • 访问方式:创建对象,再访问 (必须在作用域中)



  • 外部其他类 不能访问 局部内部类 (因为局部内部类地位是一个局部变量)
  • 如果外部类和局部内部类成员重名,默认遵循就近原则。若想访问外部类成员,则可使用 外部类名.this.成员 进行访问 (外部类名.this 表示 外部类对象)
重点:(1)局部内部类定义在方法/代码块中  (2)作用域在方法体或代码块中 (3)局部内部类本质仍是一个类
匿名内部类

匿名内部类定义在外部类的局部位置,比如方法中,且没有类名
基本语法:
new 类或接口(参数列表){
    类体
};重点:(1) 本质是类  (2) 内部类  (3) 该类没有名字  (4) 同时还是一个对象
匿名内部类的使用注意事项和细节讨论


  • 匿名内部类既是一个类的定义,也是一个对象;因此既有定义类的特征,也有创建对象的特征
匿名内部类方法调用:
1. new A(){}.cry();
2. A a = new A();
    a.cry();

  • 可以直接访问外部类的所有成员,包含私有的
  • 不能添加访问修饰符,因为它的地位是一个局部变量
  • 作用域:仅仅在定义它的方法或代码块中
  • 匿名内部类  访问  外部类成员

    • 访问方式:直接访问



  • 外部其他类  不能访问  匿名内部类
  • 如果匿名内部类和外部类成员重名,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可使用 (外部类名.this.成员) 访问
成员内部类

定义在外部类的成员位置,且没有static修饰

  • 可以直接访问外部类的所有成员,包括私有的
  • 可以添加人员访问修饰符,因为它的本质是一个成员
  • 作用域:和外部类其他成员一样,为整个类体
  • 成员内部类  访问  外部类成员

    • 访问方式:直接访问



  • 外部类  访问  内部类

    • 访问方式:创建对象,再访问



  • 外部其他类  访问  成员内部类
  • 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可使用 (外部类名.this.成员) 访问
静态内部类

静态内部类是定义在外部类的成员位置,且有static修饰

  • 可以直接访问外部类的所有静态成员,包括私有的,但不能直接访问非静态成员
  • 可以添加任何访问修饰符,因为它就是一个成员
  • 作用域:同其他成员,为整个类体
  • 静态内部类  访问  外部类

    • 访问方式:直接访问所有静态成员



  • 外部类  访问  静态内部类

    • 访问方式:先创建对象,再访问



  • 外部其他类  访问  静态内部类
  • 如果外部类和静态内部类成员重名时,静态内部类访问遵循就近原则,如果访问外部类成员,则可以使用(外部类名.成员)进行访问
小结


  • 内部类有四种:局部内部类、匿名内部类、成员内部类和静态内部类
  • 重点掌握匿名内部类 new 类/接口(参数列表){};
  • 成员内部类和静态内部类 反正外部类的成员位置,本质就是一个成员
回复

使用道具 举报

3

主题

7

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2025-2-28 10:18:02 | 显示全部楼层
前排,哇咔咔
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋| 黑客通

GMT+8, 2025-4-18 05:00 , Processed in 0.136339 second(s), 35 queries .

Powered by Discuz! X3.4

Copyright © 2020, LianLian.

快速回复 返回顶部 返回列表