1. static关键字
当我们编写一个类时,其实就是在描述其对象的属性和方法,而并没有产生实质上的对象,只有通过new关键字才会产生对象,这时系统才会分配内存空间给对象,其方法才可以通过对象调用。
我们有时候希望无论是否产生了对象或无论产生了多少对象,某些特定的数据在内存空间里只有一份。例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
1、static关键字的使用
- static:静态的
- static可以用来修饰:属性、方法、代码块、内部类
- 使用static修饰属性:
3.1
static修饰的属性称为静态变量(或称静态属性、类变量)
① 属性按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
② 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象的非静态属性时,不会导致其他对象中同样的属性值的修改。
③ 静态变量: 我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过的。
3.2
static修饰属性的其他说明:
① 静态变量随着类的加载而加载,静态变量是归类所有的。可以通过 “类.静态变量” 的方式进行调用。
② 静态变量的加载要早于对象的创建。造完一个对象后才有对象,但要想造对象,要使用构造器,要用构造器得先把类加载到内存中。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在于方法区的静态域中。
④ 调用:
类变量 | 实例变量 | |
---|---|---|
类 | yes(类.类变量) | no |
对象 | yes(对象.类变量) | yes(对象.实例变量) |
package statictest;
public class StaticTest {
public static void main(String[] args) {
//可以通过类调用类变量
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "张三";
c1.age = 20;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "李四";
c2.age = 23;
c2.nation = CHINA;
//改c2的nation属性时,c1的nation属性也改了
System.out.println(c1.nation);//CHINA
}
}
class Chinese{
String name;
int age;
//属性nation声明为static类型
static String nation;
}
类变量和实例变量的内存解析:
- 使用static修饰方法:静态方法
① 随着类的加载而加载,静态方法是归类所有的。可以通过 “类.静态方法” 的方式进行调用。
② 调用:
静态方法 | 非静态方法 | |
---|---|---|
类 | yes(类.静态方法) | no |
对象 | yes(对象.静态方法) | yes(对象.非静态方法) |
③ 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
④ 在静态方法内,不能使用this、super关键字
⑤ 关于静态属性和静态方法的使用,应该从生命周期的角度去理解。
package statictest;
public class StaticTest {
public static void main(String[] args) {
Chinese.nation = "中国";
Chinese c1 = new Chinese();
c1.name = "张三";
c1.age = 20;
c1.nation = "CHN";
Chinese c2 = new Chinese();
c2.name = "李四";
c2.age = 23;
System.out.println(c2.nation);//CHN
Chinese.eat();
}
}
class Chinese{
String name;
int age;
//属性nation声明为static类型
static String nation;
public static void eat(){
System.out.println("中国人吃中餐");
//静态方法中不能调非静态方法
// work();
//静态方法中可以调静态方法
sleep();
}
public void work(){
System.out.println("人需要工作养活自己");
//非静态方法中可以调静态方法
eat();
//非静态方法中可以调静态方法
sleep();
}
public static void sleep(){
System.out.println("人需要睡觉");
}
}
- 开发中,如何确定一个属性是否要声明为static的?
① 属性是可以被多个对象共享的,不会随着对象的不同而不同。
② 类中的常量也经常声明为static的 - 开发中,如何确定一个方法是否要声明为static的?
① 操作静态属性的方法,通常设置为static的
② 工具类中的方法,习惯上声明为static的。比如:Math、Arrays、Collections。
static关键字的练习
1、
package statictest;
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle(3);
System.out.println("c1的编号为:" + c1.getId());
System.out.println("c2的编号为:" + c2.getId());
System.out.println("c3的编号为:" + c3.getId());
System.out.println("圆的个数为:" + Circle.getTotal());
}
}
class Circle{
private double radius;//圆的半径
private int id;//圆的编号
private static int total;//统计圆的个数
private static int init = 1001;//圆的初始编号,static声明的属性被所有对象共享
public Circle(){
id = init++;//
total++;
}
public Circle(double radius){
this();
// id = init++;
// total++;
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public int getId() {
return id;
}
public static int getTotal() {
return total;
}
public static int getInit() {
return init;
}
}
输出结果:
2、
package statictest;
public class AccountTest {
public static void main(String[] args) {
Account a1 = new Account();
Account a2 = new Account("123456",10000);
Account a3 = new Account("654321",2000);
System.out.println(a1);//调用重写的toString方法
System.out.println(a2);
System.out.println(a3);
}
}
class Account{
private int id;//账号id要自动生成
private String pwd = "000000";//银行卡初始密码000000
private double balance;
private static double rate = 0.0123;
private static double minBalance = 100;
private static int init = 1001;//用于自动生成id时使用
public Account(){
id = init++;
}
public Account(String pwd,int balance) {
id = init++;
this.pwd = pwd;
this.balance = balance;
}
//属性的get和set方法根据实际情况看是否需要
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public double getBalance() {
return balance;
}
@Override
public String toString() {
return "Account{" + "id=" + id + ", pwd='" + pwd + '\''+
", balance=" + balance + '}';
}
}
2.static应用—单例设计模式
- 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。(通俗理解,就是“套路”)。
- 常用设计模式 — 23种经典的设计模式
- 创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
- 结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
- 所谓类的单例设计模式,就是采取一定的方法
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法,如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。