如何计算 Class 的实例数

How to Count Number of Instances of a Class

谁能告诉我如何计算 class 的实例数?

这是我的代码

public class Bicycle {

    //instance variables
    public int gear, speed, seatHeight;
    public String color;

    //constructor
    public Bicycle(int gear, int speed, int seatHeight, String color) {
        gear = 0;
        speed = 0;
        seatHeight = 0;
        color ="Unknown";      
    }

    //getters and setters
    public int getGear() {
        return gear;
    }
    public void setGear(int Gear) {
        this.gear = Gear;
    }

    public int getSpeed() {
        return speed;
    }
    public void setSpeed(int Speed){
        this.speed = Speed;
    }

    public int getSeatHeight() {
        return seatHeight;
    }
    public void setSeatHeight(int SeatHeight) {
        this.seatHeight = SeatHeight;
    }

    public String getColor() {
        return color;
    }
    public void setColor(String Color) {
        this.color = Color;
    }

 }//end class



public class Variable extends Bicycle {

    public Variable(int gear, int speed, int seatHeight, String color) {
        super(gear, speed, seatHeight, color);

    }

}//end class


public class Tester {

    public static void main(String args[]){


       Bicycle bicycle1 = new Bicycle(0, 0, 0, null);
       bicycle1.setColor("red");
       System.out.println("Color: "+bicycle1.getColor());
       bicycle1.setSeatHeight(4);
       System.out.println("Seat Height: "+bicycle1.getSeatHeight());
       bicycle1.setSpeed(10);
       System.out.println("Speed: "+bicycle1.getSpeed());
       bicycle1.setGear(6);
       System.out.println("Gear: "+bicycle1.getGear());

       System.out.println("");//space

       Bicycle bicycle2 = new Bicycle(0, 0, 0, null);
       bicycle2.setColor("black");
       System.out.println("Color: "+bicycle2.getColor());
       bicycle2.setSeatHeight(6);
       System.out.println("Seat Height: "+bicycle2.getSeatHeight());
       bicycle2.setSpeed(12);
       System.out.println("Speed: "+bicycle2.getSpeed());
       bicycle2.setGear(6);
       System.out.println("Gear: "+bicycle2.getGear());

       System.out.println("");//space

    }//end method
 }//end class

class 变量用于记录创建的 Bicycle class 实例的数量,测试人员 class 创建了多个 Bicycle class 并演示了 Bicycle class 和 class 变量的工作原理。我在网上找遍了,似乎找不到任何东西,请有人告诉我怎么做,在此先感谢:)

为什么不使用静态计数器?

public class Bicycle {

    private static int instanceCounter = 0;

    //instance variables
    public int gear, speed, seatHeight;
    public String color;

    //constructor
    public Bicycle(int gear, int speed, int seatHeight, String color) {
        gear = 0;
        speed = 0;
        seatHeight = 0;
        color ="Unknown";      
instanceCounter++;
    }

    public int countInstances(){
        return instanceCounter;
    }

........

由于 static 变量仅初始化一次,并且它们在所有实例之间共享,您可以:

class MyClass {

    private static int counter;

    public MyClass() {
        //...
        counter++;
    }

    public static int getNumOfInstances() {
        return counter;
    }
}

要访问静态字段 counter,您可以使用 MyClass.getNumOfInstances()

详细了解 JLS - 8.3.1.1. static Fields 中的 static 个字段:

If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized (§12.4).

请注意,counter 隐式设置为零

一种基本方法是声明一个静态数字成员字段,该字段在每次调用构造函数时递增。

public class Bicycle {

    //instance variables
    public int gear, speed, seatHeight;
    public String color;
    public static int bicycleCount = 0;

    //constructor
    public Bicycle(int gear, int speed, int seatHeight, String color) {
        gear = 0;
        speed = 0;
        seatHeight = 0;
        color ="Unknown";
        bicycleCount++;      
    }
    ...
  }

您只需要 class 中的静态计数器。

public class Bicycle {
    private static volatile int instanceCounter;

    public Bicycle() {
        instanceConter++; 
    }

    public static int getNumOfInstances() {
        return instanceCounter;
    }

    protected void finalize() {
        instanceCounter--;
    }
}

如许多评论中所述,不建议使用 finalize(),因此可能有另一种方法来计算 Bicycle 实例 -

public class Bicycle {

