前言
本文主要介绍java面向对象中static关键字、代码块和final关键字
1、关键字:static
static关键字的引入:
有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。
java将static关键字修饰的成员称为类成员:
- 类属性(class Variable):作为该类各个对象之间共享的变量。在设计类时,分析哪些属性不因对象的不同而改变
- 类方法:如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用:
- 没有对象的实例时,可以用类名.方法名()的形式访问由static修饰的类方法
- 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。
static的使用范围:
在Java类中,可用static修饰属性、方法、代码块、内部类
static修饰的成员的特点:
- 随着类的加载而加载
- 优先于对象存在
- 修饰的成员,被所有对象所共享
- 访问权限允许时,可不创建对象,直接被类调用
注意: - 在静态的方法内,不能使用this关键字、super关键字
- 关于静态属性和静态方法的使用,从生命周期的角度去理解
- static修饰的方法不能被重写
单例 (Singleton)设计模式:
设计模式:是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。
单例设计模式: 采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
- 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
单例(Singleton)设计模式-饿汉式
public class Singleton {
// 1.私有化构造器
private Singleton() {
}
// 2.内部提供一个当前类的实例,此实例也必须静态化
private static Singleton single = new Singleton();
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton getInstance() {
return single;
}
}
单例(Singleton)设计模式-懒汉式
public class Singleton {
/**
* 存在线程安全问题
*/
// 1.私有化构造器
private Singleton() {
}
// 2.内部提供一个当前类的实例,此实例也必须静态化
private static Singleton single;
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
单例模式的优点:
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
单例(Singleton)设计模式-应用场景
- 网站的计数器,一般也是单例模式实现,否则难以同步。
- 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
- 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
- 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置
文件数据,都生成一个对象去读取。 - Application 也是单例的典型应用
- Windows的Task Manager (任务管理器)就是很典型的单例模式
- Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
2、类的成员:代码块(初始化块)
代码块(或初始化块)的作用:
- 对Java类或对象进行初始化
代码块(或初始化块)的分类:
静态代码块(static block):一个类中代码块若有修饰符, 则只能被static修饰,static代码块通常用于初始化static的属性
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块随着类的加载而加载,且只执行一次。
class Person {
public static int total;
static {
total = 100;//为total赋初值
}…… // 其它属性或方法声明
}
非静态代码块:没有使用static修饰的
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 除了调用非静态的结构外,还可以调用静态的变量或方法。
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
- 每次创建对象的时候,都会执行一次。且先于构造器执行。
程序中成员变量赋值的执行顺序(由父及子,静态先行):
//总结:由父及子,静态先行
class Root {
static {
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root() {
super();
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root {
static {
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid() {
super();
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg) {
// 通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:" + msg);
}
}
public class Leaf extends Mid {
static {
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf() {
// 通过super调用父类中有一个字符串参数的构造器
super("尚硅谷");
System.out.println("Leaf的构造器");
}
public static void main(String[] args) {
System.out.println("-----main方法------");
new Leaf();
System.out.println("-------------------");
new Leaf();
// Root的静态初始化块
// Mid的静态初始化块
// Leaf的静态初始化块
// -----main方法------
// Root的普通初始化块
// Root的无参数的构造器
// Mid的普通初始化块
// Mid的无参数的构造器
// Mid的带参数构造器,其参数值:尚硅谷
// Leaf的普通初始化块
// Leaf的构造器
// -------------------
// Root的普通初始化块
// Root的无参数的构造器
// Mid的普通初始化块
// Mid的无参数的构造器
// Mid的带参数构造器,其参数值:尚硅谷
// Leaf的普通初始化块
// Leaf的构造器
}
}
3、关键字:final
在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终的”。
说明:
- final标记的类不能被继承。提高安全性,提高程序的可读性。
- String类、System类、StringBuffer类
- final标记的方法不能被子类重写。
- 比如:Object类中的getClass()。
- final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只
能被赋值一次。- final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋 值,然后才能使用。
- final double MY_PI = 3.14;
final int WIDTH = 0;
final int LEFT;
final int RIGHT;
{
LEFT = 1;
}
public FinalTest(){
RIGHT = 2;
}
- final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
public void show(){
final int NUM = 10;//常量
// NUM += 20;//错误
}
public void show(final int num){
// num = 20;//编译不通过
System.out.println(num);
}
- static final:全局常量