面向对象高级篇·上
面向对象编程高级部分
目录:
- 类变量类方法
- 理解main方法语法
- 代码块
- 单例设计模式
- final关键字
- 抽象类
- 接口
- 内部类
类变量和类方法
在单例设计模式中很常用
设计模式还有:观察者模式,工厂模式,适配器模式,装饰者模式,代理模式,模板模式,职责链模式,组合模式,桥接模式,原型模式…
类变量/静态变量
基本介绍
- 类变量最大的特点就是静态变量会被类中所有的对象实例共享
- 任何一个对象去访问它时都是同一个值,任何一个对象去修改它,修改的也是同一个变量
- 类变量可以直接通过类名来访问
- 定义语法 ;
访问修饰符 static 数据类型 变量名;
- 访问方法:
静态变量的访问修饰符的范围和普通属性是一样的 类名.类变量名 [ 较为推荐使用 ] 或者对象名.类变量名
- 什么时候需要使用类变量?
当我们需要让某个类的所有对象都共享一个变量时
类变量内存分析
- 局部变量在使用完之后内存会被释放,但静态变量会保留内存,直到程序结束
- 一说静态变量保存在堆里,一说保存在方法区,这取决于jdk的版本,jdk8以后的都在堆里,之前的在方法区
- 静态变量被类对象共享,类加载就会生成,所以即使没有创建对象也可以访问
类方法
- 类方法也叫静态方法,用static修饰
- 定义语法:
访问修饰符 static 数据返回类型 方法名(){ //方法代码 }
- 类方法的调用 ;
类名.方法名
或者对象名.方法名
前提是满足访问修饰符的范围 - 静态方法可以访问静态属性
类方法经典的使用场景:
- 当方法中不涉及到和任何对象相关的成员,可以将方法设计为静态方法,提高开发效率
(如果我们希望不创建实例也能调用某个方法,也就是当作工具来使用,那么就很适合做成静态方法) - eg:
很多工具类都是这样,比如Math类,Arrays类,直接Math.sqrt(9)
而不用创建对象
实际开发中一些通用的方法也会做成静态方法比如打印一维数组,冒泡排序,完成某个计算任务等等,这样我们不需要创建对象也可以直接使用了(且节省了创建对象的内存) - eg:
上述代码在使用时需要需要创建对象才能使用↑class MyTools{ //两数求和 public double cal(double n1,double n2) return n1 + n2; }
但是一旦成为了静态方法↓
此时要调用的话可以直接使用class MyTools{ //两数求和 public static double cal(double n1,double n2) return n1 + n2; }
System.out.println(MyTools.cal(11,12));
类方法使用注意事项和细节讨论
- 类方法中无this的参数,普通方法中隐含着this的参数(因为this与对象相关)
- 类方法中不允许使用和对象有关的关键字,比如this,super等但成员方法可以
- 非静态方法是绝对不能通过类名调用的,只能对象名调用(静态也就是和static与类绑定,不含static只能先创建对象)
- 类方法(静态方法)中只能访问静态变量或静态方法(对于普通方法,不能直接访问,但是可以通过创建对象来进行访问成员方法)
- 普通成员方法既可以访问非静态变量/方法,也可以访问静态变量/方法
main方法语法理解
解释main方法的形式
public static void main(String[] args){}
-
public
Java虚拟机在调用类的main方法,所以方法权限必须是public -
static
Java虚拟机在执行main方法时不必创建对象,所以必须是静态方法 -
String[] args
该方法接受String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数
-
在main方法中,我们可以直接调用main方法所在类的静态方法和属性
-
但是不能直接访问该类中的非静态成员,必须创建对象,然后通过对象去访问类中的非静态方法和属性(可以理解为main方法是一种特殊的类方法)
代码块
基本介绍
- 代码块:又称为初始化块,属于类中的成员,是类的一部分,类似于方法,将逻辑语句封装在方法体中,通过{}包起来
- 但和方法不同,没有方法名,没有返回,没有参数。只有方法体,而且不用通过类显式调用,而是加载类的时候,或者创建对象的时候隐式调用
- 基本语法:
[修饰符]{
//代码
};
tips:
- 修饰符可有可无,但是要写只能写static
- 代码块分两种,要么有static修饰成为静态代码块,要么没有,那就是普通代码块
- 逻辑语句可以写任何逻辑语句
- 分号可写可不写,但最好还是写吧
代码块的好处和演示
- 相当于另一种形式的构造器,可以充当初始化操作
- 应用场景:如果多个构造器中都有重复的语句,那么可以抽取到代码块中,提高代码重用率
- 详细解读:
- 当每个构造器都有相同的语句时,看起来会很冗余
- 此时我们可以把相同的语句放入一个代码块中
- 这样我们不管调用哪个构造器,创建对象,都会调用代码块中的内容
- 代码块调用的顺序优先于构造器!!!
代码块的细节
- static代码块也叫静态代码块,作用就是对类进行初始化,它随着类的加载被执行,且只会执行一次,(第二次类已经被加载了,根据已加载类的模板创建对象)(静态代码块相当于是共享的)
- 如果是普通代码块,每创建一个对象就会执行一次,普通代码块只会在创建(new)的时候执行(普通代码块执行与否和类是否加载没有任何关系,普通代码块没有对象不会执行)
- 如果只是使用类的静态成员,普通代码块并不会执行,但静态代码块一定会执行
- 静态代码块只能直接调用静态成员,普通代码块可以调用任意成员
- 类什么时候被加载
- 创建对象实例时(new时)
- 创建子类对象实例,父类也会被加载且父类先加载,子类再加载
- 直接使用类的静态成员(静态属性/方法)时(因为其实你使用这个静态成员的时候,其实也是要先加载这个类的)
- 【代码块细节的重难点】 创建一个对象时,在同一个类中调用顺序:
- 调用静态代码块和静态属性初始化(这两个调用的优先级一样)
- 调用静态代码块和静态属性初始化(这两个调用的优先级一样)
如图所示,二者调用的优先级一样,那么按照定义顺序执行
2. 调用普通代码块和普通属性的初始化(这两个调用的优先级一样,同时存在的话也是按照定义顺序执行)
3. 最后调用构造器
-
构造器的最前面其实隐含了super()和调用普通代码块。静态相关的代码块,属性初始化,在类加载的时候就执行完毕了,因此是优先于构造器和普通代码块执行的
-
面试题【代码块使用细节最难点】
创建一个子类对象时(继承关系时)静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:- 父类的静态代码块和静态属性(优先级一样,按照定义顺序执行)
- 子类的静态代码块和静态属性(优先级一样,按照定义顺序执行)
- 父类的普通代码块和普通属性初始化(优先级一样,按照定义顺序执行)
- 父类的构造方法
- 子类的普通代码块和普通属性初始化(优先级一样,按照定义顺序执行)
- 子类的构造方法