    private static final List<PhantomReference<Bicycle>> phantomReferences = new LinkedList<PhantomReference<Bicycle>>();
    private static final ReferenceQueue<Bicycle> referenceQueue = new ReferenceQueue<Bicycle>();
    private static final Object lock = new Object();
    private static volatile int counter;
    private static final Runnable referenceCleaner = new Runnable() {
        public void run() {
            while (true) {
                try {
                    cleanReferences();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    };

    static {
        Thread t = new Thread(referenceCleaner);
        t.setDaemon(true);
        t.start();
    }

    private Bicycle() {
    }

    public static Bicycle getNewBicycle() {
        Bicycle bicycle = new Bicycle();
        counter++;
        synchronized (lock) {
            phantomReferences.add(new PhantomReference<Bicycle>(new Bicycle(), referenceQueue));
        }
        System.out.println("Bicycle added to heap, count: " + counter);
        return bicycle;
    }

    private static void cleanReferences() {
        try {
            PhantomReference reference = (PhantomReference) referenceQueue.remove();
            counter--;
            synchronized (lock) {
                phantomReferences.remove(reference);
            }
            System.out.println("Bicycle removed from heap, count: " + counter);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static int getNumOfBicycles() {
        return counter;
    }
}

public class BicycleTest {

    public static void main(String[] args) {
        int i = 0;
        while (i++ < 1000) {
            Bicycle.getNewBicycle();
        }
        while (Bicycle.getNumOfBicycles() > 0) {
            try {
                Thread.sleep(1000);
                System.gc(); // just a request
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

此外,您应该覆盖 finalize 方法来递减计数器

public class Bicycle {
...
    public static int instances = 0;

    {
        ++instances; //separate counting from constructor
    }
...
    public Bicycle(int gear, int speed, int seatHeight, String color) {
        gear = 0;
        speed = 0;
        seatHeight = 0;
        color ="Unknown";
    }

    @Override
    protected void finalize() {
        super.finalize();
        --instances;
    }

}

您应该记住,静态变量是 CLASS 范围的(每个实例没有一个,每个 class 只有一个)

然后,您可以通过以下方式演示实例递减:

...
System.out.println("Count:" + Bicycle.getNumOfInstances()); // 2
bicycle1 = null;
bicycle2 = null;
System.gc(); // not guaranteed to collect but it will in this case
Thread.sleep(2000); // you expect to check again after some time
System.out.println("Count again:" + Bicycle.getNumOfInstances()); // 0

请试用java

的工具
jmap -histo <PDID>

输出

     num     #instances         #bytes  class name
----------------------------------------------
   1:       1105141       97252408  java.lang.reflect.Method
   2:       3603562       86485488  java.lang.Double
   3:       1191098       28586352  java.lang.String
   4:        191694       27035744  [C

或者,您可以创建一个带有 initializer block 和静态变量的计数器。

class SomeClass
{
    private static int instanceCounter;
    {
         instanceCounter++;
    }
}

初始化程序块被编译器复制到每个构造函数中,因此,无论您需要多少个构造函数,您都必须编写一次(如上文所述 link)。每次您创建 class 的新对象并将变量计数器加一时,{} 中的块就会运行。 当然,通过以下方式获得计数器:

public static int getInstanceCounter()
{
    return instanceCounter;
}

或直接

int numOfInstances = SomeClass.instanceCounter;

如果您不将 numOfInstances 设为私有

public class Number_Objects {

    static int count=0;
    Number_Objects(){
        count++;
    }

    public static void main(String[] args) {

        Number_Objects ob1=new Number_Objects();
        Number_Objects ob2=new Number_Objects();
        Number_Objects obj3=new Number_Objects();
        System.out.print("Number of objects created :"+count);
    }

}

如果你想根据创建的对象数量来统计和测试实例,你可以使用一个循环来查看到底发生了什么。创建构造函数并使用静态计数器

public class CountInstances {
public static int count;
public CountInstances() {
    count++;
}
public int getInstaces() {
    return count;
}
public static void main(String []args) {
    for(int i= 0; i<10; i++) {  
        new CountInstances();
    }       
    System.out.println(CountInstances.count);
  } 
}