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.
Related
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.
Is there a way to cast an Object array into a java class?,
Example: I have a class "Person" with the next attributes: Name, age, address. And i have an Object[] with this: [1]: "Peter", [2]: 20, [3]: "California 130".
I want to do something like this:
Person p = new Person();
Object[] o = new Object[2];
p = (Person) o;
I have to do this without set the values one by one, example:
p.setName((String)o[0]);
Is there a way?
Regards
You're trying to have the compiler convert an array of Object automagically into a a class with fields, and this just isn't possible. Instead you could create a constructor that takes an array of object and then assigns each item in the array into the fields of your class, but while this can be done, it has a bad code smell. Better to avoid use of Object arrays entirely, that is, arrays that hold items of different types. Instead deal with fields and parameters that have appropriate and actual types, and pass correctly typed items into your class's constructor. i.e.,
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
try something like this:
Person convert(Object[] o){
String name = (String) o[0];
int age = (int) o[1];
String address = (String) o[2];
Person p = new Person(name, age, address);
return p;
}
this method asks for this Object[] and returns a person with the information.
You cannot do it, as this would cause ClassCastException to be thrown. The reason is that because of inheritance and the is-a relationship.
Every Person object is an Object and every String object is of type Object. However, the opposite is not true. This is like saying every horse is a mammal, but not every mammal is a horse.
Create a method in the person class (setAttributes(Object[])for example) that sets the person attributes from the array values.
I just don't understand why t.getName() is Keen if t is assigned to u.
public class StringProgram{
public static void main(String[] args) {
Person t = new Person("Gene");
Person u = t;
u.setName("Keen");
System.out.println(t.getName());//Keen
System.out.println(t.equals(u));//true
}
}
Person class
public class Person{
private String name;
public Person(String d){
name=d;
}
public void setName(String a){
name=a;
}
public String getName(){
return name;
}
#Override
public boolean equals(Object o) {
if (!(o instanceof Person)) {
return false;
}
return ((Person) o).name.equals(this.name);
}
}
I am somewhat new too, but I think this is why it will print "Keen".
This will take a foray into java object usage
First thing first, Person t=new Person("Gene") creates a person object that has the name variable, "Gene". Then, it uses a reference, in your case t, to refer to the object. So t will always refer to that Person object.
Then, with your next line, Person u=t, you are creating a new reference that actually refers to the same Person object with "Gene" as the original t reference. Using the = sign made them do the same thing, refer to "Gene", just like equality with math operations in Java makes the left hand equal to the right hand.
Hence, whether you refer to the "Gene" object with u or t, you are referring to the same thing. Hence, in either u.setName("Keen") or t.setName("Keen"), you are reaching for the same object somewhere in memory and doing something to/with it, in this case changing the name variable to "Keen".
It is exactly like user4932934 mentioned in their comment above.
Note that line:
Person t = new Person("Gene");
uses "new" keyword - it tells you that new object is created.
Line:
Person u = t;
simply assigns "t" to "u". Now they refer to the same object in memory, no new instance of Person was created.
Person u = t; makes u refer to the exact same object as t. The same memory location, if that helps. So changing the contents of t changes the contents of u too. Because they're the same object.
I will share with you metaphor regarding the references i once read.
Imagine that your Person object is balloon. Your reference t is a string (rope, not java String) attached to balloon.
So, when you create another reference u which is same like t, you created another string(rope) attached to the one and same balloon (Person).
If you change property of your balloon, e.g. colour, both u and t will see this change, since you only have one balloon attached to both u and t.
So when you assign reference to another reference, you are not creating new object.
Say below is my bean class:
public class Employee {
private String name = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This is my main class:
import java.util.ArrayList;
public class MainClass {
public static void main(String[] args) {
Employee employee = new Employee();
employee.setName("First name");
ArrayList<Employee> empList = new ArrayList<Employee>();
empList.add(employee);
employee.setName("Last name");
for (Employee emp : empList) {
System.out.println(emp.getName());
}
}
}
When I executed the output is: Last name
My question is:
As I know Java is pass-by-value or rather
pass-by-copy-of-the-variable-value then does the copy of
employee object was saved in the ArrayList or it references the
original object of Employee as the object value is getting changed
to Last name after adding to ArrayList?
Does every Collection behave this way?
A copy of the employee reference was saved in the ArrayList, but since it refers to the same Employee instance, changing the instance later via the employee reference affects the element stored in the ArrayList.
Yes, every Collection behaves this way, since the Collections don't create copies of the instances passed to them, they just store references to those instances.
As I know Java is pass-by-value or rather pass-by-copy-of-the-variable-value then does the copy of employee
object was saved in the ArrayList or it references the original object
of Employee as the object value is getting changed to Last name after
adding to ArrayList?
The reference will be passed-by-value. So, there will be 2 references pointing to the same Employee instance. One reference is employee and another is in the arraylist.
Does every Collection behave this way?
Yes. Actually, this is NOT a property of collections. This is the way java was designed. All mutable reference types behave in this way.
The local variable employee and the first element of the list are two different references to the same object. That's why modifying the referenced object (via setName, for example) on one of them will be visible via the other.
However, if you replace the reference by assigning a different one, it will not effect the other.
E.g.:
employee = new Employee();
employee.setName("Vishrant");
Now employee and the first element of the list reference different objects, so the element in the array will not be called "Vishrant".
For my homework, we've been tasked with creating:
Person class with variables firstName, lastName, streetAddress, zipCode and phone.
CollegeEmployee extends Person and adds ssn, salary, and deptName.
Faculty extends CollegeEmployee by adding a boolean tenure.
Last but not least, Student extends person by adding GPA and major.
Everything looks good displaying to screen, and I'm moving on to the next part of the assignment which is to create 14 records (7 students, 4 employees and 3 faculty) in an array.
3 different classes, with multiple data types, and I cannot for the life of me figure out how to populate an array with this. This is the first array I've created that's not been completely integer. The Java Tutorials didn't give me anything, and while Java: Generic Static Multidimensional Arrays has some great information, it's a little more than I can wrap my head around right now.
I'd initially thought of creating array[14][10] -- fourteen variables each for ten objects -- but I can't mix data types. That's where I got lost.
Anyone have any suggestions on how to design this array and be able to display the values from it afterward?
Any hints and suggestions would be appreciated!
Thanks.
From what I understand, no need to get fancy with multi-dimensional arrays.
1) Create an array that takes Person instances.
Person [] myPeeps = new Person[14];
2) Create a print method on Person, which subclasses override to print the relevant info.
Because your array expects Person instances, you can put instances of any subclasses of Person, because subclasses always have an is-a relationship with their superclass.
Because Person has a print method, you can call print on anything you pull out of the array. Subclasses provide their own implementations so they can print their relevant data. That way, you don't really care about which subclass any particular instance is; the correct print implementation for the instance is invoked at runtime.
You don't need a multidimensional array. You can make an array of Person objects.
Person[] people = new Person[14];
people[0] = new Student();
people[1] = new Employee();
.
.
.
You could also create a Person[] array, just as you would an int[] array. e.g.
Person[] people = new Person[14]
You can then add people to the Array like this:
people[0] = new Student();
people[1] = new CollegeEmployee();
people[2] = new Faculty();
If you want to check what type of person is in each index you will want to use instanceof. Try looking here for more help
One example of using instanceof is:
if(people[0] instanceof Student){
System.out.println("This person is a student");
}
Or try using generics.
You could create an ArrayList<Person> and can then add any type of person to this ArrayList.
e.g.
ArrayList<Person> peopleList = new ArrayList<Person>();
//People can be added like this
peopleList.add(new Student());
peopleList.add(new CollegeEmployee();)
Again you are able to use instanceof to check which type of person is in each index!
Also if you never write
Person person1 = new Person();
In your code then consider making your class abstract.
To start:
Person[] myArray = new Person[14];
This is essentially why object oriented programming is so wonderful. If you'll notice, all Faculty, CollegeEmployee, and Student are a subset of type Person. Because of this, you can have them all contained in the same dataset if it is declared as type Person.
Person[] array = new Person[14];
You can add all of your objects to that array; however, be careful. When you go to use the elements of the array Java now only knows that each has the methods that a Person does - so therefore you can only make use of firstName, lastName, streetAddress, zipCode, and phone from these elements unless you cast the objects after they are retrieved.
Since they are all of type Person, why not use a Person array?
Person [] people = new Person[14];
You can safely add all types of Person to this array, however you can only treat them as Person (without casting). To have each subclass output customized details, and add this method in Person
class Person {
void print() {
// default Person printing
}
}
and override this method in each subclass to print its member variables:
class Student extends Person {
void print() { // <-- note same method signature!
// print "I'm a Student", GPA, major
}
}
and when the array is populated:
for (Person p : people) {
p.print(); // delegates to print method associated with the underlying type
}
Check out the inheritance tutorial
The class Person is a common superclass to all the types of the objects you want to store in the array. You can create the array based on that common supertype. Then you can access methods that are defined in that tpe on all elements of the array, regardless of the actual type -- the behavior is as defined in the actual type (look up inheritance for java if this is not clear).
If you need specific behavior based on the actual type, you need to cast the array element to the concrete type (you can determine it using instanceof, for example)