Count Number of Objects in Java - java

I am creating a program called Humans and Pets. The program simply prints out a list of Human's names (in this case I have created 4) and their corresponding pets. Here is the code:
AmazingPets.java
public class AmazingPets {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
System.out.println("Welcome to Pets and Humans! Created By Marc B.\n____________________________\n");
Dogs firstDog = new Dogs("Ghost");
Humans firstName = new Humans("Alex");
Dogs secondDog = new Dogs("Paperbag");
Humans secondName = new Humans("Michael");
Cats firstCat = new Cats("Tom");
Cats secondCat = new Cats("Mr Furball");
Humans thirdName = new Humans("Bryan");
Humans fourthName = new Humans("Julie");
System.out.printf("%s's dog's name is %s.\n", firstName.getHumanName(), firstDog.getDogName());
System.out.printf("%s's dog's name is %s.\n", secondName.getHumanName(), secondDog.getDogName());
System.out.printf("%s's cat's name is %s.\n", thirdName.getHumanName(), firstCat.getCatName());
System.out.printf("%s's cat's name is %s.\n", fourthName.getHumanName(), secondCat.getCatName());
}
}
Humans.java
public class Humans {
private String mHumanName;
public Humans(String humanName) {
mHumanName = humanName;
}
public String getHumanName() {
return mHumanName;
}
}
I would like to create a class method called populationCount for Humans that would return the total number of Humans instances created. I would then like to output the result (using a Scanner in AmazingPets.java) to have the number of counts in the console.
Can anyone please suggest possible ways to return the total number of Humans made? as I cannot seem to find any resources online. Thank you in advance. :)

You can use this abstract class, in order to count any type of objects that inherits it. The answer is based on addy2012's answer (Thanks!):
public abstract class Countable
{
private static final Map<Class<?>, Integer> sTotalCounts = new HashMap<>();
public Map<Class<?>, Integer> getCountsMap() {
return sTotalCounts;
}
public int getTotalCount()
{
return sTotalCounts.get(this.getClass());
}
public Countable()
{
int count = 0;
//Add if it does not exist.
if(sTotalCounts.containsKey(this.getClass()))
{
count = sTotalCounts.get(this.getClass());
}
sTotalCounts.put(this.getClass(), ++count);
}
}
Then, you can do:
public class Dogs extends Countable {/**/}
public class Cats extends Countable {/**/}
public class Humans extends Countable {/**/}
Then, you can instantiate any of your objects
Dogs dog = new Dogs("...");
Dogs dog2 = new Dogs("...");
Cats cat = new Cats("...");
Humans human = new Humans("...");
You can then get each total count by invoking the getTotalCount method from an instance:
System.out.println(dog.getTotalCount());
System.out.println(cat.getTotalCount());
System.out.println(human.getTotalCount());
Which will give you
2
1
1
Important Notes:
1) getTotalCount() is invoked via instances (non-static). This might be strange semantically, as you have a method returning a result for a total of instances, so any modification on this would be nice.
2) In order to allow the count on different types, map get & put operations are applied. Those operations have their own complexities and might be costly at cases. For more information on this, look in this answer.

Create a static field private static int humanCount = 0 and increment it in the constructor:
public class Humans {
private String mHumanName;
private static int humanCount = 0;
public Humans(String humanName) {
mHumanName = humanName;
humanCount++;
}
public String getHumanName() {
return mHumanName;
}
public static int populationCount() {
return humanCount;
}
}
You can add a finalize() method and use it to decrement the count. It will be called when the object is destroyed.
protected void finalize( ) throws Throwable {
humanCount--;
super.finalize();
}

Related

Java OOP; creating array of objects

