A Spock Blog.|

SpockC

园龄:3年7个月粉丝:0关注:0

📂Java
🔖Java
2022-01-08 21:16阅读: 33评论: 0推荐: 0

07 - 面向对象编程(高级部分一)

一、类变量和类方法

1. 类变量

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

定义语法:
	访问修饰符 static 数据类型 变量名

访问:
	类名.类变量名
	对象名.类变量名(静态变量的访问修饰符的访问权限和普通属性是一样的)

使用场景

  • 需要让某个类的所有对象都共享使用一个变量时,就可以考虑使用类变量。
  • 比如:定义一个学生类,每个学生缴纳班费,统计所有的学生一共交了多少钱。
package OOP_Highlevel.static_;

public class Student {  //学生类

    private String name;

    private Long money;

    //静态变量/类变量 班费的声明
    public static Long fee = 0L;

    public Student(String name, Long money) {
        this.name = name;
        this.money = money;
    }

    public Long getMoney() {
        return money;
    }
}


package OOP_Highlevel.static_;

public class static_demo01 {

    public static void main(String[] args){

        Student student1 = new Student("Lee",20L);
        Student.fee += student1.getMoney();

        Student student2 = new Student("Kity",30L);
        Student.fee += student2.getMoney();

        Student student3 = new Student("Jack",100L);
        Student.fee += student3.getMoney();

        System.out.println(Student.getFee());
    }
}

注意事项

	1.类变量,即静态变量,会被同一个类的所有实例对象共享
	2.static变量,在类加载的时候就生成了
	3.类变量是随着类的加载而创建,所以即使没有创建对象实例也可以访问
	4.类变量的访问必须遵守相关的访问权限
	5.当需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量
	6.类变量是该类的所有对象共享的,而实例变量是每个对象独享的
	7.加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
	8.类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问,推荐使用类名.对象名方式访问
	9.实例变量不能通过 类名.类变量名 方式访问
	10.类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只有类加载了,就可以使用类变量了
	11.类变量的生命周期是随着类 的加载开始,随着类的消亡而销毁

2. 类方法

基本介绍

类方法也叫静态方法
形式
	访问修饰符 static 数据返回类型 方法名(){}

类方法调用

类名.类方法名
对象名.类方法名

使用场景

当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率
在程序开发中,往往会将一些通用的方法,设计成静态方法,比如工具类

注意事项

1.类方法和普通方法都是随着类的加载而加载,将结构信息存储到方法区
2.类方法中无this的参数,普通方法中隐含着this的参数
3.类方法可以通过类名调用,也可以通过对象名调用
4.普通方法和对象有关,需要通过对象名调用,比如对象名.方法名,不能通过类名调用
5.类方法中不允许使用和对象有关的关键字,比如thissuper,普通方法可以
6.类方法中只能访问静态变量或静态方法
7.普通成员方法即可以访问非静态成员,也可以访问静态成员

二、理解 main 方法语法

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

说明

main 方法是虚拟机调用
Java虚拟机需要调用类的 main 方法,所以该方法的访问权限必须是public
Java虚拟机在执行 main 方法时不必创建对象,所以该方法必须是 static
该方法接收 String 类型的数组参数,该数组中保存执行Java命令时传递给运行类的参数
Java执行的程序 参数1 参数2 参数3
可在运行时传参

注意

main()方法中,可以直接调用 main 方法所在类的静态方法或者静态属性
但是不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员

三、代码块

基本介绍

  • 代码块又称初始化块,属于类中的成员(即是类的一部分)类似于方法,将逻辑语句封装在方法体中,通过{}包围起来

  • 但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。

基本语法

修饰符 {
	代码
};
  • 注意:
  1. 修饰符可选,要写的话,也只能写static
  2. 代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块
  3. 逻辑语句可以为任何逻辑语句(输入 输出 方法调用 循环 判断)
  4. 分号可以写,也可以省略

代码块好处

相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作

场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性

注意事项

1static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只执行一次
如果是普通代码块,每创建一个对象,就执行一次

2)类什么时候被加载
	1 - 创建对象实例时(new2 - 创建子类对象实例,父类也会被加载
	3 - 使用类的静态成员时(静态属性 静态方法)

3)普通的代码块,在创建实例时,会被隐式的调用
	被创建一次,就会调用一次
	如果只是使用类的静态成员时,普通代码块并不会执行


小结:
1 - static代码块是类加载时 执行的,并且只会执行一次。
2 - 普通代码块是在创建对象时调用的,创建一次,调用一次。

4)创建一个对象时,在一个类的调用顺序是:
	1 - 调用静态代码块和静态属性初始化
	(注意 静态代码块 和 静态属性初始化 调用的优先级一样
	如果有多个 静态代码块 和多个 静态属性变量初始化,则按照他们定义的顺序调用)
	2 - 调用 普通代码块 和 普通属性初始化
	(注意 普通代码块 和 普通属性初始化 调用的优先级一样
	如果有多个普通代码块和多个 普通属性初始化,则按定义属性调用)
	3 - 调用构造方法
class A {
	{ //普通代码块
		System.out.println("A 普通代码块 01"); 
	}
	private int n2 = getN2();//普通属性的初始化

	static { //静态代码块
		System.out.println("A 静态代码块 01");
	}
	private static int n1 = getN1();//静态属性的初始化


	public static int getN1() {//静态方法
		System.out.println("getN1 被调用...");
		return 100; 
	}

