首页 > 其他分享 >static

static

时间:2024-09-07 22:48:56浏览次数:3  
标签:name 静态 age static Student public 变量

概述

static 表示静态的意思,是 Java 的一个修饰符,可以修饰成员方法或者成员变量。

被 static 修饰的成员变量叫做静态变量,被 static 修饰的成员方法叫做静态方法(static method)

静态变量被该类的所有对象共享,所有对象的这个变量都是同一个值,在一处修改了,对所有的对象都有效果。

静态变量有两种访问方法,一种是用类名访问,一种是用类的对象来访问。更推荐用类名访问。

静态方法多用于测试类和工具类中,Javabean 类中很少用静态方法。静态方法有两种访问方法,一种是用类名访问,一种是用类的对象来访问。更推荐用类名访问。

目前接触到的三种类:

Javabean 类:用来描述一些事物,如 Student,Users 等。

测试类:用来检查其他的类书写是否正确,包含 main() 方法,是程序的主入口。

工具类:不描述任何事物,但是可以帮助我们做一些事情。

静态方法只能访问静态成员变量和静态成员方法。

非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法。

非静态方法访问变量或方法都是通过 this 对象来访问的,而静态的变量或方法既可以用类访问也可以用对象来访问,因此非静态的方法可以访问静态的方法或变量。

静态方法中不允许使用 this 关键字。

静态方法和变量和非静态方法和变量的加载时机不同:静态方法和静态变量是随着类的加载而加载到内存中的。非静态方法和变量随着对象的加载而加载。由此也能说明静态不能调用非静态,因为如果这个时候还没有 new 出来一个对象,那么对象就还不存在,只有静态的方法和变量存在于内存中。

用类名调用的内容,都要去静态区中查找相应的内容。比如用类名调用静态方法,那么该方法内用到的所有东西,比如变量等,都要去静态区查找。如果静态方法中用到了非静态的变量,而该变量不会存在于静态区中,而是随着类的加载进入了方法区(类的字节码文件加载进方法区),静态区从 JDK 8 开始,就被放到了堆内存中,非静态的东西不存在于静态区中,所以在静态区中找不到非静态的东西,因此静态的方法不能调用非静态的变量或方法,这是从内存的角度来解释的。

非静态的成员变量也被称为实例变量。因此,类中的成员变量分为实例变量(非静态)和静态变量(用 static 修饰)

程序示例:

不使用静态变量的情况:

Javabean 类:

public class Student {
    // 私有化成员变量
    private int age;
    private String name;
    private String gender;

    // 新增一个成员变量:老师的姓名, 且是 public 的, 下面的 show() 方法也要修改, 打印出老师的姓名
    public String teacherName;  // 此处追求简单,就暂时不给这个成员变量做构造方法和 getter 和 setter 的修改

    // 构造方法
    // 空参构造
    public Student() {
    }

    // 全参构造
    public Student(int age, String name, String gender) {
        this.age = age;
        this.name = name;
        this.gender = gender;
    }

    // getter and setter
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    // 其他行为
    public void study() {
        System.out.println(name + "正在学习");
    }

    public void show() {
        System.out.println(name + ", " + age + ", " + gender + ", " + teacherName);
    }
}

测试类:

public class StudentTest {
    public static void main(String[] args) {
        // 创建第一个学生对象, 成员变量用 set 方法赋值
        Student s1 = new Student();
        s1.setName("张三");
        s1.setAge(23);
        s1.setGender("男");
        s1.teacherName = "王老师";

        // 调用学生对象的成员方法
        s1.study();
        s1.show();  // 张三, 23, 男, 王老师

        // 创建第二个学生对象, 成员变量用 set 方法赋值
        Student s2 = new Student();
        s2.setName("李四");
        s2.setAge(24);
        s2.setGender("女");

        // 调用学生对象的成员方法
        s2.study();
        s2.show();  // 李四, 24, 女, null
        // 第二个对象的 teacherName 属性没有赋值, 就保持了默认值 null
        // 此处显然是不合理的, 一个班级的同学, 老师这个属性显然是共享的
        // 如果每一个对象都需要单独给这个共享的属性赋值, 显然太麻烦, 也容易出错
        // 正确做法是只赋值一次, 就能让所有的对象都共享这个属性
        // 做法是让这个属性成为私有的, 即加上 static 修饰符来修饰这个属性
        // 这样就表示所有的 Student 对象都共享同一个 teacherName 属性
    }
}

程序示例:

Javabean 类:

public class Student {
    private String name;
    private int age;
    private static String teacherName;  // private 的静态成员变量
    public static String classes;  // public 的静态成员变量

    public Student() {
    }

    public Student(String name, int age, String teacherName, String classes) {
        this.name = name;
        this.age = age;
        this.teacherName = teacherName;
        this.classes = classes;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return teacherName
     */
    public String getTeacherName() {
        return teacherName;
    }

    /**
     * 设置
     * @param teacherName
     */
    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }

    /**
     * 获取
     * @return classes
     */
    public String getClasses() {
        return classes;
    }

