Static静态关键字
Static表示静态关键词可以用来修饰成员变量和成员方法
1.成员变量的分类和访问分别是什么样的
静态成员变量(有static修饰的,属于类)
注意:static修饰的成员变量,静态成员变量,只在内存中有一份,可以被共享访问、修改。
访问格式为: 类名.静态成员变量(推荐) 对象.静态成员变量(不推荐);
实例成员变量(无static 修饰,属于对象)访问格式
对象.实例成员变量
2.两种成员变量各自在什么情况下被定义
静态成员变量:表示在线人数等需要被共享的信息
实例成员变量: 属于每个对象,且每个对象的该信息不同时(name age....)
Static变量的内存机制
用类名直接调用访问更快
在此段程序中User类和Test类先加载到方法区,因为User类中有静态成员变量,因为静态成员变量随着类的加载而加载,因此此时堆内存中只有name这个空间,然后main方法进栈加载,由于第一行代码是直接用类访问静态成员变量,因此不会再栈中创建变量,此时打印出的值为null,而如果用类调用实例成员变量的话,此时代码会报错,因为实例成员变量是属于类的,但是还没有创建类,所以这个时候堆内存中是没有age的,创建User对象u后,这个时候栈中会开辟变量u的空间,堆内存中会开辟空间将类中属性加载进去,然后再将对象的地址返回给变量u中,此时就可以直接用对象来访问实例成员变量,打印出的值为0。 再创建对象u1,使用对象u1来给属性赋值,u1的age为 23,将内存中的静态成员变量改为黑马程序员。 再创建U2对象,将u2中的age改为35,将静态成员变量改为传值教育,打印u1的age属性,为23,使用u1调用name打印出来为传值教育,因为age属性是属于单个对象的,因此u1中的age和u2中的age分别为23和35,但是由于name为静态成语变量,因此该属性是User类中是共享的,因此打印出来的是u2改动的值。
Static修饰成员方法
静态成员方法(归属于类)
调用格式:类.方法名(推荐) 对象.方法名(不推荐)
实例成员方法(归属于)
调用格式: 对象.方法名
使用场景:
实例方法:表示对象自己的行为,且方法中需要访问调用成员变量的话,需要设为实例方法。
静态方法: 如果方法是以一个通用功能为目的(例如取最大值),或者需要方便访问,则可以申明成静态方法。
package com.itheima.d1_static;
public class Student {
private String name;
/*
静态成员方法: 有static修饰,归属于类,可以被访问,用类名或者对象。
*/
public static int getMax(int age1,int age2)
{
return age1 > age2 ? age1 : age2;
}
/*
实例方法:属于对象的,只能用对象触发访问。
*/
public void study(){
System.out.println(this.name + "好好学习");
}
public static void main(String[] args) {
//同一个类中,访问静态方法,类名可以不写
System.out.println(getMax(10, 32));
// study(); 报错了
Student s = new Student();
s.name = "帅哥";
s.study();
}
}
Static方法内存图
静态方法随着类的加载而加载,当Student类加载进方法区的时候,此时main方法和getMax方法同时加载进方法区,此时getMax为可访问状态。这个时候main中的第一行代码就返回10,因为study属于实例成员方法,但是这个时候还没有创建对象,因此方法区中还没有study方法,所以直接调用会报错,创建Student类对象s,此时因为成员方法在对象中存储的是方法区中的地址,study方法会加载进入方法区,因此此时用s就可以直接调用study方法。
Static注意事项
1.静态方法只能访问静态成员变量,不能“直接”访问实例成员变量,因为实例成员变量是属于对象的,因此不能直接访问。
2.实例方法可以访问静态成员变量和实例成员变量,也可以访问静态方法和实例方法。
3.静态方法中不能有this关键字。
可以通过代码看出:
package com.itheima.d1_static;
public class Test3 {
/*
静态成员
*/
public static int onlineNum = 10;
public static void test2()
{
System.out.println("==test2==");
};
/*
实例成员
*/
private String name;
public void run(){
System.out.println(name + "跑得快");
}
//3.静态方法不可以直接出现this关键词
public static void test3()
{
// System.out.println(this); this代表当前对象地址,静态方法可能不被对象调用。
}
// 2. 实例方法可以访问静态成员,也可以访问实例成员
public void go()
{
System.out.println(onlineNum);
test2();
System.out.println(name);
run();
}
//1. 静态方法只能访问 静态成员,不能“直接”访问实例成员
public static void test()
{
System.out.println(onlineNum);
// System.out.println(name); 报错
test2();
}
}
Static工具类
因为在以后的开发中,可能一种功能要在很多地方使用到(比如验证码),因此当每个人负责功能的时候都要再写一次这个功能,这个时候为了方便,就可以创建一个工具类将静态方法书写进去,这样就都可以直接使用了。
工具类:内部都是一些静态方法,每个方法完成一个功能。一次编写处处可用,提高代码的重用性。
2.工具类有什么要求?
建议工具类的构造器私有化,这样别人就可以直接用类来调用静态方法。
代码块概述
代码块是类的五大成分之一(成员变量,构造器,方法,代码块,内部类),定义再类中方法外。
在Java类下,使用{}括起来的代码叫做代码块
代码块分为两种
1.静态代码块:
格式: Staitc{ }
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发一次、只执行一次
使用场景:在类加载的时候做一些静态资源的初始化操作,以便后续调用(比如斗地主加载牌的集合
2.构造代码块(了解)
格式:{}
特点:随着该类的对象的创建调用构造器执行时,都会执行该类代码块种的代码,并且在构造器前执行;
设计模式
单例模式
可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象。
1.饿汉单例
在类加载的时候对象已经给你创建好了。
实现步骤:定义一个类,把构造器私有化,作用是不让外界创建对象。定义一个静态变量存储一个对象。
package com.itheima.singleInstance;
public class demo1 {
/*
使用饿汉单例实现单例类
*/
/*
2.饿汉单例是指在获取对象前,对象已经提前准备好了一个。
*/
public static demo1 d = new demo1();
private demo1()
{
};
}
可以看出在懒汉单例中创建的对象地址相同,因此这是同一个对象。
2.懒汉单例
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
设计步骤: 定义一个类,把构造器私有。 定义一个静态变量存储一个对象。
package com.itheima.singleInstance;
public class SingleInstance2 {
/*
3.提供方法,对外返回单例对象
*/
public static SingleInstance2 getInstance()
{
if (instance == null)
{
//第一次拿需要创建
instance = new SingleInstance2();
}
return instance;
}
/*
2.定义一个静态成员变量
最好私有化,这样可以避免给别人挖坑
*/
private static SingleInstance2 instance;
/*
私有化构造器
*/
private SingleInstance2(){
}
}
这就说明了单例是同一个对象。