	public int getN2() { //普通方法/非静态方法 
		System.out.println("getN2 被调用..."); 
	return 200;
	}

	//无参构造器 
	public A() {
		System.out.println("A() 构造器被调用"); 
	}
}

public class CodeBlockDetail02 {
	public static void main(String[] args) {
		A a = new A();
		/* 
			(1) A静态代码块 
			(2) getN1 被调用...
			(3) A 普通代码块 
			(4) getN2 被调用...
			(5) A() 构造器被调用
		*/
	}
}

5)构造器的最前面其实隐含了 super() 和 调用普通代码块。
	静态相关的代码块,属性初始化,在类加载时就执行完毕,因此是优先于构造器和普通代码块执行的
class AAA { //父类 Object
	{
		System.out.println("AAA 的普通代码块");
	}

	public AAA() {
		//(1)super()
		//(2)调用本类的普通代码块
		System.out.println("AAA() 构造器被调用....");
	}
}
class BBB extends AAA {
	{
		System.out.println("BBB 的普通代码块..."); 
	}
	
	public BBB() {
		//(1)super()
		//(2)调用本类的普通代码块
		System.out.println("BBB() 构造器被调用....");
	}
}

public class CodeBlockDetail03 {
	public static void main(String[] args) {
		new BBB();
		/*
			(1)AAA 的普通代码块
			(2)AAA() 构造器被调用
			(3)BBB 的普通代码块
			(4)BBB() 构造器被调用 
		*/
	}
}

6)创建子类对象时,静态代码块、静态属性初始化、普通代码块、普通属性初始化构造方法的调用顺序:
	1 - 父类的静态代码块和静态属性
	2 - 子类的静态代码块和静态属性
	3 - 父类的普通代码块和普通属性
	4 - 父类的构造方法
	5 - 子类的普通代码块和普通属性初始化
	6 - 子类的构造方法

7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。

四、单例设计模式

什么是设计模式

1. 静态方法和属性的经典使用

2. 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。

什么是单例设计模式

1. 所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中
对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法

2. 单例模式有两种方式:
	1)饿汉式
	2)懒汉式

单例设计模式应用实例

演示 饿汉式 和 懒汉式 单例设计模式的实现
步骤如下:
	1 - 构造器私有化 ----> 防止直接 new 对象
	2 - 在类的内部创建对象
	3 - 向外暴露一个静态的公共方法---getInstance
  1. 饿汉式—单例设计模式
/**
* 演示饿汉式的单例模式 
*/
public class SingleTon01 {
	public static void main(String[] args) { 
		//GirlFriend xh = new GirlFriend("小红"); 
		//GirlFriend xb = new GirlFriend("小白");
		
		//通过方法可以获取对象
		GirlFriend instance = GirlFriend.getInstance(); 	
		System.out.println(instance);
		
		GirlFriend instance2 = GirlFriend.getInstance(); 	
		System.out.println(instance2);
		
		System.out.println(instance == instance2);//T //表示是同一个对象	
		
	} 
}

class GirlFriend {
		private String name;
		
		public static int n1 = 999;
		// 为了能够在静态方法中,返回 gf 对象,需要将其修饰为 static
		// 饿汉式表示创建对象但是沒有使用
		// 比如调用该类的静态变量时,类会加载完毕
		// 即使没有使用该对象,但是也创建了
		private static GirlFriend gf = new GirlFriend("小红红");
		// 如何保障我们只能创建一个 GirlFriend 对象 
		// 步骤[单例模式-饿汉式]
		//1. 将构造器私有化
		//2. 在类的内部直接创建对象(该对象是 static) 
		//3. 提供一个公共的 static 方法,返回 gf 对象 
		private GirlFriend(String name) {
			System.out.println("构造器被调用.");
			this.name = name; 
		}
		
		//获取构造器的方法
		public static GirlFriend getInstance() { 
			return gf;
		}
	}
}

  1. 懒汉式—单例设计模式
/**
* 演示懒汉式的单例模式 
*/
class Cat {
	private String name;
	public static int n1 = 999;
	
	//步骤
	//1.仍然构造器私有化
	private Cat(String name) {
		System.out.println("构造器调用...");
		this.name = name; 
	}

	//2.定义一個 static 静态属性
	private static Cat cat ;
	
	//3.提供一個 public 的 static 方法,可以返回一個 Cat 對象
	public static Cat getInstance() {
		if(cat == null) {
		//如果还没有创建 cat 对象
		cat = new Cat("小可爱");
		}

	//4.懒汉式,只有当用户使用 getInstance 时,才返回 cat 对象
	//再次调用時,会返回上次创建的 cat 对象 ,从而保证了单例
	return cat; 
	}
}

public class SingleTon02 {
	public static void main(String[] args) {
		
		Cat instance = Cat.getInstance(); 
		System.out.println(instance);
		
		//再次调用 getInstance
		Cat instance2 = Cat.getInstance(); 
		System.out.println(instance2);
		
		System.out.println(instance == instance2);//T,表示是同一个对象
	} 
}

饿汉式 VS 懒汉式

1. 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。

2. 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。(后面学习线程后,会完善一把)

3. 饿汉式存在浪费资源的可能。
因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了
懒汉式是使用时才创建,就不存在这个问题。

4. 在 JavaSE 的标准类中,java.lang.Runtime 就是经典的单例模式

本文作者:SpockC

本文链接:https://www.cnblogs.com/SpockC/p/15779635.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   SpockC  阅读(33)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起