Java初学-8-1--类变量和类方法(静态变量和静态方法)
类变量:
在Java中,类变量是一种特殊的静态变量,它属于类本身而不属于类的任何特定实例。这意味着无论创建了多少个该类的对象,类变量只有一个副本存在于内存中,并且这个副本对所有对象都是共享的。类变量通常用于需要在多个对象之间共享信息或状态的场景。
类变量的重要概念和特征:
声明:类变量使用static关键字在类中声明。即这个变量是与类相关联的,而不是与类的实例相关联的。
存储位置:类变量存储在方法区中,这是JVM的一个区域,用于存储类的信息、常量、静态变量等。当类加载到JVM时,类变量就会被初始化并分配内存。
初始化:类变量在类加载时被初始化。如果没有显式初始化,它们会被自动初始化为其类型的默认值(例如,数字类型为0,布尔类型为false,引用类型为null)。
访问:由于类变量是静态的,因此可以通过类名直接访问,而不需要创建类的实例。例如,如果有一个名为A的类,其中包含一个名为a的类变量,那么可以通过A.a来访问它。
修改:类变量可以在不创建类实例的情况下修改,修改会影响到所有已经创建和将来创建的该类的所有实例。
示例:
package StaticVariable;
public class StaticVariableTest001 {
public static int myStaticVariable = 10; // 声明并初始化一个类变量
public static void main(String[] args) {
System.out.println("第一次输出: " + StaticVariableTest001.myStaticVariable);
StaticVariableTest001.myStaticVariable += 5; // 修改类变量,此时myStaticVariable的值为10+5
System.out.println("第二次输出: " + StaticVariableTest001.myStaticVariable);
StaticVariableTest001 obj1 = new StaticVariableTest001();
StaticVariableTest001 obj2 = new StaticVariableTest001();
obj1.myStaticVariable += 10; // 修改类变量,影响所有实例,此时myStaticVariable的值为10+5+10
//不同对象,享受同一个变化
System.out.println("Obj1: " + obj1.myStaticVariable);
System.out.println("Obj2: " + obj2.myStaticVariable); // Obj2也显示更新后的值
//再次输出它的值
System.out.println("第三次输出: " + StaticVariableTest001.myStaticVariable);
//即同一个类享受同一个变化
}
}
在这个例子中,myStaticVariable是一个类变量,可以直接通过MyClass类名访问和修改,而不需要创建MyClass的实例。当在main方法中修改myStaticVariable时,所有MyClass的实例都受到这个修改的影响。
在Java中,类变量(也就是静态变量)的内存管理与其他类型的变量不同。当我们讨论类变量的内存时,主要关注的是它们的存储位置以及生命周期。
???存储位置???:
类变量确实存储在方法区。在Java 8及之前的版本中,方法区通常被称为永久代。从Java 9开始,永久代的概念已被移除,方法区现在被称为“元空间”,并且它使用本地内存而非堆内存。
生命周期:
类变量的生命周期与类的生命周期绑定。这意味着当类被加载到JVM中时,类变量被创建并初始化;当类卸载时,类变量才会被销毁。因此,类变量在整个程序执行期间存在,只要类没有被卸载。
初始化
当类第一次被加载到JVM中时,类变量将被初始化。如果未指定初始值,类变量将被初始化为其类型的默认值,如整型变量为0,浮点型变量为0.0,布尔型变量为false,引用类型为null。
访问和修改:类变量可以通过类名直接访问,而不需要创建类的实例。由于类变量是共享的,因此对它的任何修改都会影响所有通过该类创建的对象。
内存模型
Java的内存模型区分了不同的存储区域,类变量位于方法区。对象实例的非静态成员变量存储在堆上,局部变量和方法参数存储在栈上。这种分离确保了类变量的共享性和持久性,同时也避免了每次创建新对象时重复分配内存给相同的类变量。
总之,类变量的内存是在方法区中分配的,它们随着类的加载而存在,直到类被卸载为止。
定义格式:访问修饰符 static 数据类型 变量名;
访问格式:类名.变量名或者对象名.变量名
注意:类变量与成员变量的访问权限是相同的。
类变量与成员变量的区别:
存储位置
成员变量(也称为实例变量):存储在堆内存中每个对象的实例空间内。这意味着每当创建一个新的对象时,成员变量就会为该对象分配一份独立的存储空间。
类变量(也称为静态变量):存储在方法区(在JVM中),是所有对象共享的。无论创建多少个对象,类变量只有一份拷贝。
生命周期
成员变量:随着对象的创建而创建,随着对象的销毁而销毁。
类变量:随着类的加载而创建,随着类的卸载而销毁,这意味着类变量在整个应用程序运行期间都存在。
可见性
成员变量:只对创建该对象的实例可见,不同对象的成员变量是独立的。
类变量:对所有该类的实例都可见,它们是共享的。
访问方式
成员变量:必须通过对象实例来访问,即使用objectReference.variableName的形式。
类变量:可以通过类名直接访问,即使用ClassName.variableName的形式,也可以通过对象实例访问,但由于它是共享的,这种方式访问的也是同一个变量。
初始化
成员变量:默认初始化为它们的数据类型的默认值,也可以在构造函数中初始化。
类变量:同样初始化为数据类型的默认值,但如果在类体中显式初始化,则所有对象都将使用这个初始化值。
类方法
类方法(也常被称为静态方法)是在面向对象编程中的一种特殊类型的方法,它与类关联而不是与类的实例关联。在Java中,类方法通过static关键字来声明。类方法有几个关键特性:
不需要实例化:类方法可以直接通过类名来调用,而不需要先创建一个类的实例。这是因为类方法不依赖于类的任何实例状态。
不能访问实例变量:由于类方法不依赖于特定的对象实例,所以它们不能直接访问类的非静态(实例)变量。如果需要访问这些变量,必须先通过某个实例来引用它们。
可以访问类变量和类方法:类方法可以访问类中的所有静态(类)变量和静态(类)方法,因为这些都是与类本身相关的,而不依赖于具体的对象实例。
生命周期:类方法随类的加载而可用,并且在整个应用程序运行期间都存在,直到类被卸载。
内存占用:类方法只有一份副本存在于内存中,无论创建了多少个类的实例。
初始化:类方法可以包含初始化代码,这些代码会在第一次调用类方法或第一次访问类的静态变量时执行。
实例:
package StaticMethod;
public class StaticMethodTest01 {
public static void main(String[] args) {
StaticMethodTest001.classMethod(); // 直接调用类方法 不再创建实例
StaticMethodTest001.classVariable = 20; // 直接修改类变量
System.out.println("修改后: " + StaticMethodTest001.classVariable);
StaticMethodTest001 myObject = new StaticMethodTest001();
myObject.instanceMethod(); // 需要通过实例调用成员(实例)方法
System.out.println("修改后: " + myObject.classVariable);
}
}
class StaticMethodTest001 {
static int classVariable = 10;
//静态方法/类方法
public static void classMethod() {
System.out.println("调用StaticMethodTest001方法的静态方法。");
System.out.println("调用StaticMethodTest001方法的静态方法及静态变量(修改前): " + classVariable);
}
//成员方法
public void instanceMethod() {
System.out.println("调用StaticMethodTest001中的成员方法。");
}
}
类方法(也称为静态方法)和成员方法(也称为实例方法)的主要区别:
定义
成员方法:没有static关键字,它们是类的实例的一部分,每个对象实例拥有自己的一套方法。
类方法:由static关键字定义,表明方法与类相关联,而不是与类的任何特定实例相关联。
调用
成员方法:需要通过类的实例来调用,即先创建类的一个实例,然后使用objectReference.methodName()的形式调用。
类方法:可以直接通过类名调用,使用ClassName.methodName(),无需创建类的实例。
访问变量
成员方法:可以访问类的所有变量,包括实例变量和类变量。
类方法:不能直接访问实例变量,因为它们在调用时不依赖于特定的实例。类方法中只能访问类的类变量(静态变量)和其他类方法。
生命周期
成员方法:随类的实例的创建而存在,随实例的销毁而消失。
类方法:随类的加载而存在,随类的卸载而消失,与类的任何实例的生命周期无关。
内存占用
成员方法:每个对象实例都有其自身的一套成员方法,即使方法代码是相同的。
类方法:无论创建多少个类的实例,类方法在内存中只有一份拷贝。
* this关键字是一个引用,指向当前对象的实例。它在成员方法(实例方法)中非常有用,可以用来引用当前对象的属性或调用其他成员方法。然而,在类方法(静态方法)中,情况则完全不同。
成员方法中的this:
在成员方法中,this关键字可以用于:引用当前对象的实例变量。调用当前对象的其他成员方法。传递当前对象作为方法参数。构造当前类的另一个实例。
类方法中的this:
在类方法中,this关键字是不可用的,类方法不与任何特定的实例绑定,它们是与类本身相关的。因此,类方法中没有当前对象实例的概念,也就没有this引用的意义。
示例:
package StaticMethodTest;
public class StaticMethodTest04 {
public static void main(String[] args) {
StaticMethodTest04001 S = new StaticMethodTest04001(10);
S.instanceMethod(); // 成功调用实例方法并使用this
StaticMethodTest04001.classMethod(); // 成功调用类方法,但不能使用this
}
}
class StaticMethodTest04001 {
private int a;
//无参构造器
public StaticMethodTest04001(int b) {
this.a = b;
}
//成员方法
public void instanceMethod() {
System.out.println("成员方法instanceMethod()及传入值: " + this.a);
this.otherMethod();
}
//成员方法
public void otherMethod() {
System.out.println("成员方法otherMethod()。");
}
//类方法
public static void classMethod() {
// 下面这行会出错,因为在类方法中不能使用this关键字
// System.out.println("类方法 classMethod()及传入的值" + this.a);
// 下面这行也会出错,因为不能在类方法中调用非静态方法
// this.otherMethod();
// 可以调用其他类方法
anotherClassMethod();
}
public static void anotherClassMethod() {
System.out.println("类方法anotherClassMethod()");
}
}
* super关键字用于引用当前对象的直接父类的对象。super可以用来调用父类的构造方法,访问父类的字段,或者调用父类的方法。与this类似,super的行为在成员方法和类方法中有显著的区别。
成员方法中的super:
在成员方法中,super可以用来:访问父类的实例变量。调用父类的成员方法。调用父类的构造方法(通常在子类构造方法的第一行)。
类方法中的super:
在类方法中,super关键字的行为不同于成员方法:
类方法中不能使用super来调用父类的非静态方法或访问非静态字段,因为类方法与任何特定实例无关,而super涉及到父类的实例。然而,类方法可以调用父类的静态方法,因为这些方法也不依赖于特定的实例。
示例:
package StaticMethodTest;
public class StaticMethodTest03 {
public static void main(String[] args) {
StaticMethodTest03002 s = new StaticMethodTest03002();
s.childMethod();
s.parentMethod();
StaticMethodTest03002.childClassMethod(); // 调用类方法,可以调用父类的静态方法
}
}
class StaticMethodTest03001 {
public int a = 10;
//无参构造器
public StaticMethodTest03001() {
System.out.println("父类的无参构造器。");
}
//成员方法
public void parentMethod() {
System.out.println("父类的成员方法parentMethod()。");
}
//类方法
public static void parentClassMethod() {
System.out.println("父类的类方法parentClassMethod()。");
}
}
class StaticMethodTest03002 extends StaticMethodTest03001 {
//无参构造器
public StaticMethodTest03002() {
//super(); // 使用super调用父类构造器
System.out.println("子类的无参构造器。");
}
@Override
public void parentMethod() {
super.parentMethod(); // 使用super调用父类方法
}
public void childMethod() {
System.out.println("子类的成员方法childMethod()及a: " + super.a);
}
public static void childClassMethod() {
// 下面这行会出错,因为不能在类方法中使用super来访问父类的非静态成员
//System.out.println("静态方法 childClassMethod()及a" + super.a);
// 下面这行也是错误的,不可以使用super调用父类的静态方法
//super.parentClassMethod();
parentClassMethod();
StaticMethodTest03001.parentClassMethod();
}
}
*调用
从类方法调用成员方法
类方法不能直接调用成员方法,因为成员方法属于特定的实例。但是,如果你有一个类的实例,你可以在类方法内部通过该实例调用成员方法。如果没有实例,你不能直接从类方法调用成员方法,因为你没有一个具体的对象来调用这个方法。
从成员方法调用类方法
成员方法可以直接调用类方法,因为类方法是与类本身关联的,不需要特定的实例。成员方法可以通过类名直接调用类方法,或者通过this关键字调用类方法。
示例:
package StaticMethodTest;
public class StaticMethodTest02 {
private int a;
public StaticMethodTest02(int value) {
this.a = value;
}
public void instanceMethod() {
System.out.println("调用成员方法instanceMethod及a : " + a);
}
public static void staticMethod() {
System.out.println("调用类方法。");
// 创建类的实例
StaticMethodTest02 instance = new StaticMethodTest02(10);
System.out.println("从类方法调用成员方法: ");
instance.instanceMethod(); // 从类方法调用成员方法
}
public void instanceMethod01() {
System.out.println("调用成员方法instanceMethod01及a : " + a);
StaticMethodTest02.staticMethod();
staticMethod();
}
public static void main(String[] args) {
System.out.println("从main方法调用类方法: ");
System.out.println("1、类名加方法名调用:");
StaticMethodTest02.staticMethod();// 从main方法调用类方法
System.out.println("2、直接调用:");
staticMethod();//直接调用
StaticMethodTest02 instance01 = new StaticMethodTest02(10);
instance01.instanceMethod01();
}
}
类方法其他需要注意的:
- 类方法不能访问类的构造器,因为构造器是在创建对象实例时才运行的,而类方法不依赖于任何特定实例。
- 类方法可以接受参数和返回值,就像普通的方法一样。这些参数可以是任何类型,包括基本类型和对象。
- 类方法不能被子类重写,因为它们是与类而不是实例绑定的。如果在子类中定义一个与父类中类方法相同签名的方法,那么这将被视为一个全新的方法,而不是对父类类中方法方法的重写。
- 类方法可以从其他类方法中调用,甚至可以从不同类的类方法中调用,只要这些方法是可访问的(遵循访问控制规则)。
原文地址:https://blog.csdn.net/jhdyjbxsryokvdry/article/details/140642834
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!