915 字
5 分钟
Java学习笔记(2)
2025-03-08

可变参数#

Java的函数支持可变参数。在Java中,可变参数允许在调用方法时传入不定数量的参数。这为方法提供了一种灵活的方式来处理不同数量的输入。

要定义一个可变参数方法,只需在参数类型后加上省略号(…)。例如,以下是一个简单的可变参数方法的示例:

public class VarargsExample {
    public static void main(String[] args) {
        // 调用可变参数方法
        printNumbers(1, 2, 3, 4, 5);
        printNumbers(10, 20);
    }
    // 定义可变参数方法
    public static void printNumbers(int... numbers) {
        for (int number : numbers) {
            System.out.println(number);
        }
    }
}

在这个示例中,printNumbers方法可以接受任意数量的int类型参数。当调用这个方法时,可以传入任意数量的整数,方法会遍历并打印每个数字。

需要注意的是,可变参数必须是方法参数列表中的最后一个参数,并且一个方法只能有一个可变参数。如果方法还有其他参数,它们必须位于可变参数之前。

此外,可变参数在内部实际上是一个数组,因此可以像数组一样进行操作。但是,为了提高代码的可读性和清晰度,建议在需要处理不定数量参数的情况下使用可变参数。

Java类内实例化与循环引用分析#

静态方法实例化类#

Java中类的静态方法(比如main)属于类本身,而不是实例。在静态方法中,可以创建该类的实例,这没有问题。比如常见的public static void main里,通常会创建自己类的实例来启动程序。所以这并不会导致循环引用,因为这只是创建一个实例,而不会无限递归。比如:

public class Test {
    public static void main(String[] args) {
    	Test t = new Test(); // 这是合法的,不会导致循环
    }
}

这时候,每次运行main方法会创建一个Test实例,但如果没有在构造函数里再次创建Test实例的话,就不会有问题。

循环引用#

  • 循环引用的定义:循环引用指两个或多个对象互相持有引用,导致无法被垃圾回收。例如:
class A { B b; }
class B { A a; }

实际上,只有在构造函数中不加控制地创建自身实例只会导致栈溢出。

public class Test {
    public Test() {
    	new Test(); // 每次构造都会创建新的实例,导致无限递归,栈溢出
    }
    public static void main(String[] args) {
    	new Test();
    }
}

同时,对象之间的相互引用,比如A引用B,B引用A,这样可能导致内存泄漏。

public class reference {
    private class Node{
        int a, b, c;
        Node(int a, int b, int c){
            this.a = a;
            this.b = b;
            this.c = c;
        }
        public String toString(){
            return "a: " + a + " b: " + b + " c: " + c;
        }
    }
    public void change(Node node){
        node.a = 1;
        node.b = 2;
        node.c = 3;
    }
    public static void main(String[] args) {
        reference outer = new reference();
        Node node = outer.new Node(0, 0, 0);
        System.out.println(node);
        outer.change(node);
        System.out.println(node);
    }
}

这段代码仅存在单向引用nodeouter),而非referenceNode互相引用。因此不存在循环引用。

非静态内部类在编译后会生成一个包含外部类引用的构造器。例如,Node类会被编译为类似以下形式:

class reference$Node {
    final reference outer; // 隐式持有外部类实例
    int a, b, c;
    
    reference$Node(reference outer, int a, int b, int c) {
        this.outer = outer;
        this.a = a;
        // ...
    }
}
  • 当你通过outer.new Node(...)创建Node实例时,实际调用的是上述构造器,将outer作为参数传入。
Java学习笔记(2)
http://zaoweiceng.github.io/posts/java/java学习笔记_2/
作者
静惜
发布于
2025-03-08
许可协议
CC BY-NC-SA 4.0