I'd like to create an array of objects where 3 objects are from one class, and a 4th is from second class.
In the first class I did the following:
public class Pupil {
public int n= 0;
Pupil(int n) {
this.n = n;}
}
in the second class I did the following:
public class Tutor {
public int m= 0;
Tutor(int m) {
this.m = m;}
}
In the main class, I created several pupil objects and one tutor object, like this:
public class Main {
public static void main (String[] args) {
//Pupil(n) while for tutor objects it'd be Tutor(m)
Pupil pupil1 = new Pupil(9);
Pupil pupil2 = new Pupil(8);
Pupil pupil3 = new Pupil(6);
Tutor tutor1 = new Tutor(2);
Using objects for printing in main works fine.
But I'd like to create a fourth class where I group them into arrays of objects, but it won't see the objects that I created to create groups out of them. I'm also not sure about the format for creating an array of objects.
public class Groups {
public static void main(String [] args){
Pupil [] g1 = {tutor1, pupil1, pupil2, pupil3};
//cannot resolve any symbols
}
}
EDIT: according to my tutor the groups class should be static to solve this, but I'm not sure how to actually code this?
Edit2: an answer pointed that the array should be Object as the above code would only be able to create an array of pupils, not pupils and tutors objects.
Object [] g1 = {tutor1, pupil1, pupil2, pupil3};
but that still doesn't solve the main issue where no objects are seen from the groups class (//cannot resolve any symbols)
Arrays can only contain the same type of object. With that being said, here is a way:
Object[] g1 = {tutor1, pupil1, pupil2, pupil3};
Java is a strongly typed programming language so you cannot add different type objects to a same collection. But you take advantage of OPP polymorphism principle. You can create a parent class and extend your subclasses from parent class.
Parent Class
public class Group {
}
Child Classes
public class Pupil extends Group {
public int m = 0;
public Pupil(int m) {
this.m = m;
}
}
public class Tutor extends Group {
public int n = 0;
public Tutor(int n) {
this.n = n;
}
}
So this way you can use it as follows:
public class TestSchool {
public static void main(String[] args) {
Pupil pupil1 = new Pupil(9);
Pupil pupil2 = new Pupil(8);
Pupil pupil3 = new Pupil(6);
Tutor tutor1 = new Tutor(2);
Tutor tutor2 = new Tutor(2);
Group[] groupArray = {pupil1, pupil2, pupil3, tutor1, tutor2};
}
}

Check if a list of Enums contains a String in Java

I have a list of objects with one attribute type. I want to filter that list to contain only those objects whose value is in the list of Enum.
Here is a simple version of Java Program describing above.
public enum Types {SLOW("Slow"), FAST("Fast"), VERY_FAST("Running");}
List<Types> playerTypes = new ArrayList<>();
playerTypes.add(Types.SLOW);
List<Player> myPlayers = new ArrayList<>();
Player player = new Player("FAST");
myPlayers.add(player);
for (Player p : myPlayers) {
if(playerTypes.contains(p.getType())) {
System.out.println("Player type is : " + p.getType());
}
}
I want to retain only those items in the players List which are part of enum list. Above does not seem to work. Please suggest a way to achieve this. I am doing this in Java 8.
According to me, there are two ways:
*Instead of creating the list of player types with enums, use enum names:
public enum Types {
SLOW("Slow"), FAST("Fast"), VERY_FAST("Running");
}
List<String> playerTypes = new ArrayList<>();
playerTypes.add(Types.SLOW.name());
List<Player> myPlayers = new ArrayList<>();
Player player = new Player("FAST");
myPlayers.add(player);
for (Player p : myPlayers) {
if(playerTypes.contains(p.getType())) {
System.out.println("Player type is : " + p.getType());
}
}
*You can use the valueOf method of the enum class to convert the string obtained from p.getType() into an Enum:
public enum Types {
SLOW("Slow"), FAST("Fast"), VERY_FAST("Running");
}
List<Types> playerTypes = new ArrayList<>();
playerTypes.add(Types.SLOW);
List<Player> myPlayers = new ArrayList<>();
Player player = new Player("FAST");
myPlayers.add(player);
for (Player p : myPlayers) {
if(playerTypes.contains(Types.valueOf(p.getType()))) {
System.out.println("Player type is : " + p.getType());
}
}
You enum doesn't even compile. Once you've got a minimal complete example that otherwise works, you just need to use Collections.removeIf.
import java.util.*;
import java.util.stream.*;
enum PlayerType {
SLOW, FAST, VERY_FAST
}
class Player {
private final PlayerType type;
public Player(PlayerType type) {
this.type = type;
}
public PlayerType type() {
return type;
}
#Override public String toString() {
return type.name();
}
}
interface Play {
static void main(String[] args) {
Set<PlayerType> playerTypes = EnumSet.of(
PlayerType.SLOW
);
List<Player> myPlayers = new ArrayList<>(Arrays.asList(
new Player(PlayerType.FAST)
));
myPlayers.removeIf(player -> !playerTypes.contains(player.type()));
System.err.println(myPlayers);
}
}
Update: Original poster has said Player stores type in a String (for whatever reason). So that'll need to be looked up to the enum type (or just use a Set<String> playerTypes).
myPlayers.removeIf(player ->
!playerTypes.contains(PlayerType.valueOf(player.type()))
);
If you want to find if an Enum has a String, I would add a Hashmap to our Enum and add our value as a key. This way, I can do a simple get and check if it exists.
public enum PlayerSpeed {
// Type of speeds.
SLOW("Slow"),
FAST("Fast"),
VERY_FAST("Running");
// String value that represents each type of speed.
public final String value;
// Hash map that let us get a speed type by it's String value.
private static Map map = new HashMap<>();
// Private constructor.
private PlayerSpeed(String value) { this.value = value; }
// Fill our hash map.
static {
for (PlayerSpeed playerSpeed : PlayerSpeed.values()) {
map.put(playerSpeed.value, playerSpeed);
}
}
/**
* Given a string, look it up in our enum map and check if it exists.
* #param searchedString String that we are looking for.
* #return True if the string is found.
*/
public static boolean containsString(String searchedString) {
return map.get(searchedString) != null;
}
}
Then, all you would need to do is check if the String exists using the containsString method of our Enum.
Player player = new Player("FAST");
if(PlayerSpeed.constainsString(p.getType())) {
System.out.println("Player type is : " + p.getType());
}
I already tried this code and it is working like intended. Please let me know if it helps.

How to return count for every class's count and not of every class's instance count

I've got:
interface - ISpacecraft
abstract class - Spacecraft (implements the interface above)
Classes - 4 Kind of ships (derived children of Spacecraft)
Task: Return the count of every ship, if I have 2 cargoShips, then return 2.
Problem: When I iterate through the ArrayList It prints '2' twice, because I have 2 cargoShips.
Expected output: 2,1,1,2
Current output: 2,2,1,1,2,2
Question: How can I iterate through the number of types of ships, instead of all instances of them?
Note: I can't change the signature of 'printInstanceNumberPerClass'.
Code:
StarFleetManagerTester
public static void printInstanceNumberPerClass (ArrayList<ISpacecraft> fleet)
{
ArrayList<ISpacecraft> objects = new ArrayList<>(fleet);
ArrayList<Integer> cnt = new ArrayList<Integer>();
for(ISpacecraft obj : objects)
{
cnt.add(obj.getCount());
}
for(ISpacecraft obj : objects)
System.out.println(obj.getCount() +" "+obj.getName());
}
Spacecraft
protected static int countCruiser;
ISpacecraft
int getCount();
cargoShip, ReserarchShip, etc..
private static int count
#Override
public int getCount() {
return this.count;
}
You could define a String member called typeName like this
protected String typeName;
public String getTypeName() {
return typeName;
}
into your abstract class and define the member in child class constructors like this
typeName = "Some Particular Type";
Now, you need a static Map for your abstract class:
public static Map<String, int> typeCounts;
and in your constructor of the abstract class do something like this:
if (typeCounts == null) {
typeCounts = new HashMap<String, int>();
}
if (typeCounts.get(getTypeName()) === null) {
typeCounts.put(getTypeName(), 1);
} else {
typeCounts.put(getTypeName(), typeCounts.get(getTypeName()) + 1);
}
Finally you will need to iterate typeCounts and use the keys and values for your output.

I need a way to randomize outcomes passing and holding classes

I'm trying to add let's say 5 classes that they all extend a General class and implements an init() method in a different way.
What I need is a way to store those classes while passing a number of chances for that Class to "happen"
For this I created a Class holder:
public class ClassHolder {
private Class<? extends GeneralOutcome> holdClass;
private int chances;
public ClassHolder(Class<? extends GeneralOutcome> holdClass, int chances) {
super();
this.holdClass = holdClass;
this.chances = chances;
}
public Class<? extends GeneralOutcome> getHoldClass() {
return holdClass;
}
public void setHoldClass(Class<? extends GeneralOutcome> holdClass) {
this.holdClass = holdClass;
}
public int getChances() {
return chances;
}
public void setChances(int chances) {
this.chances = chances;
}
}
Also a GeneralOutcome class that the ones that will be added to a list will extend:
public class GeneralOutcome {
public void init(String text, int times) {
}
}
And the way I'm adding them to a list:
public class Randomizer {
private static List<ClassHolder> myList = new ArrayList<ClassHolder>();
private static ClassHolder outcome01 = new ClassHolder(Outcome01.class, 10);
private static ClassHolder outcome02 = new ClassHolder(Outcome02.class, 10);
private static ClassHolder outcome03 = new ClassHolder(Outcome03.class, 10);
private static ClassHolder outcome04 = new ClassHolder(Outcome04.class, 10);
private static ClassHolder outcome05 = new ClassHolder(Outcome05.class, 10);
public static void main(String[] args) {
for(int i = 0; i < outcome01.getChances(); i++) {
myList.add(outcome01);
}
for(int i = 0; i < outcome02.getChances(); i++) {
myList.add(outcome02);
}
for(int i = 0; i < outcome03.getChances(); i++) {
myList.add(outcome03);
}
for(int i = 0; i < outcome04.getChances(); i++) {
myList.add(outcome04);
}
for(int i = 0; i < outcome05.getChances(); i++) {
myList.add(outcome05);
}
System.out.println(myList.size());
int rand = (int) (Math.random() * myList.size());
System.out.println(rand);
ClassHolder theHoldClass = myList.get(rand);
System.out.println(theHoldClass.getHoldClass());
Class<? extends GeneralOutcome> theOutcome = theHoldClass.getHoldClass();
theOutcome.init();
}
}
The problem is that I'm not able (Don't know how really) cast back to GeneralOutcome to I can access the .init() method.
I get The method init() is undefined for the type Class<capture#3-of ? extends GeneralOutcome>
I know this isn't the best way to do this. So I'm open to both, a fix for this and also what would be a better way to achieve something like this.
What you are trying to do here doesn't work for some reasons.
First of all, your init method isn't static. So that call
Class<? extends GeneralOutcome> theOutcome = theHoldClass.getHoldClass();
theOutcome.init();
leads directly to a compile-time error.
But then, the whole design looks strange. What is the point of holding Class objects in the first place?
Why don't you create an interface
public interface OutcomeFunctionality {
public void foo(String text, int times);
}
to later instantiate objects of whatever class implementing that interface? So that you can finally can deal with lists of such objects (together with those probabilities)?
[ I used the name foo on purpose: alone the strange name "init" makes it very unclear what your code is intended to do! In that sense you should rethink your design, and find better method names to express what those methods will be doing! ]
Long story short: using/holding Class objects doesn't buy you anything in your example code - it only adds complexity. So my advise is: start working there and get rid of that "detour". You might also want to read about the Open/Closed principle - that could give you some guidance how a good OO design looks like that uses abstract classes / subclassing in order to split "behavior" between base and derived classes.

