Referencing subclasses from superclasses in java - java

Suppose I have an abstract class Person. There is another class Student which extends Person. But the Student class has a member variable, say college of type String, which is not there in Person class.
We know that we can reference a subclass from a superclass, for example,
Person p = new Student();
Will the object p have the member college?

You won't be able to do p.college. However, you can cast it to Student and in this case it will have:
((Student) p).college;

In your sample, Person object IS a Student and hence will have the college member.
Since you cast the Student to a Person, any public routines or data not present in Person will be hidden by the cast assignment though.

Related

What is the difference between those kind of instantiation?

it's maybe a newbie question but I think it will be helpful for some beginners.
My question is :
public abstract class Person {
code goes here ....
}
public class Employee extends Person {
code goes here ....
}
What is the difference between those kind of instantiation ?
Person student = new Employee("Dove","Female",0);
and
Employee student = new Employee("Dove","Female",0);
They are essentially the same, but the compiler treats Person student as a Person without any type information from the concrete class Employee
It's basically the same thing, but the difference is that:
1- In the first declaration:
Person student = new Employee("Dove","Female",0);
Here student can't access Employee class specific methods or attributes as it's a Person object which contains an Employee instance.
2- But in the second one:
Employee student = new Employee("Dove","Female",0);
Here student can benefit from both Employee and Person attributes and methods.
Please check Polymorphism Oracle Docs for further reading about polymorphism in Java.
Example:
We can see that in this example, where we use Integer and Object classes:
Integer i1= new Integer(0);
//This will run and execute perfectly
System.out.println(i1.intValue());
Object i2= new Integer(0);
//This will throw an error as `Object` class doesn't have `intValue()` method.
System.out.println(i2.intValue());
This is a live working Demo so you can see that.
Following is difference in both instantiation.
(1)
Person student = new Employee("Dove","Female",0);
In this instantiation student is object of Person class so it can't access Employee class specific methods or attributes.
(2)
Employee student = new Employee("Dove","Female",0);
Here, in second instantiation student can access Employee class specific methods and attributes as well as Person class because it is extending in Employee class.
This is basic difference in this two statements.

I am getting unusual object reference codes and null values when I initialise a constructor

I have a couple of questions about how class instances are set up. If I have an object constructor as follows:
Object(String newName, ArrayList<Person> newPersonList){
name=newName;
personList=newPersonList;
System.out.println(personList);}
which is then assigned to a person as a method in the Object class:
matchPersonToObject(Person person){
this.matchedPerson=person;
person.addToObjects(this); //do I need to add the full project.domain address in here?
//Because if so it will only let me put the class `Person` in rather than an instance `person`
}
//in the person class:
addToObjects(Object obj){
this.objectList.add(obj);
System.out.println(objectList);
}
when I then initialise this as follows:
Person chris=new Person("Chris");
Object obj1=new Object("thing",new ArrayList<Person>(Arrays.asList(chris)))
it gives an output of:
[project.domain.Person#1a40fff] //personList in object constructor
[Object - null] //objectList once person has been matched to it
My two questions are
a) what is that hexidecimal code that is being give to my person instance? Why does it not just display [project.domain.chris]?
b)When I add the object to the objectList, why is this registering as null? Have I initialised the ArrayList correctly?
First: Never name your classes with reserved words of languague you are using, e.g. avoid create classes with names like Vector, Long, etc... generates confuse in your code.
Second: he hexidecimal code you are looking at is the hash code of your class Person, overwrite the method toString() os Person class.
public String toString() {
return <anything_you_want> + name;
}
it's possible a bad package importation because you have a class with Name object and compiler doesn't recognize your class, java.lang.Object is different of your Object class.

Polymorphic behavior not being implemented

