Calling a Constructor without parameters - java

I am trying to build a class with a constructor, mutators and accessors. Reading through books and online, I am made to learn that you can call a constructor with or without parameters. However, my case below seems not to work. I am not even able to compile without errors. It works when I use student jane = new student(""). What am I doing wrong?
Devolution.java:6: cannot find symbol
symbol : constructor student()
location: class Governor
student jane = new student();
^
public class designers {
public static void main(String[] args) {
student jane = new student();
student smith = new student("jane", "36365355", "Nairobi", "Male");
System.out.println("Janes's Properties: "+jane.name() + " " + jane.nationalID() + " " + jane.county()+" "+jane.gender());
System.out.println("Smith's Properties: "+smith.name() + " " + smith.nationalID() + " " + smith.county()+" "+smith.gender());
}
}
other code is below
public class student {
//Private fields
private String name;
private String nationalID;
private String county;
private String gender;
//Constructor method
public student(String name, String nationalID, String county, String gender)
{
this.name = name;
this.nationalID = nationalID;
this.county = county;
this.gender = gender;
}
//Accessor for name
public String name()
{
return name;
}
//Accessor for nationalID
public String nationalID()
{
return nationalID;
}
//Accessor for county
public String county()
{
return county;
}
//Accessor for gender
public String gender()
{
return gender;
}
}

A constructor is a way of creating an instance of a class:
Student s = new Student(...);
will create a new instance of the Student class and enable you to access it using s.
Often, when you create an instance of a class, you need to specify certain information that's used in building the instance. In the case of a student, that might be the name, the age, and so on. You'd have a constructor that looks like this:
public Student(String name, int age) {
//...
}
But in some contexts, you can build an instance of a class without needing (at least initially) to specify anything. So you might, for instance, have a constructor like this
public Student() {
//...
}
which leaves the name and age fields blank or zeroed out, until you later set them with another method of the class.
The critical point for what you're doing is that you've made a constructor that requires various parameters, but you haven't specified one like this second example that doesn't require any. As things stand, you can write
Student s = new Student("Bob", "ABC12345", "Surrey", "Male");
because you've got a constructor that takes four Strings as arguments. But you can't write
Student s = new Student();
because you didn't create a constructor that takes no arguments.
The slight wrinkle in this is that if you don't specify any constructors in your class, then Java will automatically create one for you that takes no arguments and doesn't do anything special. So if you don't write any constructors, you'll get one for free that looks like this:
public Student() {
}
But that's only if you don't write any of your own. Since you've specified one that does take parameters, Java won't give you a no-argument one for free. You have to put it in yourself if you want to be able to create instances without any arguments.

You've only written one constructor - the one with four parameters. You don't have a constructor without parameters, so you can't write new student().
Note that if you don't write any constructors at all, the compiler will automatically make a constructor for you, without parameters, but as soon as you write one constructor, this doesn't happen.
By the way, most people use capital letters for class names (so Student, not student). This makes it easy to distinguish them from the names of other identifiers. It would be good for you to get into the habit of doing the same.

You don't have a constuctor without parameters in the student class. Such a constructor is generated by the compiler only if you haven't defined any other constructors, which you have.
Just add the constructor :
public student()
{
this.name = null;
this.nationalID = null;
this.county = null;
this.gender = null;
}

You need to make another constructor as follow:
public Student(){
//do things here
}
Explanation:
When no constructors are defined in a class then there is a default constructor(without
any parameters) already. In which case you don't need to define it. But if you have any constructor with some parameters, then you need to define the constructor without parameters as well.

Its called overloading the constructor. In your class, declare a constructor again without parameter requirements. See this post for more info

You don't have a constructor without parameters. That would only be the case when you had not write an own one. When you want to have the possibility to make an object of the class with or without parameters, you need two different constructors in your code.

Related

How can I access subclass attribute through passing its superclass as parameter of a method

