文章目录
- 一、类导入单例static
- (1) static 修饰成员变量
- (2) static 修饰成员方法
- 二、变量静态导入
- (1) 静态导入概念
- (2) 静态导入使用场景
- 三、类方如何给实例变量设置初始值
- 四、键字静态静态如何给类变量设置初始值
- 五、初始初始继承中出现(静态)初始化块 ☆
- 六、化块化块单例模式
一、模式static
☘️ static
可用来修饰类的类导入单例成员:成员变量、方法、变量嵌套类
public class Person { /* static 可以修饰成员变量 */ private static int age; /* static 可以修饰成员方法 */ public static void eat() { } /* static 可以修饰嵌套类 */ static class Head { }}
(1) static 修饰成员变量
☘️ 被static
修饰的类方成员变量可叫做:类变量、静态变量、键字静态静态静态字段
☘️ 类变量在程序运行过程中只占用一份固定的初始初始内存(存储在方法区)
☘️ 可通过类名访问
☘️ 可通过引用变量名访问(不推荐)
类名或引用变量名访问静态变量:
public class VisitStaticField { public static void main(String[] args) { /* 通过类名访问静态变量 */ // Book.bookNum = 1 System.out.println("Book.bookNum = " + Book.bookNum); Book.bookNum = 11; /* 通过引用变量名访问静态变量 */ // book 是引用变量名 Book book = new Book(); // book.bookNum = 11 System.out.println("book.bookNum = " + book.bookNum); }}class Book { /* bookNum 是一个静态变量 (类变量) */ public static int bookNum = 1;}
统计 Person 对象的个数:
public class CountPersonObjectNum { public static void main(String[] args) { Person p = new Person(); Person pp = new Person(); Person ppp = new Person(); Person pppp = new Person(); Person ppppp = new Person(); Person pppppp = new Person(); Person ppppppp = new Person(); // 当前 Person 对象个数:7 System.out.println("当前 Person 对象个数:" + Person.personObjNum); }}class Person { /* personObjNum 记录 Person 对象的个数 */ public static int personObjNum = 0; public Person() { personObjNum++; }}
☘️ 没有被static
修饰的成员变量可叫做:实例变量
☘️ 实例变量在每个实例内部都有一份内存(存储在堆空间)
☘️ 只能通过引用变量名访问
(2) static 修饰成员方法
☘️ 被 static
修饰的成员方法可叫做:类方法、静态方法
☘️ 类方法可通过类名调用
☘️ 类方法可通过引用变量名调用通过类名或对象名调用类方法:
public class TestDemo { public static void main(String[] args) { /* 通过类名调用类方法 */ String randStr1 = GqUtil.obtainRandomStr(); /* 通过引用变量名(对象名)访问类方法(不推荐) */ GqUtil util = new GqUtil(); String randStr2 = util.obtainRandomStr(); // randStr1 = 2185dffafc244193a9c056db2cf7ba93 System.out.println("randStr1 = " + randStr1); // randStr2 = 9beb2ecd2a4842f18692b33354508c16 System.out.println("randStr2 = " + randStr2); }}class GqUtil { /** * 被 static 修饰的化块化块方法叫做类方法(或静态方法) * 作用:返回随机字符串 */ public static String obtainRandomStr() { return UUID.randomUUID().toString().replace("-", ""); }}
☘️ 类方法内部坚决不能使用this
✏️
this
:
① 与实例挂钩
② 是一个隐藏的、位置最靠前的模式方法参数
③ 是当前对象(实例)的引用
④ 类变量、类方法可通过类名访问或调用,类导入单例与实例没有瓜葛
☘️ 类方法中可直接访问类变量和调用其他类方法
☘️ 类方法中不可以直接访问实例变量,不可以直接调用实例方法
public class TestDemo { public static void main(String[] args) { /* 通过类名调用类方法 */ String randStr1 = GqUtil.getRandString(); /* 通过引用变量名(对象名)访问类方法(不推荐) */ GqUtil util = new GqUtil(); String randStr2 = util.getRandString(); System.out.println("randStr1 = " + randStr1); System.out.println("randStr2 = " + randStr2); }}class GqUtil { /* 一个类变量 */ public static int count = 6; public String name = "庆医"; /* 类方法 */ public static String getRandString() { // 类方法中可直接访问类变量 System.out.println("count = " + count); /* 类方法中不能直接访问实例变量 name, 需创建 GqUtil 的对象, 然后通过对象名访问 name 类方法中不能直接调用实例方法 test2 需创建 GqUtil 的对象, 然后通过对象名调用 test2 */ GqUtil util = new GqUtil(); System.out.println("name = " + util.name); util.test2(); // 类方法中可调用其他类方法 test1(); return UUID.randomUUID().toString().replace("-", ""); } /* 类方法 */ public static void test1() { System.out.println("类方法 test1()"); } /* 实例方法 */ public void test2() { System.out.println("实例方法 test2()"); }}
☘️ 没有被static
修饰的方法叫做实例方法(只能通过对象名去调用)
☘️ 只能通过对象名去调用
☘️ 内部可以使用this
☘️ 可直接访问实例变量、实例方法
☘️ 可直接访问或调用类变量、类方法(类变量、类方法可通过对象名进行访问或调用)
二、静态导入
(1) 静态导入概念
☘️ 使用了静态导入后,就可以省略类名访问静态成员(成员变量、方法、嵌套类)
public class TestClass { public static int age = 1; public static void show() { System.out.println("age is " + age); } public static class Other { public void other() { System.out.println("Other_other()"); } }}
public class TestDemo { public static void main(String[] args) { // 1 System.out.println(TestClass.age); // age is 1 TestClass.show(); TestClass.Other other = new TestClass.Other(); // Other_other() other.other(); }}
静态导入后访问静态成员:
import static com.gq.TestClass.*; // 静态导入public class TestDemo { public static void main(String[] args) { // 1 System.out.println(age); // age is 1 show(); Other other = new Other(); // Other_other() other.other(); }}
(2) 静态导入使用场景
import static java.lang.Math.PI;public class TestDemo { public static void main(String[] args) { // 62.83185307179586 System.out.println(2 * PI * 10); // 125.66370614359172 System.out.println(2 * PI * 20); }}
三、如何给实例变量设置初始值
☘️ 声明的时候就赋值
☘️ 构造方法的时候赋值
☘️ 在初始化代码块中赋值
✏️ 编译器会将初始化代码块中的代码复制到每个构造方法的头部(每创建一个对象就会执行一次初始化代码块中的代码)
✏️ 先执行初始化代码块中的代码,后执行构造方法中的代码
public class TestDemo { public static void main(String[] args) { Person person = new Person("庆医"); // age = 17 System.out.println("age = " + person.age); // name = 庆医 System.out.println("name = " + person.name); // money = 67899.99 System.out.println("money = " + person.money); // address = 日本神奈川县川崎市 System.out.println("address = " + person.address); }}class Person { /* 声明 age 属性的时候就给 age 赋值 */ public int age = 17; public String name; public double money; public String address; public Person(String name) { /* 在构造方法中给 name 属性赋值 */ this.name = name; } /* 在初始化代码块中给 money 和 address 属性赋值 */ { money = 67899.99; address = "日本神奈川县川崎市"; }}
先执行初始化代码块中的代码,后执行构造方法中的代码
看下面代码,思考打印结果是什么:
public class TestDemo { public static void main(String[] args) { Person p = new Person(11, "庆医", 10000); System.out.println("age = " + p.age); // age = 12 System.out.println("name = " + p.name); // name = 庆医 System.out.println("money = " + p.money); // money = 15000.0 }}class Person { public int age; public String name; public double money; public Person(int age, String name, double money) { this.name = name; this.age = age + this.age; this.money = money + this.money; } /* 每次创建 Person 对象都会调用初始化代码块的代码 */ { name = "张浩男"; age = 1; money = 5000; }}
四、如何给类变量设置初始值
☘️ 声明的时候就赋值
☘️ 在静态初始化(代码)块中
✏️ 当一个类被初始化的时候会执行静态初始化块中的代码
✏️ 当一个类第一次被主动使用的时候,JVM 会对类进行初始化(当一个类第一次被主动使用的时候会执行静态初始化块中的代码)
✏️ 静态初始化块中的代码只会被执行一次
public class TestDemo { public static void main(String[] args) { new Person(); new Person(12898); }}class Person { /* 静态初始化块(作用:为类变量赋初始值) */ static { System.out.println("\n静态初始化块中的代码在类第一次被使用的时候会被执行一次(只执行一次)"); } /* 初始化块(为实例变量赋初始值) */ { System.out.println("初始化块中的代码会被复制到每个构造方法的头部, 每次创建对象都会执行一次初始化块中的代码"); } public Person() { } public Person(int money) { }}
☘️ 初始化块和静态初始化块都可以有多个(按照它们在源码中出现的顺序依次执行)
五、继承中出现(静态)初始化块 ☆
public class TestDemo { public static void main(String[] args) { new Student(); /* Person_静态初始化块 Student_静态初始化块 Person_初始化块 Person_Person() Student_初始化块 Student_Person() */ }}class Person { // 静态初始化块, 当类第一次被使用的时候会执行一次静态初始化块里面的代码 static { System.out.println("Person_静态初始化块"); } // 初始化块, 初始化块里面的代码会被拷贝到每个构造方法的头部 // 每次创建 Person 对象的时候都会执行一次初始化块里面的代码 { System.out.println("Person_初始化块"); } public Person() { System.out.println("Person_Person()"); }}class Student extends Person { // 静态初始化块, 当类第一次被使用的时候会执行一次静态初始化块里面的代码 static { System.out.println("Student_静态初始化块"); } // 初始化块, 初始化块里面的代码会被拷贝到每个构造方法的头部 // 每次创建 Student 对象的时候都会执行一次初始化块里面的代码 { System.out.println("Student_初始化块"); } public Student() { System.out.println("Student_Person()"); }}
六、单例模式
☘️ Singleton Pattern:如果一个类被设计成单例设计模式,则在整个应用程序运行过程中,该类只能存在一个实例。饿汉式:
class Rocket { /* 饿汉式 */ private static Rocket instance = new Rocket(); // 构造方法私有化 private Rocket() { } /** * 返回唯一的 Rocket 实例 */ public static Rocket getInstance() { return instance; }}
懒汉式:
class Rocket { /* 懒汉式: 有线程安全问题 */ private static Rocket instance = null; // 构造方法私有化 private Rocket() { } /** * 返回唯一的 Rocket 实例 */ public static Rocket getInstance() { if (instance == null) instance = new Rocket(); return instance; }}
再见!如有错误,请不吝赐教!