The last two lines of this code illustrate the problem: the compiler works when I use the reference to the object, but not when I assign the reference to an array element. The rest of the code is in the same package in separate files. BioStudent and ChemStudent are separate classes, as well as Student.
package pkgPoly;
public class Poly {
public static void main(String[] arg) {
Student[] stud = new Student[3];
// create a biology student
BioStudent s1 = new BioStudent("Tom");
// create a chemistry student
ChemStudent s2 = new ChemStudent("Dick");
// fill the student body with studs
stud[0] = s1;
stud[1] = s2;
// compiler complains that it can't find symbol getMajor on next line
System.out.println("major: " + stud[0].getMajor() ); // doesn't compile;
System.out.println("major: " + s0.getMajor() ); // works: compiles and runs correctly
}
}
There's a lot of missing info, such as what is s0, or if BioStudent and ChemStudent extend Student, however I'll just assume all of this is true and s0 is either a BioStudent or ChemStudent.
If so, I'm not entirely sure about the proper terminology, but when you use a reference variable of the parent type and point it to a Child object, you can only access the child methods if these override the parent methods.
In other words, you need to have the getMajor() method defined in your parent class Student, then overriden in your child class BioStudent and/or ChemStudent.
stud is an object of class Student.
I am assuming few things -
BioStudent and ChemStudent extends Student class.
BioStudent has a method getMajor()
Student Class does not!
That is the reason stud[0].getMajor() is giving you a compile time error.
You have to typecast it to the subclass of Student.
System.out.println("major: " + ((BioStudent) stud[0]).getMajor() );
According to the information given I am assuming couple of things.
Student is a super class
BioStudent and ChemStudent extends Student
stud[0] = s1
stud[1] = s2
The error that you are getting is because Student class doesnt have getMajor() but the BioStudent and ChemStudent has that method.
You have created a Student array. For the compiler stud[0] is Student class, not the BioStudent nor ChemStudent. Only during the runtime jre would know that stud[0] has BioStudent and stud[1] has ChemStudent. That is why you are getting the compilation error.
Solution 1:
Either add getMajor() method to Student class and the other 2 class overrides it.
OR
Solution 2:
Typecast by adding this to your print statement (BioStudent stud[0]).getMajor() - which explicitly means this is BioStudent object and the compiler would know BioStudent has getMajor().

Access variables outside a class that extends another class

How can I access variable outside a class that extends an other class that is used in an array list? I get an error that says that the variable does not exist in the extended class. Take a look, I want to access the variable members without having to declare it in my Object class:
public abstract class Object {
public int x, y;
}
public class House extends Object {
public int members = 10;
}
// Somewhere else
ArrayList<Object> list = new ArrayList<Object>();
list.add( new House() );
for (Object o : list ) {
o.members;
}
The problem is that in the RTS I'm writing, my Object class has over 40 variables, just because it doesn't work to declare them only in the sub class and access them from outside.
Hope you understand. How can I do this?
You can use instanceof and a cast:
for (Object o : list ) {
if (o instanceof House) {
h = (House) o;
h.members;
}
}
However, this is often considered bad design; you should consider defining an appropriate method in Object (which should really have another name, as others have pointed out) and override it in House. Then, you may call that method on an Object without knowing what kind of object it refers to, and if it is a House, the correct method will be called. (Learning how to do this properly, and when to do it, takes a bit of practice - google polymorphy and overriding.)
First do not name your class Object (see the comments). You cannot access member of an Object in your code, because Object has no field member, House has. But an Object does not have to be a House, so it is not guaranteed that it has member.
If you're sure that in this case youre Object is always a House, cast it:
((House) anObject).member;
This way the compiler assumes that you know more than he does about the actual class of the Object and handles it as if it was a House. You can use instanceof to check if the cast is valid.
Hope you understand that you are using the name for your class as 'Object', which is the parent class for all the classes in Java. Now in your environment there will be two Object classes one which java provides from java.lang.Object and another one you have created. So when you are trying to access your class object and trying to get the attributes of that, it is actually not your class object rather it is an instance of java.lang.Object and hence you are running into an issue.
You have to cast o to a House. E.g. ((House) o).members
just cast the member of arraylist like this
((House)o).members;

I need some help designing an array

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)

Categories