Why is this class better suited to be abstract instead of concrete? - java

Why is this Student class (a class which creates new student objects and assigns them unique ID's) better suited to be an abstract class rather than a concrete class? Each student object created is assigned it's own unique ID right, so why not just have the implementation for the graduate() method inside the class itself rather than implemented by an inherited class?
public abstract class Student {
protected int id;
private static int lastID = 0;
protected String firstName;
protected String familyName;
public Student(String firstName, String familyName) {
id = Student.nextID();
this.firstName = firstName;
this.familyName = familyName;
}
private static int nextID() {
return ++lastID;
}
public String toString() {
return firstName + " " + familyName;
}
// Generate string containing graduation information
public abstract String graduate();
}

The point would be: if you have various sub classes of Student, each one coming with a distinct differentiating attribute, say "major class".
Thus: this model would only allow students with a distinct "major class", therefore it would be meaningful to prevent creating "raw" Student objects that lack the corresponding "attribute".
But you have to understand: the reasons that determine how exactly you build your object model (which classes are abstract, and which ones are not) are coming out of what you intend to model.
In other words: the person writing this abstract Student class deemed that doing it exactly like this would be the best fit to the underlying requirements. In a different context, Student might very will be not abstract.

Generally a student class is written as abstract because of the types of students that you will have. i.e, high school, college, etc.
Some students have information that others don't. For instance, a college student may have a dorm number where a high school student wouldn't. The abstract class allows you to have more flexibility and not lock in a singular definition for student.

Related

What makes the difference between the two examples below?

What makes composition different from aggregation they are both declared as private, is it in composition example we are creating an object of Address class in constructor of Person, if it's then how this makes the Person object control/own the Address object.
public class Person {
private String firstName;
private String lastName;
private Address address;
//Composition example
public Person() {
address = new Address();
}
public Address getAddress() {
return address;
}
}
Employee Class
public class Employee {
private String firstName;
private String lastName;
private int age;
//Aggregation Java example
private Address address;
public void setAddress(Address address) {
this.address = address;
}
public Address getAddress() {
return address;
}
}
Well, let me first start by explaining the differences between Aggregation and Composition.
Aggregation:
1. A child in an Aggregation relationship can exist independently of the parent
2. Aggregation can be read as "HAS A"
Example: If we have a class Wheel, the relationship between the class Wheel and Car is an Aggregation: "A car has four wheels". A Wheel can exist out of the context of a car.
Composition:
1. A child in an Composition relationship cannot exist independently of the parent. In other words, there's no sense of for the child class to exist if it cannot be hosted into the parent class.
2. Composition can be read as IS PART OF
Example: If we have a class Human, the relationship between the class Heart and Human is composition. You never seen a heart hanging out by itself, don't you? Hence, the need for Composition.
In Java we represent the Composition relationship using private final
class Human { private final Heart heart; }
While Aggregation would be just:
class Wheel { ... }
class Car { private List<Wheel> wheels; }
Now let's say, we would like to remove an object of class Human (taking into account he is not an organ donor) completely, the Composition relationship forces us to destroy the instance of the heart related to that human being. In Aggregation it is not the case, the wheels can be used by another car if the instance of the car they used to belong to got wrecked.
I hope this helps.

Using an extend from a class or use composition

I have a abstract class called user and I'm wondering if i have to add another class that requires a user does it need to extend from the class below or do i need to reuse the user class via composition, all help is greatly appreciated.
public abstract class User implements Serializable {
protected String userName;
protected String emailAddress;
protected Date dob;
protected Password password;
// Initialisation Constructor
public User(String userName, String emailAddress,
int d, int m, int y,
String cPW, String uEPW, int noTries){
this.userName = username;
this.emailAddress = emailAddress;
this.dob = new Date(d, m, y);
}
this.password = new Password(cPW, uEPW, noTries);
// Assume that User also has ==>
// 1. a toString() method,
// 2. an equals() method, and
// 3. appropriate set() and get() methods
}
Its not clear why this class needs to be marked as abstract. An abstract class is one that cannot be instantiated, but you have written a constructor suggesting that it can?
Since an abstract class can't be instantiated on its own the only way it can be used is via inheritance.
In this scenario though, it would seem that your User class should not be abstract, and therefore other classes can simply use it via composition.
In general, prefer composition over inheritance where it makes sense, and if there is a need for inheritance, prefer to inherit purely abstract interfaces rather than classes containing implementation.
Inheritance is an "is-a" relationship.
Composition is a "has-a" relationship.
So if the new class is for example, Admin - An admin is-a user so use inheritance.
If the new class is something like UserAccount - use composition. The account is not a user but is associated with one.

Java super classes, subclasses, and arrays. Inherit subclass methods not showing in array

I am having trouble getting an array to give me the setters and getters for subclasses in my program.
I have the main class Person, the subclass SchoolEmployee, and two subclasses that inherit fields from SchoolEmployee (which inherits fields from the Person class).
I created a test file to check if everything is working, but it seems to only be able to give me the methods for the Person class.
For example, I created an array:
Person[] schoolemployees = new Person[4];
Then, I proceeded to put values in the array using the constructors I made for each class:
schoolemployees[0] = new Teacher(FirstNameHere, SecondName, etc...);
schoolemployees[1] = new Teacher(FirstNameHere, SecondName, etc...);
schoolemployees[2] = new Office(FirstNameHere, SecondName, etc...);
schoolemployees[2] = new Office(FirstNameHere, SecondName, etc...);
My problem is, I am only able to set/get fields and call methods from within the Person class.
For example:
input = JOptionPane.showInputDialog(null, "Enter name for first name");
schoolemployees[1].setFirstName(input);
When I try to set/get fields or call methods from within the subclasses, they will not show up at all.
Could someone please provide some insight into why I am unable to see the inherited fields in the array? Thank you.
Your array is typed as a Person[]. This means that the compiler knows that each element is a Person (or null). It has no way of knowing that schoolemployees[1] is a Teacher, so it will not let you access fields or methods other than the ones common for all Person.
If all Person should have a setFirstName, then you can declare an abstract (or even a concrete) method on Person for it.
If you are sure that the given array entry is a Teacher you can typecast: Teacher t = (Teacher)schoolemployees[1];. Then you can call teacher methods on t. But you will get an exception when this person turned out not to be a teacher.
Maybe you want to have your array be a SchoolEmployee[] instead (that class seems to have your methods).
I think about that your problem, there are one way. you can make the abstract class of person. and inherits the SchoolEmployee. you define same method that common your opinion for example setName(String str) because all object get the name. and you expand your function
It is happening because you are using reference of Person class So during compile time method call will be resolved from the Person class. e.g.
class Person {
private String firstName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
class Student extends Person {
private String ClassName;
public String getClassName() {
return ClassName;
}
public void setClassName(String className) {
ClassName = className;
}
}
And you are accessing it in below way
Student student = new Student();
student.setFirstName("Naresh");
student.setClassName("Highschool");
// For compiler person is Person (at runtime it will be resolved to object of Student class), and person class doesn't have setClassName() defined in it compiler will give an error while accessing it
Person person = new Student();
person.setFirstName("Naresh");
// Compilation error here because setClassName() is not accessible from Person
person.setClassName("Highschool");

Accessing the properties of a super-class from an instance of its sub-class

class Person {
public String name;
String id;
public Person() {
System.out.println("Parent default");
name = id = "";
}
public Person(String name, String id) {
System.out.println("Parent parameter");
this.name = name;
this.id = id;
}
void show() {
System.out.println(this.name + "\n" + this.id);
}
}
class Student extends Person {
Student() {}
Student(String a, String b) {
super(a, b);
}
}
class Main {
public static void main(String args[]) {
Person p = new Person("A", "AA");
Student s = new Student("b", "BB");
s.show();
}
}
I'm very new to java, so I wanted to understand a few basic things, but I failed. If I inherit from a parent class, this means I get a copy of the parent class in the child class, right? So, in this code—if I reference the parent class' show method (in Main class), this is supposed to show the parent class' name and id which were set previously.
But it isn't showing—so I have a problem in my understanding for sure. How can I access the parent class' copy from the child class? Using the super method from child's constructor? I also want to know the basic of inheritance in short.
Consider the following statement:
Person p = new Person("A", "AA");
This is creating a Person. Its name is "A" and its id is "AA".
Now consider this statement:
Student s = new Student("b", "BB");
This is creating a new Student. It's also creating a new Person. How is that possible? Well a Student is a Person. That's what inheritance means. When a type extends another type, that is defining an "is a" relationship between the types.
Dog extends Animal, because a Dog is an Animal. Car extends Vehicle, because a Car is a Vehicle.
So when you create a new Student, you're creating a Person. Student extends Person, so a Student is a Person. Not too surprisingly, I might add.
The super keyword is used to reference a parent class' methods and fields from its child class. In your Student constructor
Student(String a, String b) {
super(a, b);
}
you're actually indirectly invoking the Person constructor by calling super(a, b). So new Student("b", "BB") creates a Person with name "b" and id "BB". That Person happens to be a Student as well.
There's no real relation whatsoever between person "a" and person "b" (though they could perhaps be distant cousins). If you ask person "a" for her name, she will reply "a". If you ask person "b" for his name, he will reply "b". It would be a little odd to have one person reply with someone else's name, so the individuals are treated as completely different people.
See also: Java Inheritance Documentation
Inheritance doesnt quite work how you think, The methods and variables are copied however the values are not.
If you make a new Person() and populate it, then make a new Student() the values in the Person are not copied, this is because values are usually based on Instances of classes not just Classes. There is a way to copy this but it is not usually done except in mistake which is to make the variable static.
Static variables are associated with the Class and not the instance and so are shared by all instances of that Class
When you call super() you are calling the method of the parent with the values of the child, so if you had two methods one overloaded and one not then you can call the parent method instead if you needed to, for instance, note it doesnt change the person class previously defined just sets the "parent" name variable in the Student
class Person{
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
public Student(String name, int grade){
super(name);
this.grade = grade;
}
}
For the Static idea you can share a variable across all instances. ie
class Person{
static String School = "Wandsworth Primary";
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
public Student(String name, int grade){
super(name);
this.grade = grade;
}
public show() {
System.out.println(school);
}
}
Your child class, 'Student' has inherited the show method from the parent.
Hence, when you created an object of student, with some values b and BB, those values got displayed.
The values of the student , will be passed through student to parent since you called super(a,b) and will be displayed using the show() method which is obtained from it's parent class.
Hope this helps you.
This is not related to inheritance. You just don't understand the concept of classes.
The p and s that you created are completely independent things. They won't affect each other, so calling s.show() will never print the values in p.
"But s inherits from p though! So it must have a copy of p!" you argued. No, s does not inherit from p, only Student inherits from Person.
It is not that s has a copy of p, but instead, Student has a copy of Person.
In Student, there isn't a show method, but you can still call it. Why? Because Student inherits from Person, so the show method is "copied" to Student.
When you call show, what actually happens is that the show in Person is called:
System.out.println(this.name + "\n" + this.id);
As you can see, it prints the caller's (We know it's caller because of the this keyword) name and id. So who's the caller here? s! That's why it prints the student's name and id.
If you still don't understand, just think of Student like this:
class Student {
public String name;
String id;
void show() {
System.out.println(this.name + "\n" + this.id);
}
Student() {}
Student(String a, String b) {
System.out.println("Parent parameter");
this.name = name;
this.id = id;
}
}
See? I copied all the stuff from the Person class to Student!

Java, how to make variable of the upper class stays null; how to 'hide' variable from the subclass?

I have four classes. Class Person, and three more, Student, Professor, Tutor, each of which extends class Person. Class Person has 2 variables studentID and staffID. However, only student can have studentID != null, and Tutors and Professors can have staffID != null. Now when creating new object Student, how can I make sure that no matter what staffID always stays null? staffID must remain in class Person, so no moving it around.
The whole point of inheritance is that only values and functions (members) that are valid for a parent class are placed in the parent class, and any child-specific members are placed in the child class.
Don't abuse OO, move staffID into your child class.
My suggestion would be to create a Staff class that contains staffID, have it inherit Person, then have Professor and Tutor inherit from it. Then move studentID into the Student class. That way only Professor and Tutor have access to staffID and Student does not, and vice versa for studentID. All classes can still be assigned to a Person type.
Create interfaces to restrict operations:
package main;
public interface IsStaff {
public void setStaffId(Integer staffId);
public Integer getStaffId();
}
package main;
public interface IsStudent {
public void setStudentId(Integer studentId);
public Integer getStudentId();
}
Create your Person class:
package main;
public class Person {
protected Integer studentId = null;
protected Integer staffId = null;
}
Create your Student and Staff subclasses with the Interfaces to define the only allowed operations:
package main;
public class Staff extends Person implements IsStaff {
#Override
public void setStaffId(Integer staffId) {
this.staffId = staffId;
}
#Override
public Integer getStaffId() {
return staffId;
}
}
package main;
public class Student extends Person implements IsStudent {
#Override
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
#Override
public Integer getStudentId() {
return studentId;
}
}
And now create your Tutors and Professors:
package main;
public class Tutor extends Staff {
}
package main;
public class Professor extends Staff {
}
Objects of the Student class don't have operations that can affect the staffId, and objects of the Staff class (including the Tutor and Professor subclasses) don't have operations that can affect the studentId. Add other operations as necessary (common ones can go into Person directly).
As a bonus, you can use the interfaces to better define methods, like this:
public void assignParkingSpaceTo(IsStaff staffMember);
public void issueLateSlipTo(IsStudent student);
The studentID should be a member of Student not Person. Likewise Professor and Tutor should both extend a class Faculty which has a staffId which in turn extends Person
Make this variables private and create getter and setter.
Depending of class implement different methods behaviors.
For stasfs - protect setting studentId
for student - protect setting staffId.
don't extend the Person class. Use composition instead.
If you want polymorphism, create a Blammy interface that provides a common interface for Student, Professor, and Tutor. The student ID and staff Id stuff could or could not be part of the Blammy interface.
Each class, Student, Professor, and Tutor would contain a private instance of Person and proxy to any Person functionality they wanted to expose.
Student would have a studentId data member and Professor and Tutor would have a staffId data member. The getStudentId() for profesor and tutor would always return null and the get staffId for student would also always return null.
make the variable private, create getters and setters. Then make your constructor initialize both variables, and simple pass null for student ID for teachers, and null for staffID for students.
constructor --->
public Person(int staffID, int studentID){
this.staffID = staffID;
this.studentID = studentID:
}
when you initialize ---->
Student student = new Person(null, 1234);

Categories

Resources