    /**
     * 设置
     * @param classes
     */
    public void setClasses(String classes) {
        this.classes = classes;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", teacherName = " + teacherName + ", classes = " + classes + "}";
    }
}

测试类:

public class staticDemo1 {
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
        s1.classes = "001";                 // 用对象直接访问 public 的 static 成员变量
        System.out.println(s1.classes);     // 001
        System.out.println(s2.classes);     // 001,修改了一个对象的 static 成员变量的值,其他对象的这个值也变为相同的内容
        Student.classes = "002";            // 用类访问 static 成员变量
        System.out.println(s1.classes);     // 002
        System.out.println(s2.classes);     // 002
        s1.setTeacherName("xiao");          // 对象调用 set 方法来修改 private 的 static 成员变量的值
        System.out.println(s1.getTeacherName());        // xiao
        System.out.println(s2.getTeacherName());        // xiao
    }
}

非静态成员方法有一个自带的隐藏的形参 this。这个形参不是在调用方法的时候我们手动赋值的,这个形参不允许手动赋值。在调用方法时,虚拟机给这个形参赋值。哪个对象调用了这个方法,那么 this 就表示这个对象的地址值,因此 this 的类型也跟随着对象的类型而变化。这个隐藏的 this 形参位于形参列表的第一个位置。

this 代表这个对象, 因此 this 的类型就是当前所在的这个类名.

代码示例:

public class Student {
    private String name;
    private int age;

    public void show1() {  // 等价于 public void show1(Student this), 此处, this 的类型为 Student
        System.out.println(name + ", " + age);
    }

    public static void method() {
        System.out.println("静态方法");
    }
}

代码示例:

Javabean 类:

public class Student {
    private String name;
    private int age;

    public void show1() {  // 等价于 public void show1(Student this)
        System.out.println("this: " + this);  // 即便方法定义的括号内没有写 this 这个形参, 方法体内也可以使用 this 这个对象
    }

    public static void method() {
        System.out.println("静态方法");
    }
}

测试类:

public class StudentTest {
    public static void main(String[] args) {
        Student s1 = new Student();
        System.out.println("s1: " + s1);  // s1: a02staticdemo2.Student@404b9385
        s1.show1();  // this: a02staticdemo2.Student@404b9385

        Student s2 = new Student();
        System.out.println("s2: " + s2);  // s2: a02staticdemo2.Student@6d311334
        s2.show1();  // this: a02staticdemo2.Student@6d311334
    }
}

代码示例:

public class Student {
    private String name;
    private int age;

    public void show1() {
        System.out.println(name + ", " + age);  // name 等价于 this.name, age 等价于 this.age, 此处没有重名, 所以 this 可以省略
        show2();  // 调用其他方法, 相当于 this.show2()
    }

    
    public void show2(){
        System.out.println("show2");
    }
    public static void method() {
        System.out.println("静态方法");
    }
}

非静态的东西, 往往是和对象相关的, 比如里面的方法体, 是打印某个对象的 name 和某个对象的 age, 所以此处有 this, 是和对象相关的, this 指明了是哪个对象.

静态的东西是所有对象共享的, 不是和某个具体的对象有关系的. 所以 Java 在设计的时候, 在静态方法里面就没有 this 关键字.

静态和非静态的内容, 加载到内存中的时机是不同的. 静态的内容是随着类的加载而加载到内存中的. 非静态的东西是随着对象的创建而加载进内存中的.

静态方法在执行时, 只会去堆内存的静态区中去找它需要的东西, 而不是静态的内容就不会出现在静态区中, 所以静态方法只能访问静态的内容.

非静态的成员方法被调用时, 必须指定调用者, 用 this 指定. 静态方法中没有 this, 所以静态方法不能调用非静态方法.

static 内存图

程序示例:

Javabean 类:

public class Student {
    String name;
    int age;
    static String teacherName;

    public void show() {
        System.out.println(name + "..." + age + "..." + teacherName);
    }
}

测试类:

public class staticDemo1 {
    public static void main(String[] args) {
        Student.teacherName = "xiaoming";
      
        Student s1 = new Student();  // 第一个对象
        s1.name = "zhangsan";
        s1.age = 23;
        s1.show();
      
        Student s2 = new Student();  // 第二个对象
        s2.show();
    }
}

执行结果:

zhangsan...23...xiaoming
null...0...xiaoming

第一步,先执行 main() 方法,main() 方法先进栈。

第二步,执行语句 Student.teacherName = "xiaoming";

这样一来就用到了 Student 这个类,所以要把这个类的字节码文件加载到方法区,并创建了一个单独存放静态变量的空间,可以将这个空间称为静态存储位置或静态区。将字节码文件加载到内存中后,静态区就出现了。JDK8 之前,静态区是在方法区里面的,到了 JDK8 之后,就将其放到了堆空间中。在静态区中就存放着这个类的所有的静态变量。静态变量的默认初始化值和普通成员变量的规则相同。此时在内存中尚无对象,因为代码还没有执行到 new 关键字。只有 new 关键字执行了,在内存中才有对象。因此静态变量是优先于对象而存在的,是随着类的加载而加载的。类一旦加载进了内存,这个静态变量就会出现。只要是用 static 修饰的,不限于成员变量,都随着类的加载而加载,优先于对象出现在内存中。

