Как подсчитать количество экземпляров класса

Может ли кто-нибудь сказать мне, как подсчитать количество экземпляров класса?

Вот мой код

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

Переменная класса должна использоваться для подсчета количества созданных экземпляров класса Bicycle, а класс тестировщика создает несколько экземпляров класса Bicycle и демонстрирует работу класса Bicycle и переменной класса. Я облазил весь интернет и ничего не нашел, может кто-нибудь показать мне, как это сделать, пожалуйста, заранее спасибо :)


person RifferRaffers    schedule 09.03.2015    source источник
comment
Просмотрите поля static (т. е. в пределах класса).   -  person Mena    schedule 09.03.2015
comment
Эта переменная подкласса на самом деле ничего не делает. Похоже, вы ищете структуру данных для отслеживания экземпляров вашего класса. Это может быть что-то, что находится за пределами вашего класса, например коллекция объектов в Java. Для этой цели также можно использовать статические переменные класса.   -  person JNYRanger    schedule 09.03.2015


Ответы (9)


Поскольку переменные static инициализируются только один раз и используются всеми экземплярами, вы можете:

class MyClass {

    private static int counter;

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

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

Подробнее о полях static читайте в . JLS — 8.3.1.1. статические поля:

Если поле объявлено как static, существует ровно одно воплощение поля, независимо от того, сколько экземпляров (возможно, ноль) класса может быть создано в конечном итоге. Поле static, иногда называемое переменной класса, воплощается при инициализации класса (§12.4).

Обратите внимание, что counter неявно устанавливается равным нулю

person Maroun    schedule 09.03.2015
comment
Лучше сделать getNumOfInstances() static. - person John Bollinger; 09.03.2015
comment
а как насчет сбора мусора? - person Math Machine; 22.02.2021

Пожалуйста, попробуйте инструмент 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
person Lee Tuấn    schedule 12.10.2017

Кроме того, вы должны переопределить метод 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 (нет одной для каждого экземпляра, только одна для каждого класса)

Затем вы можете продемонстрировать уменьшение экземпляра с помощью:

...
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
person Danilo Gomes    schedule 09.03.2015
comment
Фу. НИКОГДА не переопределяйте finalize(), если вы можете этого избежать. Возможно, в этом простом контексте это не слишком вредно, но вам действительно не следует развивать эту привычку. Обратите внимание, что в этом случае есть альтернатива, включающая фантомные ссылки (которая намного сложнее, чем я полагаю). Заметьте также, что объект может жить после вызова его метода finalize(), поэтому использование finalize() таким образом даже не гарантирует работу. - person John Bollinger; 09.03.2015

почему бы не использовать статический счетчик?

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;
    }

........
person Matteo Rubini    schedule 09.03.2015
comment
Метод countInstances() более подходил бы static. - person John Bollinger; 09.03.2015
comment
в зависимости от философии вашего приложения - person Matteo Rubini; 09.03.2015
comment
Количество экземпляров является свойством класса, а не какого-либо конкретного экземпляра, независимо от того, как вы пишете имя метода доступа. Следовательно, этот метод доступа должен быть методом класса. Это вопрос согласованности дизайна. На практике это позволяет вам определить, сколько экземпляров было создано, не имея ни одного на руках. С его помощью в качестве метода экземпляра я могу быть вынужден сделать следующее: int numInstances = new Bicycle().countInstances() - 1;. Это уродство возникает из-за неправильного дизайна. - person John Bollinger; 09.03.2015
comment
Метод countInstances() должен быть определен как статический. @JohnBollinger в самый раз. - person ardarda; 28.01.2020

Вам просто нужен статический счетчик в классе.

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();
            }
        }
    }
}
person hemant1900    schedule 09.03.2015
comment
Нет нет нет! Не переопределять finalize(). Не. Не развивайте привычку, не рекомендуйте ее другим, не пропускайте ее в код-ревью. Это может иметь вредные последствия (например, объекты живут дольше, чем они могли бы в противном случае), и, как правило, не гарантируется поведение, которое вы, вероятно, ожидаете. - person John Bollinger; 09.03.2015
comment
Соглашаться!. Хотя я думаю, что использовать finalize() в данном конкретном случае не так уж и вредно, но да, вы правы, это не рекомендуемое решение. Поэтому я изменил свой ответ другим подходом к подсчету экземпляров. - person hemant1900; 11.03.2015

Кроме того, вы можете создать счетчик с помощью блока инициализации и статическая переменная.

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

Блоки инициализатора копируются компилятором в каждый конструктор, поэтому вам придется написать его один раз, независимо от того, сколько конструкторов вам понадобится (как указано в приведенной выше ссылке). Блок в {} запускается каждый раз, когда вы создаете новый объект класса, и увеличивает счетчик переменной на единицу. И, конечно же, получите счетчик примерно так:

public static int getInstanceCounter()
{
    return instanceCounter;
}

или напрямую

int numOfInstances = SomeClass.instanceCounter;

Если вы не сделаете numOfInstances приватным

person Alexandros    schedule 02.06.2018

Один из основных подходов заключается в объявлении статического числового поля-члена, которое увеличивается при каждом вызове конструктора.

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++;      
    }
    ...
  }
person Amir Afghani    schedule 09.03.2015

Если вы хотите подсчитать и протестировать экземпляры на основе количества созданных объектов, вы можете использовать цикл, чтобы увидеть, что происходит на самом деле. Создайте конструктор и используйте статический счетчик

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);
  } 
}
person karto    schedule 21.09.2020

person    schedule
comment
Хотя это может ответить на вопрос авторов, в нем отсутствуют поясняющие слова и ссылки на документацию. Необработанные фрагменты кода не очень полезны без фраз вокруг них. Вы также можете найти очень полезным как написать хороший ответ. Пожалуйста, отредактируйте свой ответ. - person hellow; 27.09.2018