Im new to java and I am super confused on how you format arrays to hold objects, specifically with multiple data types. I am trying to make an array called myMonsters that essentially holds a bunch of other monsters, which is a string and an integer. 1, I really don't understand how to put objects into an array. 2, I don't get why the array are under one class name instead of another.
What I mean -->
private Monster[] myMonsters;
private int s;
public Monsters(int size)
{
s = size;
myMonsters = new Monster[s];
}
public void add(int spot, Monsters m)
{
myMonsters[spot] = m;
}
This creates the array that holds the monster objects. I don't understand why I would create the array under Monster. Doesn't it make more sense to create it under the Monsters class, where the monster objects are being held?
private int weight;
private int height;
private int age;
public Monster( int a, int h, int w )
{
age = a;
height = h;
weight = w;
}
And of course this creates the objects.
I can tell how poorly formatted this questions is but can you still help me with this?
A class is a template, like a cookie-cutter for making cookies. A class has no content, just as a cookie-cutter has no cookie dough.
A cookie-cutter exists only to make delicious cookies. A class exists only to make useful objects (a.k.a. instances). Objects have content inside, just as cookies have dough inside.
Monster is the class, the cookie-cutter, for making various monster objects.
In Java 16 and later, we can more briefly define a class as a record. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.
package work.basil.example.animalkingdom.cookies;
public record Monster(String name , int weight)
{
}
As a conventional class, that would be:
package work.basil.example.animalkingdom.cookies;
import java.util.Objects;
public final class Monster
{
private final String name;
private final int weight;
public Monster ( String name , int weight )
{
this.name = name;
this.weight = weight;
}
public String name ( ) { return name; }
public int weight ( ) { return weight; }
#Override
public boolean equals ( Object obj )
{
if ( obj == this ) return true;
if ( obj == null || obj.getClass() != this.getClass() ) return false;
var that = ( Monster ) obj;
return Objects.equals( this.name , that.name ) &&
this.weight == that.weight;
}
#Override
public int hashCode ( )
{
return Objects.hash( name , weight );
}
#Override
public String toString ( )
{
return "Monster[" +
"name=" + name + ", " +
"weight=" + weight + ']';
}
}
Let's cut some cookies using that cookie-cutter. We want to represent 3 monsters, each with a different name and different weight.
Monster x = new Monster( "Alice" , 42 );
Monster y = new Monster( "Bob" , 77 );
Monster z = new Monster( "Carol" , 58 );
There we have three separate objects, each cut from the same Monster class. We are currently handling the 3 monsters separately, each assigned to separate variables.
If we want to track those monsters together, in a particular order, we do not need your Monsters class. Just use an array.
Say we want them organized together by weight.
Monster[] monstersByWeight = new Monster[ 3 ];
monstersByWeight[ 0 ] = x;
monstersByWeight[ 1 ] = z;
monstersByWeight[ 2 ] = y;
The Monster[] says we want this variable named monstersByWeight to hold an array that holds Monster objects. The new Monster[ 3 ] creates such an array, an array with three empty slots. The = puts that array of three empty slots into the variable named monstersByWeight so we can use it later.
Dump that array to the console, to inspect.
String output = Arrays.toString( monstersByWeight );
System.out.println( "output = " + output );
output = [Monster[name=Alice, weight=42], Monster[name=Carol, weight=58], Monster[name=Bob, weight=77]]
You said:
… to hold objects, specifically with multiple data types
There is only one data type involved here: Monster. We have only Monster objects to track. So the data type of the array named monstersByWeight is Monster.
If we want to add another Monster object:
Monster david = new Monster( "David" , 63 ) ;
…to our array, we need to open up a slot. Using arrays, this is tedious programming. Likely we would create another array, move elements from old array to new array while skipping the slot we want to keep open for our new Monster. Not fun writing that code.
Fortunately, that code has already been written. We can use the class ArrayList. This class implementing the List interface. ArrayList can do all the element-insertion work for us.
List< Monster > monstersByWeight = new ArrayList<>() ;
The List< Monster > monstersByWeight says we want a list that holds Monster objects. The new ArrayList<>() instantiates such a list, of a default size.
Next we add our Monster objects.
monstersByWeight.add( x ) ;
monstersByWeight.add( z ) ;
monstersByWeight.add( y ) ;
Dump to console.
System.out.println( monstersByWeight ) ;
[Monster[name=Alice, weight=42], Monster[name=Carol, weight=58], Monster[name=Bob, weight=77]]
Later we can insert our new Monster object named David, assigned to variable named david. At weight of 63, this new monster belongs before the one named Bob but after the one named Carol. Like arrays, the List interface uses annoying zero-based counting rather than ordinal counting. To specify the 3rd element, we say 2 (annoying, as I said).
monstersByWeight.add( 2 , david ) ;
Dump to console.
System.out.println( monstersByWeight ) ;
[Monster[name=Alice, weight=42], Monster[name=Carol, weight=58], Monster[name=David, weight=63], Monster[name=Bob, weight=77]]
You asked:
This creates the array that holds the monster objects. I don't understand why I would create the array under Monster. Doesn't it make more sense to create it under the Monsters class, where the monster objects are being held?
No, you would not want a collection of Monster objects stored within the class of Monster. The job of the Monster class is to define the state (data) and behavior (methods) for any one Monster object (instance) that represents any one real-world monster.
You want a separate class to track a bunch of Monster objects together. Here in this Answer we used an instance of the ArrayList class which we named monstersByWeight to track our group of monsters. You could just as well have written your own MonsterList class if you wanted to do all that array-rearranging yourself, as practice. But for real work, use ArrayList.
The principal at work here is called separation of concerns. The ArrayList class knows nothing of what it means to be a Monster. And the Monster class knows nothing of how to group together Monster objects. Following this principal leads to clean, well-organized code that is easier to read, comprehend, and maintain.
Related
I am using java.lang.instrument package to get the memory size of java object (can be nested ).
I am using below to get Object Size :
import java.lang.instrument.Instrumentation;
public class ObjectSizeFetcher {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}
public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
}
I have Person class having below fields :
private String name ;
private int age;
private Addresses addresses [] ;
Now need size of below person Object :
Person person = new Person();
person.setName("aa");
person.setAge(11);
Addresses addresses [] = new Addresses[2000];
for(int i = 0 ; i < 1000 ; i ++){
addresses[i] = new Addresses();
addresses[i].setAddress1("dadadadafasfasf"+i);
addresses[i].setAddress2("dadadadafasfasfdasdsadsd"+i);
}
person.setAddresses(addresses);
System.out.println("size : " + ObjectSizeFetcher.getObjectSize(person));
Now after executing this, I am getting output as :
size : 24
Issue is If i am iterating this loop 10 times, or 1000 times, or 100000 times, i am getting Size as 24.
I am expected that person object memory size should increase if number of times loop increased as person object is having more addresses.
Why java.lang.instrument.Instrumentation is not giving correct results ?
Simply said: an object consist of it's own fields. But if these fields are objects themselves, they consist simply of the reference to those other objects. So your array is an object, and only the reference to that array is included. The size doesn't contain the whole object tree of what an object exists of, in other words.
Arrays are objects itself and you're declaring only one array.
Addresses addresses [] = new Addresses[2000]; //the single array instance
for(int i = 0 ; i < 1000 ; i ++){
addresses[i] = new Addresses();
addresses[i].setAddress1("dadadadafasfasf"+i);
addresses[i].setAddress2("dadadadafasfasfdasdsadsd"+i);
}
and populate it with address records. So your arrray pointing the same area in memory, it is still the same reference. The only difference made is that you're createing new Addresses instances and fill your memory outside the class in which array addresses[] declared. For further explanation;
Before: addresses[] ----> 0x0000f -> {}
After: addresses[] ----> 0x0000f ->{address1, address2, ..., address1000}
So your reference for addresses[] stays the same, it keeps pointing the same area. It's only the reference and not the array itself.
I'm working on a project for my data structures class and I've been having a hard time wrapping my head around Abstract class inheritance and how it can be manipulated through subclasses, object comparison, method args, etc. I've been reading through Stack Overflow posts and Java tutorials, and while I've learned a ton, I'm still not understanding some things. I haven't coded in Java in 2+ years and have been using mostly C lately so I'm feeling very rusty and overwhelmed.
Project Overview
I was asked to build a database of sorts that represents data for my university students and professors. I have an abstract superclass, Person, which has 2 child classes Student and Instructor. Lastly (the class I'm currently working on), is a class called UniversityPeople which references an array of Student[] objects as well as an array of Instructor[] objects. The UniversityPeople class has methods to add(), delete(), search(), validate data, ect. for the 2 object arrays.
I know this implementation seems really strange, but I have to follow the instructions unfortunately. I've tried to make the methods work with both arrays seamlessly which is partially where I'm getting confused. Here are my questions:
1.) This is kind of a general question, but one I feel is important to understanding inheritance. I've done tons of reading on this, but I'm still pretty confused. If I create an object that uses the type of the superclass but is a subclass object, like: Person newStudent = new Student(), will this object have access to the methods in it's own class, or is it restricted to the superclass methods only? My understanding was, if the superclass is abstract, the children still inherit their methods when instantiated in this way.
2.) I don't understand how to differentiate between the two object arrays in the methods. For example, I'm writing a clear() function that sets the specified object array(Student[] or Instructor[]) to null when called. I first tried using the instanceOf method to test what type the array was but the compiler warned me I couldn't cast type Student to Person or something like that. Here is the constructor for the class as well as the clear function I'm having trouble with. I'm not sure if I'm understanding how inheritance fully works here, so if there's a better way please enlighten me:
Constructor:
//Global declarations
//Declares arrays of student and instructor classes
private Student[] studentArray;
private Instructor[] instArray;
private int studentCount;
private int instCount;
/*
checks user input. If user enters 1, create student array.
if user enters 2, create Instructor array
*/
public UniversityPeople(int type, int size)
{
if (type == 1)
{
studentArray = new Student[size];
}
else if (type == 2)
{
instArray = new Instructor[size];
}
}
Separate insert methods for students/instructors because I couldn't figure out a way to do 1, if it's even possible:
/*
checks if array is full or duplcate id exists.
If not, new Student object is created and
inserted into the student array
*/
public void insertStudent(String lastName, String firstName, int id,
int age, String yearStanding, double GPA)
{
boolean checkFull = isFull();
boolean checkId = containsID(studentArray, id);
if (checkFull)
{
System.out.println("Array is full. Please delete a data member.");
}
else if (checkId)
{
System.out.println("Duplicate ID. Please check data and re-enter.");
}
if (!checkFull && !checkId)
{
Student newStudent = new Student(lastName, firstName, id, age, yearStanding, GPA);
newStudent = studentArray[studentCount];
studentCount++;
}
else
System.err.println("There was an error while attempting to \n" +
"process your request. Please check your \n" +
"data entry and try again.");
}//end insertStudent
/*
checks if array is full or duplicate id exists.
If not, new Instructor object is created and
inserted into instructor array
*/
public void insertInstructor (String lastName, String firstName, int id,
int age, int officeNum, String subjectTaught)
{
boolean checkFull = isFull();
boolean checkId = containsID(instArray, id);
if (checkFull)
{
System.out.println("Array is full. Please delete a data member.");
}
else if (checkId)
{
System.out.println("Duplicate ID. Please check data and re-enter.");
}
if (!checkFull && !checkId)
{
Instructor newInstructor =
new Instructor(lastName, firstName, id, age, officeNum, subjectTaught);
newInstructor = instArray[instCount];
instCount++;
}
else
System.err.println("There was an error while attempting to \n" +
"process your request. Please check your \n" +
"data entry and try again.");
}//end insertInstructor
Lastly, a method to find someone in the array from their id and a method to clear whatever array is specified. I've made the arg type Person[] array in most of these methods which I hope is acceptable.
public int findPerson(Person[] array, int id)
{
for (int i = 0; i < array.length; i++)
{
if (array[i].getId() == id)
{
return i;
}
}
return -1;
}
//Sets specified array to null. I need to reset the count of objects in
//the specified array to 0, but i'm really confused about how that works. Below is the best
//understanding I could come up with
public void clear(Person[] array)
{
for (int i = 0; i < array.length; i++)
{
array[i] = null;
}
if (array.getClass().equals(Student.class))
{
studentCount = 0;
}
else if (array.getClass().equals(Instructor.class))
{
instCount = 0;
}
else
{
System.out.println("There was an issue validating the object type.");
}
}
I'm especially confused about the implementation of the clear() method as I've never had to do this type of object comparison before. I'm not sure why the instanceOf operator comparison was giving me weird results.
[...] will this object have access to the methods in it's own class, or is
it restricted to the superclass methods only? My understanding was, if
the superclass is abstract, the children still inherit their methods
when instantiated in this way.
It doesn't matter, whether the superclass is abstract. A child class inherits the parent class' methods and attributes. Whether these are accessible by the child class depends on visibility modifiers.
I'm having a hard time understanding how to differentiate between the
two object arrays in the methods. For example, i'm writing a clear() function that sets the specified object array(Student[] or Instructor[]) to null when called.
You could overload the clear() method like:
public void clear(Student[] array) {...}
public void clear(Instructor[] array) {...}
or (if I understand the purpose of your example correctly) compare the input array's reference with the array references in your class definition:
public void clear(Person[] array) {
if(array == this.studentArray) {
// clear students
} else if(array == this.instArray) {
// clear instructors
}
}
But if you want to actually compare the arrays' types, you can do:
array.getClass().equals(Student[].class)
or
array instanceof Student[]
For the clear method :
array = new Person[array.length] // re-init arrayt ot it's inital size.
studentCount = studentArrayl.length;
instCount = instArray.length;
that should réinit the given array to a new empty array of the correct length and reasigne correct number to studentCount and instCount.
Regards.
Nemesis.
For #1, yes, newStudent will have access to it's own methods and also it's superclass unless it's #Overriden.
For #2, you are having a hard time because your UniversityPeople class is doing too many things. This is will become a maintenance issue and is a code smell. UniversityPeople violates the single responsibility principle. Your class should do one thing only. Why not do a UniversityInstructor and a UniveristyStudent? But since you are following instructions, here's an idea for your clear function. Before you null your array, get one content in the array. Say Person person = array[0];, then you can do an if (person instanceof Student) and then if (person instanceof Instructor). This way you'll know the type of you array and proceed accordingly.
I missed one of my lectures in Java, and the subject was classes, methods, constructors etc. The homework is one task:
Create a class Person, objects of which describe persons, and which
contains only two felds: name (String) and year of birth (int). In
this class, define
constructor taking name and year of birth;
constructor taking only name and setting the year of birth to default value 1990;
method isFemale returning true if this person is a woman (we assume, not very sensibly, that only women and all women have names ending
with the letter 'a'); otherwise the method returns false;
static function getOlder taking two references to objects of class Person and returning the reference to the older of these two persons;
static function getOldest taking the reference to an array of references to objects of class Person and returning the reference to
the oldest person represented in the array;
static function getYoungestFemale taking the reference to an array of refe- rences to objects of class Person and returning the reference
to the youngest woman represented in the array, or null if there is no
woman in the array.
In a separate class, write a main function in which the whole
functionality of the class Person is tested.
I checked some tutorials and explanations, I didn't go straight here asking for help but after 2 hours of ripping my hair out I've been only able to come up with this:
public class Person {
String name;
int yob; //year of birth
public Person() {
Person jan = new Person("Jan", 1995); //the names are polish
Person joanna = new Person("Joanna", 1993);
Person michal = new Person("Michal", 1980);
Person beata = new Person("Beata", 1979);
Person kazimierz = new Person("Kazimierz", 1998);
Person magdalena = new Person("Magdalena", 1999);
}
public Person(String name, int yob) {
this.name = name;
this.yob = yob;
}
public Person(String name) {
this.name = name;
this.yob = 1990;
}
public static boolean isFemale(String name) {
if(name.equals("Joanna")) {
return true;
} else {
return false;
}
}
public static String getOlder(Person x?, Person y?) { // if I understand the task correctly, I should reference any two names?
if(x?.yob>y?.yob) {
return x?.name;
} else {
return y?.name;
}
//getOldest and getYoungestFemale methods go here
}
}
However, I can't wrap my head around the last three steps. My brain is literally boiling. It would really help if anyone could explain the last three bullet points (getOlder reference to any 2 people and getOldest/getYoungestFemale)
If you don't have time to explain, some example of a "method taking a reference to an array" should be enough for me to get a basic understanding.
Thanks in advance.
Usually.. you don't call it "reference to an array of references of something" You just say "array of something". Even though arrays of objects are arrays of references to objects. Just like a variable for an object is just a reference to an object.
Type heyImAReference = new ImTheObject();
So when you write
Person person = new Person();
You'll have the class Person as type, person as a reference to an instance (or object) of that class and the resulting entity of new Person() as the actual thing that is being referenced. Usually called "instance" or in your case "object".
When it comes to arrays of persons and you do
Person[] persons = new Person[5];
You create via new Person[5] an array instance that has 5 slots, in each slot can go a Person instance figuratively, actually though you have 5 references. Person[0] being the first, Person[1] being the second and so on. So that is an "array of references to objects of class Person".
And persons is a reference to that. So it is a "reference to an array of references to objects of class Person"
static function getOldest taking the reference to an array of references to objects of class Person and returning the reference to the oldest person represented in the array
means nothing more than
static Person getOldest(Person[] persons) {
...
}
I would call that a method that takes an array of Persons and returns a Person. Though technically, it's all just references that go in and come out. The Person objects don't "move"
Firstly create another class which will have main method. Within main create an array:
Person[] parr = new Person[6];
//Then fill all your person to this array:
parr[0] = new Person("name", year);
parr[1] = ....
Then pass this array handler to your methods:
Person p1 = Person.findSomething(parr);
In Person class:
public static Person findSomething(Person[] parr){
for (Person p : parr){
if (p.name.endsWith("a")) return p;
}
return null;
}
Here are some hints which should help you work out the answer yourself without me giving away the solution ;)
1)
public static String getOlder(Person x?, Person y?) {
// if I understand the task correctly, I should reference any two names?
if(x?.yob>y?.yob) {
return x?.name;
} else {
return y?.name;
}
}
This code is almost correct! Just remove the question marks! Also remember that the older person will have an earlier yob. EDIT, also you need to return the reference to the person, not their name, so return either x or y.
2) getOldest and getYoungestWoman
Person[]
is an array of references to Person objects. You should be able to read up on how to loop through the elements of an array and compare values.
3) an extra: if you declare those 6 Person objects inside the constructor, you won't be able to access them in other methods of the class. it is ok to create the Person objects there, but you must declare them outside the constructor. Declare them in the class.
I am creating a vector which stores the object of a particular class.
This class a String variable which is the identifier of that object.
So, I create an object and set this variable as "abc". Then after this object is destroyed I make another object and set the same variable as "abc".
Now I have to check if there is any object in vector already present with variable set as "abc".
I have tried using toString() and comparable() as such but no success.
I know I can make a loop and check for it but I was hoping for some simpler and faster way.
Thanks in advance.
Do you mean something like…
We have a class Dog.
public class Dog {
public String name;
public String color;
public ZonedDateTime dateOfBirth;
public Dog( String nameArg ) {
this.name = nameArg;
}
}
We collect instances in a Vector.
Vector dogs = new Vector( 3 );
dogs.add( new Dog( "Jupiter" ) ) ;
dogs.add( new Dog( "Jasmine" ) ) ;
dogs.add( new Dog( "Jacques" ) ) ;
Later we want to test if the Vector contains any dog by the name of "Jasmine"? Not that particular dog above, but any containing that text as its name?
Yes, looping to ask each dog's name and compare the text returned is one way.
Another way is to override the equals method to compare names. Then you can call the contains method on the vector to see if it has a matching dog object. But overriding equals is often not realistic. In this example, sharing a name does not mean we have the same dog and so we don't want that to be the definition of equals.
Map
A better approach is to use a different collection than Vector. One of the Map implementations makes more sense. A map stores a pair of objects, a key and a value.
In this example the dog's name string would be the key. The dog object would be the value. When you later provide the key, you can retrieve the value (the dog object). You can ask the map if it contains contains a particular key.
See the Tutorial on Map.
By the way, Vector is generally not used any more. It was long ago supplanted by other implementations of List such as ArrayList and LinkedList.
I have a file with is the output of an trading agent's activities. For example:
222666:org.powertac.common.Order::171875::new::21::165482::-35.74395569719625::35.0
222666:org.powertac.common.Order::171876::new::21::165893::-35.74395569719625::35.0
The class Order is defined as:
public Order (Broker broker, Timeslot timeslot,
double mWh, Double limitPrice)
{
super();
this.broker = broker;
this.timeslot = timeslot;
this.mWh = mWh;
this.limitPrice = limitPrice;
}
so from the file I have:
<id>:<package_name>::<execution_id>::<new object>::<args_list>
However, there is some examples like:
222665:org.powertac.genco.Genco::21::setCurrentCapacity::35.74395569719625
222665:org.powertac.genco.Genco::21::setInOperation::true
so instead of creating a new object, I have to call the method setCurrentCapacity with the 35.7439.. parameter.
My goal is to create a
Map<Integer, Object> map = new Map<Integer, Object>();
that's it, a Map between Integer id and Object. Thus, if I want to reproduce the agent activity again, I would just process the Map Object. I was wondering what would be the best approach to achieve my goal. Do I have to actually create the Genco object, for example, and cast it to Object before storing on the Map? How do I set the function call? I mean, how do I create the Genco object and tell it to call setInOperation in the Map? Also, what does it mean and how could I handle values like:
300:org.powertac.du.DefaultBrokerService$LocalBroker::1::new::default broker
300:org.powertac.du.DefaultBrokerService$LocalBroker::1::setLocal::true
with the $ symbol?
The dollar sign is a valid character in a class name, but by convention its use is discouraged. In practice, it can show up for numerous reasons. In your scenario, it is likely that LocalBroker is an inner class of DefaultBrokerService.
From the JLS§3.8:
The "Java letters" include uppercase and lowercase ASCII Latin letters
A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical
reasons, the ASCII underscore (_, or \u005f) and dollar sign ($, or
\u0024). The $ character should be used only in mechanically generated
source code or, rarely, to access pre-existing names on legacy
systems.
I was wondering what would be the best approach to achieve my goal. Do
I have to actually create the Genco object, for example, and cast it
to Object before storing on the Map?
Genco is already an Object. You don't need to cast it. All classes inherits from Object in Java. Just insert it in the map.
yourMap.put( 1234, gencoObj );
I mean, how do I create the Genco object and tell it to call
setInOperation in the Map?
Get the object via its id (your map key), cast it to the apropriate type and call the desired method.
Object o = yourMap.get( 1234 );
if ( o instanceof Genco ) {
Genco g = ( Genco ) o;
g.methodToBeCalled();
}
The $ sign is used by the Java compiler to name nested classes. So, in your case, LocalBroker is a nested class of DefaultBrokerService.
Compiling this:
public class Foo {
private class Bar {
}
}
Will generate two .class files: Foo.class and Foo$Bar.class.
Edit: to store the method parameters you can do something like:
// considering this class
public class Genco {
...
public void methodToBeCalled( Double param ) {
// do something
}
}
// in another class...
// storing the parameters using a String as a key
// representing the object id + the name of the method to be called
Map<String, Object[]> params = new HashMap<String, Object[]>();
// for methodToBeCalled of the object with id equals to 1234
// store a new array of objects with an 2.5 Double (autoboxing will apply here, i.e.,
// the double 2.5 will be wrapped in a Double
params.put( "1234-methodToBeCalled", new Object[]{ 2.5 } );
// now, using...
int objectId = 1234;
// get the object
Object o = yourMap.get( objectId );
// verify if it is an instance of Genco
if ( o instanceof Genco ) {
// yes, it is, so cast it to Genco to be able
// to call Genco specific methods
Genco g = ( Genco ) o;
// getting the parameters (objectId + method name)
Object p = params.get( objectId + "-methodToBeCalled" );
// calling the method, passing the first value of the stored array (2.5)
g.methodToBeCalled( ( Double ) p[0] );
}