24、使用 Java 官方教程学习:① 类变量和类方法详解;② 深入介绍 main() 方法

简介: 24、使用 Java 官方教程学习:① 类变量和类方法详解;② 深入介绍 main() 方法


一、引出类变量

需求:有一群小孩👶在玩堆雪人☃️的游戏,不时会有新的小孩加入游戏。请问如何知道现在共有多少人在玩?

public class Child {
    public static int childCnt = 0;
    private String name;
    /**
     * 返回全部的孩子个数
     */
    public int getChildCnt() {
        return childCnt;
    }
    public Child(String name) {
        this.name = name;
        childCnt++;
        System.out.println("【" + this.name + "】小朋友加入了游戏");
    }
}
public class ChildPlaySnowman {
    public static void main(String[] args) {
        System.out.println();
        
        Child qy = new Child("庆医");
        Child hn = new Child("浩男");
        Child ms = new Child("莫松");
        Child wf = new Child("王凡");
        Child lh = new Child("陆昊");
        System.out.println();
        System.out.println("共有 " + qy.getChildCnt() + " 个小孩在玩游戏!");
        System.out.println("共有 " + Child.childCnt + " 个小孩在玩游戏!");
        System.out.println("共有 " + hn.childCnt + " 个小孩在玩游戏!");
    }
}

🔑 被 static 修饰的成员变量叫做类变量(也叫做静态变量、静态字段)

🔑 类变量的值被所有该类的实例共享(所有 Child 类的对象修改 childCnt 变量的值的时候,修改的是同一个 childCnt 变量的值)

🔑 类变量在程序运行过程中只占用一份固定的内存(存储在方法区)

🔑 没有被static修饰的成员变量也叫做实例变量

🔑 类变量可通过类名访问(推荐)

🔑 类变量可通过对象名访问(不推荐)

🔑 类被初始化的时候类变量会被赋予初始值

🔑 当类第一次被主动使用的时候,类会被初始化

二、类变量(Class Variables)

(1) 官方教程

【官方教程地址(类成员)】

🌼 When a number of objects are created from the same class blueprint, they each have their own(属于它们自己的) distinct copies of instance variables.

🌾 使用同一个类的蓝图创建多个对象后,这多个对象有它们自己的独特的实例变量。

🌼 Sometimes,you want to have variables that are common to all objects.

🌾有时候,您希望拥有所有对象共有的变量。

🌼 This is accomplished with the static modifier. Fields that have the static modifier in their declaration are called static fields or class variables.

🌾 这是通过static修饰符完成的。在其声明中具有static修饰符的字段被称为静态字段类变量

🌼 They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory.

🌾 类变量与类相关联,而不与任何对象相关联。同一个类的每一个实例都共享一个类变量,类变量位于内存中的一个固定的位置。

🌼 Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.

🌾 同一个类的所有对象都可以改变类变量的值,但类变量的值也可以在不创建任何对象实例的时候被操纵。

(2) 类变量细节

✏️ ① 当需要让某个类的所有对象共享一个变量的时候,可以考虑使用类变量(静态变量)

✏️ ② 类变量是该类的所有对象共享的,而实例变量是每个对象独享的

✏️ ③ 被static修饰的称为类变量或静态变量,否则称为实例变量或属性

✏️ ④ 类变量在类加载(类被初始化:第一次主动使用类)的时候有初始值(即使没有创建对象,只要类被初始化了,类变量就有值了)

三、类方法

(1) 类方法知识点罗列

🌼 The Java programming language supports static methods as well as static variables. Static methods, which have the static modifier in their declarations, should be invoked with the class name, without the need for creating an instance of the class.

🌾 Java 语言支持静态方法(类方法)和静态变量(类变量)。方法声明的时候有static关键字的是静态方法,静态方法应该通过类名来调用,无需创建一个类的实例。

🌼 You can also refer to static methods with an object reference,

but this is discouraged because it does not make it clear that they are class methods.

🌾 你也可以通过对象引用来调用静态方法,但并不鼓励这样做,因为它没有明确说明它们是类方法

🌼 A common use for static methods is to access static fields.

🌾 静态方法的一个常见用途是访问静态字段。


🌼 ① Instance methods can access instance variables and instance methods directly. 实例方法可以直接访问实例变量和调用实例方法。

🌼 Instance methods can access class variables and class methods directly. 实例方法可以直接访问变量和调用方法。

