1. 引入
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象, 只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。
例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
2. 理解
static :静态的
3. 使用
3.1 使用范围
在Java类中,可用 static 修饰属性、方法、代码块、内部类
3.2 static修饰属性
3.2.1 设计思想
类属性作为该类各个对象之间共享的变量。在设计类时,分析哪些属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
3.2.2 分类
属性,按是否使用 static 修饰,又分为:
静态属性(静态变量或类变量)vs 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
3.2.3 注意
静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用。
静态变量的加载要早于对象的创建。
修饰的成员,被所有对象所共享。
访问权限允许时,可不创建对象,直接被类调用。
由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
无论创建多少个对象,静态数据都只占用一份存储区域。
static 关键字不能应用于局部变量, 因此它只能作用于域。
① 如果一个域是静态的基本类型域,且也没有对它进行初始化,那么它就会获得基本类型的标准初值。
② 如果它是一个对象引用,那么它的默认初始化值就是 null 。
静态变量与实例变量可修饰的范围区别:
类 | yes | no |
对象 | yes | yes |
3.2.4 举例
静态属性举例: ① System.out; ② Math.PI;
应用举例:
应用举例1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Test1 { public static void main(String args[]) { Circle c1 = new Circle( 2.0 ); Circle c2 = new Circle( 3.0 ); c1.display(); //name:这是一个圆radius:2.0 c2.display(); //name:这是一个圆radius:3.0 } } class Circle { private double radius; public static String name = "这是一个圆" ; public static String getName() { return name; } public Circle( double radius) { this .radius = radius; } public double findArea() { return Math.PI * radius * radius; } public void display() { System.out.println( "name:" + name + "radius:" + radius); } } |
应用举例2:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Person { private int id; public static int total = 0 ; public Person() { total++; id = total; } public static void main(String args[]){ Person Tom= new Person(); Tom.id= 0 ; total= 100 ; // 不用创建对象就可以访问静态成员 } } |
应用举例3:
1 2 3 4 5 6 7 8 9 |
public class StaticDemo { public static void main(String args[]) { Person.total = 100 ; // 不用创建对象就可以访问静态成员 //访问方式:类名.类属性,类名.类方法 System.out.println(Person.total); Person c = new Person(); System.out.println(c.total); //101 } } |
3.2.5 类变量内存解析
图解1:
图解2:
3.3 static修饰方法
3.3.1 设计思想
如果方法与调用者无关,则这样的方法通常被声明为类方法,由 于不需要创建对象就可以调用类方法,从而简化了方法的调用。
3.3.2 理解
static 修饰方法为静态方法。
3.3.3 使用
没有对象的实例时,可以用 类名.方法名() 的形式访问由 static 修饰的类方法。
静态方法与非静态方法可修饰的范围区别:
类 | yes | no |
对象 | yes | yes |
3.3.4 注意
因为不需要实例就可以访问 static 方法,因此 static 方法内部不能有 this 。(也不能有 super )
static 修饰的方法不能被重写。
静态方法中,只能调用静态的方法或属性。
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。
3.3.5 举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
public class StaticTest { public static void main(String[] args) { Chinese.nation = "中国" ; Chinese c1 = new Chinese(); c1.name = "姚明" ; c1.age = 40 ; c1.nation = "CHN" ; Chinese c2 = new Chinese(); c2.name = "马龙" ; c2.age = 30 ; c2.nation = "CHINA" ; System.out.println(c1.nation); //CHINA //编译不通过 // Chinese.name = "张继科"; c1.eat(); Chinese.show(); //编译不通过 // Chinese.eat(); // Chinese.info(); } } //中国人 class Chinese{ String name; int age; static String nation; public void eat(){ System.out.println( "中国人吃中餐" ); //调用非静态结构 this .info(); System.out.println( "name :" +name); //调用静态结构 walk(); System.out.println( "nation : " + nation); } public static void show(){ System.out.println( "我是一个中国人!" ); //不能调用非静态的结构 // eat(); // name = "Tom"; //可以调用静态的结构 System.out.println(Chinese.nation); walk(); } public void info(){ System.out.println( "name :" + name + ",age : " + age); } public static void walk(){ } } |
4. 注意
关于静态属性和静态方法的使用,可都从生命周期的角度去理解。
开发中,如何确定一个属性是否要声明为 static 的?
属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
类中的常量也常常声明为 static 。
开发中,如何确定一个方法是否要声明为 static 的?
操作静态属性的方法,通常设置为 static 的。
工具类中的方法,习惯上声明为 static 的。 比如: Math 、 Arrays 、 Collections 。
5. 单例 (Singleton)设计模式
5.1 概述
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。]套路]
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们应该怎么做呢?
① 我们首先必须将类的构造器的访问权限设置为 private
这样,就不能用 new 操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。
② 其次,指向类内部产生的该类对象的变量也必须定义成静态的
因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
5.2 优点
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
5.3 单例设计模式-饿汉式
1 2 3 4 5 6 7 8 9 10 11 12 |
class Singleton { // 1.私有化构造器 private Singleton() { } // 2.内部提供一个当前类的实例 // 4.此实例也必须静态化 private static Singleton single = new Singleton(); // 3.提供公共的静态的方法,返回当前类的对象 public static Singleton getInstance() { return single; } } |
5.4 单例设计模式-懒汉式
(1)单例设计模式-懒汉式(线程不安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Singleton { // 1.私有化构造器 private Singleton() { } // 2.内部提供一个当前类的实例 // 4.此实例也必须静态化 private static Singleton single; // 3.提供公共的静态的方法,返回当前类的对象 public static Singleton getInstance() { if (single == null ) { single = new Singleton(); } return single; } } |
(2)单例设计模式-懒汉式(线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class BankTest { } class Bank{ private Bank(){} private static Bank instance = null ; public static Bank getInstance(){ //方式一:效率稍差 // synchronized (Bank.class) { // if(instance == null){ // // instance = new Bank(); // } // return instance; // } //方式二:效率更高 if (instance == null ){ synchronized (Bank. class ) { if (instance == null ){ instance = new Bank(); } } } return instance; } } |
5.5 应用场景
网站的计数器,一般也是单例模式实现,否则难以同步。
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置 文件数据,都生成一个对象去读取。
Application 也是单例的典型应用。
Windows 的 Task Manager (任务管理器)就是很典型的单例模式。
Windows 的 RecycleBin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
到此这篇关于Java超详细透彻讲解static的文章就介绍到这了,更多相关Java static内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://blog.csdn.net/weixin_52533007/article/details/124522586
查看更多关于Java超详细透彻讲解static的详细内容...