第三步,执行 Student s1 = new Student();

等号左边在 main() 方法中定义了一个变量 s1,等号右边在堆内存开辟了一个空间,这个空间存储了所有的非静态的成员变量。这个空间的地址被赋值给了变量 s1。如果想要通过 s1 去访问静态变量 teacherName,就要去静态区去找对应的变量。

第四步,执行 s1.name = "zhangsan";s1.age = 23;

第五步,执行 s1.show();

此时,show() 方法被加载进栈。show() 方法的调用者是 s1。执行完毕之后 show() 方法出栈。

第六步,执行 Student s2 = new Student();

等号左边在 main() 方法中定义了一个变量 s2,等号右边在堆内存又开辟了一个新的空间,这个空间存储了所有的非静态的成员变量。这个空间的地址被赋值给了变量 s2。如果想要通过 s1 去访问静态变量 teacherName,就要去静态区去找对应的变量。

第七步,执行 s2.show();

此时,show() 方法被加载进栈。show() 方法的调用者是 s2。执行完毕之后 show() 方法出栈。

静态区中的变量是对象共享的,在内存中只有一份,谁要用谁去拿。非静态区的变量,是每一个对象所独有的,在每一个对象内单独存放。

标签:name,静态,age,static,Student,public,变量
From: https://www.cnblogs.com/Chengkai730/p/18402264

相关文章

  • 封装、static~
    封装1.封装的基本知识1.1什么是封装  首先上面代码定义了一个Date类,类中有三个成员变量year、month、day和一个printDate成员方法,通过main函数实例化了一个date1对象,date1.分别访问了变量和方法,输出了2024年9月7日。  但如果将成员变量year的访问限定符public改......
  • 响应式单位rpx及搭配UI产品工具和@import导入css样式和scss变量与用法static目录以及p
    1.响应式单位rpx及搭配UI产品工具1.对于rpx的认知和用法以及对于px的区别我们可以去官网先了解一下我们的rpx用法和注意以及与px的区别。链接:页面样式与布局|uni-app官网(dcloud.net.cn)我平时使用的px是我们的屏幕像素的单位,我们在一个页面创建一个view组件,并且给其在......
  • 【Moveit2】MoveGroupInterface设置目标姿态,然后创建一个计划到该姿态的运动路径,stati
    PlanandExecuteusingMoveGroupInterface//CreatetheMoveItMoveGroupInterfaceusingmoveit::planning_interface::MoveGroupInterface;automove_group_interface=MoveGroupInterface(node,"panda_arm");//SetatargetPoseautoconsttarget_p......
  • static 数据 编程中的作用
      编程的开发语言有静态强类型语言和动态弱类型语言。静态强类型语言有C/C++,JAVA。静态的开发语言是编译型的开发语言。计算机的编程开发由程序设计师编写代码,源代码文件通过不同语言的编译器编译后会生成不同的机器执行文件。解释性语言为动态弱类型语言,编译型语言是静态强......
  • C++(static_cast)
    目录1.语法2.示例3.为什么选择static_cast总结static_cast是C++中的一种类型转换运算符,用于在不同的数据类型之间进行安全转换。与C风格的强制类型转换不同,static_cast更加安全和明确。它主要用于进行类型转换时,确保转换是合法的,并且不会引入不必要的风险。1.语法......
  • 【Java 基础】类和对象(构造&this&封装&static&代码块)
    ✨                           风起于青萍之末,浪成于微澜之间    ......
  • 【Java学习】静态static&继承
    一、静态static(一)定义static是静态的意思,static可以修饰成员变量或者修饰方法。static关键字的使用,它可以用来修饰的成员变量和成员方法,被static修饰的成员是属于类的,放在静态区中,没有static修饰的成员变量和方法则是属于对象的。static关键字在Java开发非常的重要,对于理......
  • C++学习——类当中static关键字的作用
    一、类和对象我们知道类是“行为”和“属性”的集合,我们可以通过类来实例化对象,从而定义对象的“行为”和“属性”。比如:classCar{ Stringbrand; Stringlicense; Stringcolor;}CarToyota;这里定义了“Car”的类,通过“Car”这个类实例化了“Toyota”。那么类当中的......
  • [1048] Hosting a static website using Amazon S3
    ref:HostingastaticwebsiteusingAmazonS3TohostastaticwebsiteonanAmazonS3bucket,followthesesteps:Step-by-StepGuideCreateanS3Bucket:OpentheAmazonS3console.Clickon“Createbucket”.Enterauniquebucketnameandchoosea......
  • 利用instanceof比较类、类之间的类型转换和Static
    instanceof引用类型,类型转换判断某一个对象是不是某个类型的类的实例(有关系才能比较,否则会报错)能不能编译通过,取决于X与Y是否存在父子关系例子:父类代表高类,子类代表低类Object>Persion>TeacherObjectobject=new.Student();System.out.println(obje......