class MethodAccessDemo {
    public static int staticVar = 666;
    private String instanceVar = "庆医";
    public int instanceMethod1() {
        // instanceVar = 庆医
        System.out.println("instanceVar = " + instanceVar);
        // staticVar = 666
        System.out.println("staticVar = " + staticVar);
        // instanceMethod2()
        instanceMethod2();
        // staticMethod()
        staticMethod();
        return staticVar;
    }
    private static void staticMethod() {
        System.out.println("staticMethod()");
    }
    public void instanceMethod2() {
        System.out.println("instanceMethod2()");
    }
}
public class Demo {
    public static void main(String[] args) {
        MethodAccessDemo instance = new MethodAccessDemo();
        int cnt = instance.instanceMethod1();
        // staticVar = 666
        System.out.println("staticVar = " + cnt);
    }
}

🌼 Class methods can access class variables and class methods directly. 类方法可以直接访问类变量和调用类方法。

🌼 Class methods cannot access instance variables or instance methods directly.【they must use an object reference. Also, class methods cannot use the this keyword as there is no instance for this to refer to】 类方法不能直接访问实例变量和调用实例方法。【在类方法中必须使用对象引用才能够访问实例变量和调用实例方法,并且类方法中不能使用this关键字,因为没有实例对象让this去引用】

(2) 案例(统计捐款金额)

📜 疫情无情,人有情。一方有难,八方支援。新冠病毒☠️肆虐我的家乡,为了帮助我们抗击疫情, 很多人用金钱给予帮助。请编写一个程序,统计总共捐款金额。

/**
 * 捐款者
 */
class Donor {
    private static double totalMoney;
    private String name;
    public Donor(String name) {
        this.name = name;
    }
    public void donate(double val) {
        if (val <= 0) {
            System.out.println("金额必须大于0");
            return;
        }
        System.out.println("\n感谢【" + name + "】资助 " + val + " 元");
        totalMoney += val;
    }
    public static double getTotalMoney() {
        return totalMoney;
    }
}
public class Demo {
    public static void main(String[] args) {
        Donor wf = new Donor("王凡");
        wf.donate(10000);
        Donor zhn = new Donor("张浩男");
        zhn.donate(99999);
        Donor qy = new Donor("庆医");
        qy.donate(800);
        // 总共收到捐款金额:110799.0
        System.out.println("\n总共收到捐款金额:" + Donor.getTotalMoney());
    }
}

(3) 类方法使用场景

✏️ 当某个方法中的代码不涉及任何与对象相关的成员的时候,可以考虑将该方法设计为静态方法

✏️ 如果希望不创建类的实例也可以调用该方法,可考虑将该方法设计为静态方法

✏️ 如 jdk 中的 MathArraysCollections

✏️ 工具类中的方法可以考虑设计为静态方法

(4) 类方法注意事项

📖 类方法和实例方法都是随着类的加载而加载的,方法的结构信息存储在方法区。this是一个隐藏的、位置最靠前的方法参数,this是指向当前对象的引用,this与实例相关。类方法中是不能使用this的【类方法可以通过类名调用,也许通过类名调用类方法的时候对象根本就没有创建(对象没有创建就不可能存在this)】

📖 实例方法的方法参数中隐藏着一个位置最靠前的方法参数this(它指向调用该方法的对象)

📖 实例方法和对象相关,只能通过对象名调用,不能通过类名调用

📖 类方法可以通过类名调用,也可以通过对象名调用

四、类变量和类方法 Exercise

第 ① 题

看下面的代码, 分析打印结果是什么?

public class Demo {
    static int count;
    public void count() {
        System.out.println("count = " + (count++));
    }
    public static void main(String[] args) {
        // count = 0
        new Demo().count();
        // count = 1
        new Demo().count();
        // 2
        System.out.println(Demo.count);
    }
}

第 ② 题

看下面的代码, 修改错误,并思考打印结果:

class Person {
    private int id;
    private static int total;
    public static int getTotalPerson() {
    /*
      1.id 是实例变量
      2.getTotalPerson() 是静态方法
      3.静态方法中不能够直接访问实例成员
     */
        // id++; // ERROR
        return total;
    }
    public Person() {
    /*
      1.total 类变量
      2.Person() 是构造方法, 构造方法是和实例相关的
      3.在构造方法中可以直接访问类变量
     */
        total++;
        id = total;
    }
}
public class TestPerson {
    public static void main(String[] args) {
        // total = 0
        System.out.println("total = " + Person.getTotalPerson());
    /*
      创建 Person 对象会调用构造方法, 构造方法的调用会使得 total 的值
      变为1, id 的值也变为1
     */
        new Person();
        // total = 1
        System.out.println("total = " + Person.getTotalPerson());
    }
}