I am having trouble with a method that accepts two classes Pokemon as its parameters because it could be whatever pokemon battling, but if I try to catch the name of the subclass, such as Totodile, the superclass's name attribute is printed
in Pokemon.java:
abstract public class Pokemon {
private String name="POKEMON";
public String getName() {
return name;
}
}
in Totodile.java :
public class Totodile extends Pokemon {
String name = "Totodile";
}
in Geodude.java :
public class Totodile extends Pokemon {
String name = "Geodude";
}
in Battle.java :
public class Battle {
public void initiateBattle(Pokemon pokemon1,Pokemon pokemon2){
System.out.println(pokemon1.getName()+ " is battling against " + pokemon2.getName());
}
}
in App.java:
public class App {
public static void main(String[] args) throws Exception {
Geodude geodude = new Geodude();
Totodile totodile = new Totodile();
Battle battle = new Battle();
battle.initiateBattle(totodile, geodude);
}
}
The output is "POKEMON is battling against POKEMON"
, but how could I get "Totodile is battling against Geodude"
You can't "override" a field. When you write:
class Foo {
String name;
}
you are always declaring a new field. If your superclass also has a field with the same name, okay. Now your Totodile class has 2 fields, both named name, one of which has value POKEMON, the other has value Totodile.
Which one do you get when you write myPokemon.name? Depends on the compile-time type of myPokemon (the variable, not the object it is pointing at!) - and given that it is Pokemon in your code, you get the Pokemon version of the name field.
This notion that you have 2 fields with identical names is called 'shadowing'.
Shadowing is a mistake; do not do it unless you really, really know what you are doing.
The solution is therefore quite simple: Don't define a field named name in the Totodile class. Instead, set the value of the name field (which you inherited, so the Totodile class has that name field already, no need to make a second field with the same name and confuse things):
class Totodile {
{ name = "Totodile"; }
}
This somewhat weird syntax creates an instance initializer, as you need to stuff your code somewhere (you can't just start putting statements straight into a class, you need to brace em up). This is a tad odd, the more usual design is instead something like this:
abstract class Pokemon {
private final String name;
public Pokemon(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Totodile extends Pokemon {
public Totodile() {
super("Totodile");
}
}
This is what most java programmers do:
It forces subclasses of Pokemon to actually set the name properly. That default 'POKEMON' value is weird and no longer needed in the above strategy.
It avoids exotic code constructs to make it work. Constructors and abstract classes tend to be a lot more familiar to your average java coder than instance initializers.
Adds final in the appropriate places.

Sports team model - constructor in class cannot be applied to given types

You are writing a computer program to model sports teams (could be baseball, football, kickball, ultimate, anything!). Your awesome coworker has already written the following classes:
The Team class contains the following methods:
// Constructs a Team object based on the supplied Roster object.
public Team(Roster r)
// Simulates this Team playing a single game, returning a String describing the results of the game.
public String play(Game g)
The Roster class contains the following method (other methods not shown):
// Returns a String containing the names of players on this Roster
public String toString()
The Game class contains methods, but none are shown here.
Design a new class TeamWithStats that inherits from Team, but also keeps track of the team's statistics ("stats"). You should provide the same methods as the superclass, as well as the following new behavior:
// Constructs a TeamWithStats object using information in the Roster object r.
public TeamWithStats(Roster r)
// Returns the information described below
public String getStats();
The getStats method returns a single String containing (in this order): the Roster (in String form, as returned by Roster’s toString method), a "newline" character (\n), the results returned from the first call to play, a "newline" character (\n), the results returned from the second call to play, a "newline" character (\n), the results returned from the third call to play, and so on, through the very last call to play that has been made so far. If play has not yet been called, getStats just returns the Roster (in String form).
Assume all classes other than TeamWithStats were written by your awesome coworker and cannot be changed. In your class, you should include the following:
Any private field(s) you need to add to TeamWithStats
Implementation of the TeamWithStats constructor
Implementation of any methods you need to override.
Implementation of getStats
As always, your methods should call into the superclass as appropriate.
Code:
public class TeamWithStats extends Team
{
private Roster r;
public TeamWithStats(Roster r) {
super(r);
this.r = r;
}
public String getStats() {
return r.toString() + "\n" + super.play(new Game()) + "\n";
}
}
Error message
Error on line 12: constructor Game in class Game cannot be applied to given types;
return r.toString() + "\n" + super.play(new Game()) + "\n";
^
required: java.lang.String
found: no arguments
reason: actual and formal argument lists differ in length
Explanation
Your error message is pretty straightforward, carefully read it:
Error on line 12: constructor Game in class Game cannot be applied to given types;
return r.toString() + "\n" + super.play(new Game()) + "\n";
^
required: java.lang.String found: no arguments
reason: actual and formal argument lists differ in length
So you are calling new Game(), without any arguments. But the constructor in that class requires you to call it with a String, like new Game("foo").
If you lookup the code for the class Game, you will see something like:
public class Game {
...
// Constructor that requires a String as argument
public Game(String foo) {
...
}
...
}
Check out the class to see what exactly the purpose of that String is.
Example
To give you a better feeling for what you did wrong, let me show you another example. Suppose you have a class Person and you want that each person has a String name and an int age. You can achieve this by letting the constructor require both. For example:
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public String getAge() { return age; }
}
Now you can create instance of this class by calling the constructor and providing both, a name and an age:
Person person = new Person("John", 20);
But what you are trying to do is just calling it like new Person(), without supplying any name or age, despite the constructor requiring it.

Succinct way to print using multiple getter methods - Java

I have quite a few getter methods in a class and I need to print the return of those getters (Just one and not all of them at once). I need to be able to do this with one print() method but I am not sure how to do this. Is there a way to dynamically call another method and then print the return of that method?
Here are a couple of getter methods:
public String getEmail()
{
return this.studentEmail;
}
public Integer getAge()
{
return this.studentAge;
}
Here is what I am wanting to do:
public void print(???)
{
System.out.println(theGetterMethod);
}
I know that I can create a bunch of print methods but I need to be able to do this with one method.
As asked by the OP:
"I think you were correct with your first comment and it can be an answer."
From:
"You can tackle it by using Sytem.out.println ("E-mail: " + ...getEmail(), " Age: " + ...getAge()); If you want to go overkill you can use reflection."
Meaning instead of having a seperate print() method you will instead be invoking the right accessor for the value you want to print.
This is one of reasons why you use accessors in the place, as now you are exposing the fields without any risk of having the user change them.
You can still change on underlying Objects apart from String as it is immutable.
You can call methods dynamically based on their name by using reflection.
In this example I assume that each Getter follows a pattern and just pass over the property name that I want to print out:
import java.lang.reflect.Method;
public class Student {
private String studentEmail = "MyEmail";
private Integer studentAge = 20;
public String getEmail() {
return this.studentEmail;
}
public Integer getAge() {
return this.studentAge;
}
// Prints out a property based on the name
public void print(String property) throws Exception {
for (Method method : this.getClass().getMethods())
if (method.getName().equals("get" + property))
System.out.println(method.invoke(this, null));
}
// Prints out all properties with a getter
public void print() throws Exception {
for (Method method : this.getClass().getMethods())
if (method.getName().startsWith("get"))
System.out.println(method.invoke(this, null));
}
}
And than call the method like that:
Student s = new Student();
s.print("Email");
s.print("Age");

How can we get immutable object if class did not implement cloneable

I have few issues/doubts to fill values in a HashMap
I want a HashMap to accept "Student" as key and "Details" as value.
Since key to a hashMap should be immutable I have some doubts how can this be dealt if
Student class did not cloneable
Student class has reference to which in turn have reference to "Lab"
public class Student {
private String id;
private String name;
private Department dept;
public Student(String id, String name, Department dept)
{
this.id=id;
this.name=name;
this.dept=dept;
}
public Department getDepartment()
{
return this.dept;
}
}
public class Department {
private String deptId;
private Lab lab;
public Department(String deptId, Lab lab)
{
this.deptId=deptId;
this.lab=lab;
}
public void setLab(Lab lab)
{
this.lab=lab;
}
}
public class Lab {
private String labId;
private String labName;
public Lab(String labId, String labName)
{
this.labId=labId;
this.labName=labName;
}
}
public class StudentDetails
{
private String fatherName;
private String address
public StudentDetails(String fatherName, String address)
{
this.fatherName=fatherName;
this.address=address;
}
}
public class StudentMaintainer {
public static void main(String[] args)
{
StudentDetails stDetails= new StudentDetails("John","Mumbai");
Lab lab= new Lab("100","CS");
Department dept= new Department("900", lab);
Student st = new Student("3000",dept);
Map<Student,StudentDetails> studentMaintainer= new ArrayList<>();
studentMaintainer.put(st,stDetails);
}
}
Now Even if Student is cloneable, I can get reference of Department and call setLab() which changes the StudentObject. (Am I wrong?)
Now if Department and Lab are from 3rd party jars, how can I use Student Object in my Map if Student hashCode is (primeNumber+Student.id+Department.id+Lab.id).hashcode() [just some weird case];
Immutability has nothing to do with Cloneable as far as I understand it, and in fact just the opposite. Immutability has more to do with declaring the class final and using immutable fields, non-overridable methods, no setter methods, getter methods that return deep copies of fields or immutable fields, etc... Please read A Strategy for Defining Immutable Objects for more on this.
Also your code has a pseudo-constructor:
public void Student(String id, String name, Department dept)
{
this.id=id;
this.name=name;
this.dept=dept;
}
A true constructor should not be declared to return anything, not even void. Better would be:
// note the difference?
public Student(String id, String name, Department dept)
{
this.id=id;
this.name=name;
this.dept=dept;
}
Also, your Student class should properly override equals and hashCode if it is to work well as a key for a HashMap.
Now Even if Student is cloneable, I can get reference of Department
and call setLab() which changes the StudentObject. (Am I wrong?)
You are correct. This can happen, and can cause your Student class to appear to be mutated. For an instance of Student to be immutable, you must not be able to modify any of its fields[0]. That includes calling something like a setter method on one of its fields.
Now if Department and Lab are from 3rd party jars, how can I use
Student Object in my Map if Student hashCode is
(primeNumber+Student.id+Department.id+Lab.id).hashcode() [just some
weird case];
That is a very good question. You obviously can't just change the classes to be immutable, since you don't have control over them, so you may have to get a bit creative. Possible solutions:
if the third party objects you want to use are interfaces, you could implement the interface with your own type, where the body of every mutator method throws an exception (think e.g. java.util.Collections.unmodfiableList). This has the benefits that you can still refer to the third party class in your codebase, but the drawback that calling mutator methods will fail at runtime, rather than at compile time.
write adapters in your own codebase, like this:
public final class MyImmutableDepartment {
private final MyImmutableLab lab;
private final String departmentId;
public MyImmutableDepartment(Department thirdPartyMutableDepartment) {
this.departmentId = thirdPartyMutableDepartment.getId();
this.lab = new MyImmutableLab(thirdPartyMutableDepartment.getLab());
}
// getters and the MyImmutableLab class left as an exercise
}
This has the advantage that you know at compile time, the classes cannot be mutated.
The downside in both approaches is that you basically have to mirror every class from the third party library, to ensure they're immutable.
I don't think there's any other alternatives.
[0] there are some cases where this is possible, and can be used for internal caching, but it's a decent guideline to stick to when learning.
Student does not need to be immutable! Specifically, the requirement is that the behavior of equals/hashCode doesn't change when the key is in the HashMap.
This can be accomplished in three ways:
Don't implement equals/hashCode. If you use the default reference equality, it doesn't matter how you mutate the key. To clarify intent, override those methods, explicitly call super.equals, and make them final.
Don't include any fields that will mutate in your calculation of equals/hashCode. Or, if the properties of a field may change but not the reference, use reference equality (==) instead of field.equals() and call System.identityHashCode(field) instead of field.hashCode()
Don't mutate the object while it is used as a key in the HashMap. A bit dangerous, but works fine if references aren't held by code beyond your control. Document the requirement.
But, in your concrete example, each student has an id. Why would you use any other properties when implementing equals/hashCode.?

List being populated by null records - junit test failing

I've been banging my head against the wall for a while with this one -
I have a method to create a list of objects of another class:
public List <PayrollRecord> processPayroll() {
List<PayrollRecord> payroll = new ArrayList<PayrollRecord>();
for (Employee employee : staff) {
PayrollRecord payRec = new PayrollRecord(employee.getName(), employee.calculatePay());
payroll.add(payRec);
}
return payroll;
}
staff is a list of Employee class objects that can be added to the list by this method:
public void addEmployee(Employee employee) {
staff.add(employee);
}
Employee is also an interface implemented by a few other classes - Manager, SalesAssociate and StoreEmployee. (Can you tell I'm trying to get through an assignment yet? Maybe some of you are familiar).
The PayrollRecord class looks like this:
package my.package.ext;
public class PayrollRecord {
private String employeeName;
private double currentPay;
public PayrollRecord(String employeeName, double currentPay) {
}
public double getCurrentPay() {
return this.currentPay;
}
public String getEmployeeName() {
return this.employeeName;
}
}
So within a test class, I should be able to create some variables for employee info, add some employees to staff, and then run the processPayroll method and do some asserts on it. My test class currently looks like this (and will need several more asserts. I'm not going to bother adding those until I can get this basic problem figured out):
#Test
public void testPayroll() {
List<PayrollRecord> list = store.processPayroll();
assertEquals(managerTestPay, list.get(0).getCurrentPay(), 0);
}
Based on the number of employees I have added elsewhere in the test class, there should be five. I can set list.get out of bounds and verify that there are indeed 5. However the problem is that all 5 records are null and 0.0. I should have a name and pay for each employee record. However the assertion error comes back showing me what I expected, but that the actual value is 0.0 (or null when I try list.get(0).getName()).
Thank you in advance for your help and wisdom.
And you set the members how ?
private String employeeName;
private double currentPay;
public PayrollRecord(String employeeName, double currentPay) {
}
In your constructor you need to assign to the members e.g.
this.employeeName = employeeName;
It's not enough to simply call the constructor with arguments. The arguments need to be used to populate the members of the class (either directly or via some manipulation).
A useful technique here is to set the member variables to be final. This means:
you can't change their values post initialisation
you have to initialise the values either immediately or in the constructor
You might think this is a limitation. However a lot of the time you'll find you only set this info once (I suspect for your assignment the name and salary will remain constant). If you need to change one or other it's easy to remove the final qualification.
private final String employeeName;
private final double currentPay;
public PayrollRecord(String employeeName, double currentPay) {
this.employeeName = employeeName;
// etc...
}
Ensuring that the members don't change means the class instance is immutable. This is a good thing generally. It's easy to reason about and debug immutable classes, and they're implicitly thread-safe.
You are not assigning the constructor arguments to class variables. Update your constructor as :
public PayrollRecord(String employeeName, double currentPay) {
this.employeeName = employeeName;
this.currentPay = currentPay;
}

Categories