Deep Copy of Object Array Instance, Java

I have an object made in my main Recipe recipeOne = new Recipe("Pepperoni Pizza");
This object is an instance of this Object Array defined and constructed here!
public class Recipe implements Cloneable{
String Name;
final int INGREDIENT_ARRAY_MAX = 10;
Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];
public Recipe(String name){
Name = name;
}
So I am looking to make a deep copy of this object with the line Recipe ressippi = (Recipe) recipe.clone(); and it sends me here!
public Object clone(){
Recipe cloneRec = new Recipe(Name);
return cloneRec;
}
I know this is currently a shallow copy because the method only passes references, so if I was to attempt a name change on my new Object that was a clone of recipeOne...it would change both of their names. Obviously I do not want that, I'm fairly lost on this, can anyone help?
EDIT:#Rohit Jain
Both my Recipe class as well as my Ingredient class (the objects the recipe array holds) have toString methods and recipes calls on ingredients in order to print it all out in a nice little format. When I call it on my "recipeOne" object (the one called pepperoni pizza) i get "Pepperoni Pizza: 1.0 Pounds of Dough, 8.0 Ounces of Sauce, 10.0 Ounces of Cheese"
Then I proceed to make the object ressippi and set that to the clone of recipeOne, so all good from here...then I change ressippi's name to "Pineapple Pizza" and that prints out fine but it doesnt print the 3 ingredient objects that recipeOne stored, which it is suppose to do!
Add a copy constructor to the recipe class, which creates a new instance of recipe and copies all of the fields from an original recipe.
Recipe.java
public class Recipe implements Cloneable {
String name;
final int INGREDIENT_ARRAY_MAX = 10;
Ingredient[] ingredients = new Ingredient[INGREDIENT_ARRAY_MAX];
public Recipe(String name) {
this.name = name;
}
//Copy Constructor
private Recipe(Recipe recipe){
this.name = recipe.name;
for(int x = 0; x < recipe.ingredients.length; x++){
this.ingredients[x] = recipe.ingredients[x];
}
}
public static Recipe newInstance(Recipe recipe){
return new Recipe(recipe);
}
//Debug Method
public static void printRecipe(Recipe recipe){
System.out.println("Recipe: " + recipe.name);
for(Ingredient i:recipe.ingredients){
if(i != null && i.getName() != null){
System.out.println("Ingredient: " + i.getName());
}
}
}
//Test Method
public static void main(String[] args) {
Recipe recipe = new Recipe("Chicken Soup");
recipe.ingredients[0] = new Ingredient("Chicken");
recipe.ingredients[1] = new Ingredient("Broth");
Recipe copy = new Recipe(recipe);
copy.ingredients[2] = new Ingredient("Rice");
copy.name = "Chicken Rice Soup";
printRecipe(recipe);
printRecipe(copy);
System.out.println(recipe == copy);
System.out.println(recipe.ingredients == copy.ingredients);
}
}
Ingredient.java
public class Ingredient {
private String name;
public Ingredient(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
As you have found out, implementing the Cloneable doesn't actually clone the object. You'll have to implement the clone() method sensibly, and if you want a deep copy, that's what you should implement.
Now, creating a new Recipe object with the same Name attribute is quite OK. And changing the name for the new object afterwards is also quite okay, it won't change the name of the first object as java String's are immutable.
You may want to have a look at the commons-beanutils package, which provides handy code for cloning objects.
Finally, as for "...only passes references..." you should read eg. this and this thread.
Cheers,
Serialize it! Take a look at the deepClone function as exampled here: http://www.avajava.com/tutorials/lessons/how-do-i-perform-a-deep-clone-using-serializable.html
The other replies on Strings being immutable are true of course, but the problem you tried to describe with the String example was just a bad example; complexer objects like the Ingredients array still is copied-by-reference.
Also: change the name of your array so that it doesn't match the class name (=confusing):
Ingredient Recipe[] = new Ingredient[INGREDIENT_ARRAY_MAX];

Categories

Resources