第 ③ 题

看下面的代码, 修改错误,并思考打印结果:

class Person {
    private int id;
    public static int total;
    public static void setTotalPerson(int total) {
    /*
        1.setTotalPerson() 是类方法
      2.类方法中坚决不能使用 this 关键字
     */
        // this.total = total; // ERROR
        Person.total = total;
    }
    public Person() {
        total++;
        id = total;
    }
}
public class TestPerson {
    public static void main(String[] args) {
        Person.setTotalPerson(1);
        new Person();
        // 2
        System.out.println(Person.total);
    }
}

五、深入介绍 main() 方法

(1) 电影 Hello World

❤️ 即使世界毁灭,我也想再见你一面 ❤️

❤️为了再见你一面,我愿意重启整个世界❤️

这是日本动画电影《Hello World》里面的台词

✏️ 在京都居住的16岁内向男高中生👦直实的面前,突然出现从10年后穿越而来的自己。

✏️ 未来的直实告诉他,自己不久便会与瑠璃相爱,可是之后烟花🎆大会时瑠璃却会因为一场事故意外成为植物人。

✏️ 一心为拯救初恋的直实与十年后的自己并肩作战,卷入了这场现实与虚拟的记忆世界,经历了一系列超乎想象的事情。

✏️ 原本怯懦的高中生直实燃生了即使世界毁灭,我也想再见你一面的勇气。

✏️ 十年后穿越而来的直实也终于说出了深藏心底的那句我一直爱你 …

赶快去看看吧!🍀① 为了浪漫的台词【即使世界毁灭,我也想再见你一面;为了再见你一面,我愿意重启整个世界】;🍀② 为了刻在程序开发者心中的 Hello World!

(2) Hello World!

📃 学习一门新的编程语言的时候,大多数人的第一个程序一般都是【Hello World】,Java 的【HelloWorld】程序如下所示:

public class HelloWorld {
    public static void main(String[] args) {
        // Hello World!
        System.out.println("Hello World!");
    }
}

📃 当你第一次编写并运行了 Java 中的【HellowWorld】程序后,你便用 Java 语言和计算机打了一个招呼,有了一个美好的邂逅。

📃 这美好的邂逅是在 Java 的入口方法main()方法中进行的

📃 但对main()方法还没有一个完美的介绍

📃 下面深入介绍一下 Java 的入口方法:

public static void main(String[] args){}

(3) 深入介绍 main() 方法

public class HelloWorld {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println("parameter" + (i + 1) + ": " + args[i]);
        }
    }
}

📖 ① public:JVM 需要调用类的 main() 方法 (入口方法),所以该方法的访问权限必须是public

📖 ② static:JVM 调用main()方法的时候无需创建对象,所以是static

📖 ③ String[]main()方法接收 String 数组类型的参数,该数组中保存了执行 java 命令时传递的参数

👑 java 命令:运行 class 文件

👑 love、study、handsome 被放在字符串数组 args

👑 参数名 args 只是一个标识,写成其他的参数名也是可以的(下面的代码把 args 改为了 canShu 也是正确的)

public class HelloWorld {
    public static void main(String[] canShu) { 
        for (int i = 0; i < canShu.length; i++) {
            System.out.println("parameter" + (i + 1) + ": " + canShu[i]);
        }
    }
}

📖 ④ 在 main() 方法中可以直接调用 main() 方法所在类的静态方法或访问静态属性,但不能直接访问或调用实例成员,只有创建该类的对象后才能访问实例成员

结束!若有错误,请不吝赐教!

相关文章
|
6天前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
14天前
|
Java 编译器
Java重复定义变量详解
这段对话讨论了Java中变量作用域和重复定义的问题。学生提问为何不能重复定义变量导致编译错误,老师通过多个示例解释了编译器如何区分不同作用域内的变量,包括局部变量、成员变量和静态变量,并说明了使用`this`关键字和类名来区分变量的方法。最终,学生理解了编译器在逻辑层面检查变量定义的问题。
Java重复定义变量详解
|
14天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
37 17
|
6天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
10天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
50 4
|
10天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
11天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
26 2
|
8天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
17天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
4天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
23 9