回顾类中的实例变量(即非static的成员变量)
class Circle{
private double radius;
public Circle(double radius){
this.radius=radius;
}
public double findArea(){
return Math.PI*radius*radius;
}
}
创建两个Circle对象:
Circle c1=new Circle(2.0); //c1.radius=2.0
Circle c2=new Circle(3.0); //c2.radius=3.0
Circle类中的变量radius是一个实例变量(instance variable),它属于类的每一个对象,c1中的radius变化不会影响c2的radius,反之亦然。
如果想让一个成员变量被类的所有实例所共享,就用static修饰即可,称为类变量(或类属性)!
1.1 类属性、类方法的设计思想
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份
。例如,所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
此外,在类中声明的实例方法,在类的外面必须要先创建对象,才能调用。但是有些方法的调用者和当前类的对象无关,这样的方法通常被声明为类方法
,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
这里的类变量、类方法,只需要使用static
修饰即可。所以也称为静态变量、静态方法。
1.2 static关键字
-
使用范围:
-
在Java类中,可用static修饰属性、方法、代码块、内部类
-
-
被修饰后的成员具备以下特点:
-
随着类的加载而加载
-
优先于对象存在
-
修饰的成员,被所有对象所共享
-
访问权限允许时,可不创建对象,直接被类调用
-
1.3 静态变量
1.3.1 语法格式
使用static修饰的成员变量就是静态变量(或类变量、类属性)
[修饰符] class 类{
[其他修饰符] static 数据类型 变量名;
}
1.3.2 静态变量的特点
-
静态变量的默认值规则和实例变量一样。
-
静态变量值是所有对象共享。
-
静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。
-
如果权限修饰符允许,在其他类中可以通过“
类名.静态变量
”直接访问,也可以通过“对象.静态变量
”的方式访问(但是更推荐使用类名.静态变量的方式)。 -
静态变量的get/set方法也静态的,当局部变量与静态变量
重名时
,使用“类名.静态变量
”进行区分。
没有用static修饰前
所谓的实际变量就是每个对象一份
package chapter08_oop3.src.com.atguigu01._static;/*** ClassName: clineseTest* Package: chapter08_oop3.src.com.atguigu01._static* Description:** @Author 小白* @Create 2024/4/3 17:33* @Version 1.0*/ public class clineseTest {public static void main(String[] args) {Clinese c1 = new Clinese();c1.name = "朱元璋";c1.age = 40;Clinese c2 = new Clinese();c2.name = "小明王";c2.age = 23;System.out.println(c1);System.out.println(c2);}}class Clinese{ //中国人类//非静态变量 实际变量String name;int age;@Overridepublic String toString() {return "Clinese{" +"name='" + name + '\'' +", age=" + age +'}';} }
加了static后 没必要每个对象一份
package chapter08_oop3.src.com.atguigu01._static;/*** ClassName: clineseTest* Package: chapter08_oop3.src.com.atguigu01._static* Description:** @Author 小白* @Create 2024/4/3 17:33* @Version 1.0*/ public class clineseTest {public static void main(String[] args) {Clinese c1 = new Clinese();c1.name = "朱元璋";c1.age = 40;c1.nation ="china";Clinese c2 = new Clinese();c2.name = "小明王";c2.age = 23;System.out.println(c1);System.out.println(c2);System.out.println(c1.nation); //chinaSystem.out.println(c2.nation); //chinac2.nation = "CHN";System.out.println(c1.nation); //CHNSystem.out.println(c2.nation); //CHN}}class Clinese{ //中国人类//非静态变量 实际变量String name;int age;//静态变量、类变量static String nation; //国@Overridepublic String toString() {return "Clinese{" +"name='" + name + '\'' +", age=" + age +'}';} }
1.3.3 举例
举例1:
class Chinese{
//实例变量
String name;
int age;
//类变量
static String nation;//国籍public Chinese() {
}public Chinese(String name, int age) {
this.name = name;
this.age = age;
}@Override
public String toString() {
return "Chinese{" +
"name='" + name + '\'' +
", age=" + age +
", nation='" + nation + '\'' +
'}';
}
}
public class StaticTest {
public static void main(String[] args) {
Chinese c1 = new Chinese("康师傅",36);
c1.nation = "中华人民共和国";Chinese c2 = new Chinese("老干妈",66);
System.out.println(c1);
System.out.println(c2);System.out.println(Chinese.nation);
}
}
对应的内存结构:(以经典的JDK6内存解析为例,此时静态变量存储在方法区)
举例2:
package com.atguigu.keyword;
public class Employee {
private static int total;//这里私有化,在类的外面必须使用get/set方法的方式来访问静态变量
static String company; //这里缺省权限修饰符,是为了方便类外以“类名.静态变量”的方式访问
private int id;
private String name;public Employee() {
total++;
id = total;//这里使用total静态变量的值为id属性赋值
}public Employee(String name) {
this();
this.name = name;
}public void setId(int id) {
this.id = id;
}public int getId() {
return id;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public static int getTotal() {
return total;
}public static void setTotal(int total) {
Employee.total = total;
}@Override
public String toString() {
return "Employee{company = " + company + ",id = " + id + " ,name=" + name +"}";
}
}
package com.atguigu.keyword;
public class TestStaticVariable {
public static void main(String[] args) {
//静态变量total的默认值是0
System.out.println("Employee.total = " + Employee.getTotal());Employee e1 = new Employee("张三");
Employee e2 = new Employee("李四");
System.out.println(e1);//静态变量company的默认值是null
System.out.println(e2);//静态变量company的默认值是null
System.out.println("Employee.total = " + Employee.getTotal());//静态变量total值是2Employee.company = "尚硅谷";
System.out.println(e1);//静态变量company的值是尚硅谷
System.out.println(e2);//静态变量company的值是尚硅谷//只要权限修饰符允许,虽然不推荐,但是也可以通过“对象.静态变量”的形式来访问
e1.company = "超级尚硅谷";System.out.println(e1);//静态变量company的值是超级尚硅谷
System.out.println(e2);//静态变量company的值是超级尚硅谷
}
}
1.3.4 内存解析
1.4 静态方法
1.4.1 语法格式
用static修饰的成员方法就是静态方法。
[修饰符] class 类{
[其他修饰符] static 返回值类型 方法名(形参列表){
方法体
}
}
1.4.2 静态方法的特点
-
静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。
-
只要权限修饰符允许,静态方法在其他类中可以通过“类名.静态方法“的方式调用。也可以通过”对象.静态方法“的方式调用(但是更推荐使用类名.静态方法的方式)。
-
在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。
-
静态方法可以被子类继承,但不能被子类重写。
-
静态方法的调用都只看编译时类型。
-
因为不需要实例就可以访问static方法,因此static方法内部不能有this,也不能有super。如果有重名问题,使用“类名.”进行区别。
静态可以类调属性
package chapter08_oop3.src.com.atguigu01._static;/*** ClassName: clineseTest* Package: chapter08_oop3.src.com.atguigu01._static* Description:** @Author 小白* @Create 2024/4/3 17:33* @Version 1.0*/ public class clineseTest {public static void main(String[] args) {System.out.println(Chinese.nation); //静态可以类调属性Chinese c1 = new Chinese();c1.name = "朱元璋";c1.age = 40;c1.nation ="china";Chinese c2 = new Chinese();c2.name = "小明王";c2.age = 23;System.out.println(c1);System.out.println(c2);System.out.println(c1.nation); //chinaSystem.out.println(c2.nation); //chinac2.nation = "CHN";System.out.println(c1.nation); //CHNSystem.out.println(c2.nation); //CHN}}class Chinese{ //中国人类//非静态变量 实际变量String name;int age;//静态变量、类变量static String nation = "中国"; //国@Overridepublic String toString() {return "Clinese{" +"name='" + name + '\'' +", age=" + age +'}';} }
1.4.3 举例
package com.atguigu.keyword;
public class Father {
public static void method(){
System.out.println("Father.method");
}public static void fun(){
System.out.println("Father.fun");
}
}
package com.atguigu.keyword;
public class Son extends Father{
// @Override //尝试重写静态方法,加上@Override编译报错,去掉Override不报错,但是也不是重写
public static void fun(){
System.out.println("Son.fun");
}
}
package com.atguigu.keyword;
public class TestStaticMethod {
public static void main(String[] args) {
Father.method();
Son.method();//继承静态方法Father f = new Son();
f.method();//执行Father类中的method
}
}