Java - static constructor - java

Hey there Stackoverflowers,
I just started programming in Java and encountered a strange problem concerning printing an object. When a new object of type gast is created the user has to enter his or her birthday. This al works fine, however, if I try to print it out I returns 0-0-0. Why is that? By the way, if I create a new datum directly with the parameter constructor it works fine. Wherein lays the problem? I just can't figure it out. I hope you guys can help me out.
Thanks in advance!
public class Datum {
private static String patroon = "\\d{2}-\\d{2}-\\d{4}";
public int dag;
public int maand;
public int jaar;
Datum(int dag, int maand, int jaar) {
System.out.print("constructor: " + dag);
this.dag = dag;
System.out.println(", dag: " + this.dag);
this.maand = maand;
this.jaar = jaar;
}
Datum() {
newDatum();
}
/* */
public static Datum newDatum() {
String input = Opgave5.userInput("Geboortedatum gast");
boolean b = input.matches(patroon);
if (b) {
String[] str = input.split("-");
int dag = Integer.parseInt(str[0]);
int maand = Integer.parseInt(str[1]);
int jaar = Integer.parseInt(str[2]);
Datum datum = new Datum(dag, maand, jaar);
System.out.println(datum);
return datum;
}
else {
return new Datum();
}
}
public String toString() {
return this.dag + "-" + this.maand + "-" + this.jaar;
}
}
Second class:
Gast() {
this.firstName = Opgave5.userInput("Voornaam gast");
this.lastName = Opgave5.userInput("Achternaam gast");
this.geboortedatum = new Datum();
System.out.println("gast: " + this.geboortedatum); // <--- this prints out 0-0-0
}
public String toString() {
return this.firstName + " " + this.lastName + " " + this.geboortedatum;
}

I think you don't understand constructors in Java. You are merely ignoring the result of newDatum() in the constructor. Also, if it did have the expected effect, it might recurse infinitely in the constructor invocation inside newDatum(). Use something like this; allowing newDatum() to edit the instance will work:
Datum() {
newDatum(this);
}
public static void newDatum(Datum instance) {
String input = Opgave5.userInput("Geboortedatum gast");
boolean b = input.matches(patroon);
if (b) {
String[] str = input.split("-");
int dag = Integer.parseInt(str[0]);
int maand = Integer.parseInt(str[1]);
int jaar = Integer.parseInt(str[2]);
instance.dag = dag;
instance.maand = maand;
instance.jaar = jaar;
System.out.println(instance);
}
else {
new Datum();
}
// ^^ Above code may be buggy, see my answer above code
}

This line:
this.geboortedatum = new Datum();
Is using the default constructor. This will set no values. Try to pass the parameters in via constructor like this:
this.geboortedatum = new Datum(1, 2, 3);
If you want to take advantage of the static method you wrote (which is where you ask for user input), then do the following:
this.geboortedatum = Datum.newDatum();

Related

How to improve a cumbersome comparison of 2 objects' fields

We have a program that compares thousands of pairs of Students by checking each field of the Student and counting the diffs:
class Student{
String name;
String address;
String biologyCourse;
.....
// about 100 other fields
}
And the counter POJO class:
class Counters{
long bothStudentsHaveName;
long onlyLeftHasName;
long onlyRightHasName;
......
// number of fields in Student * 3 (both, only left, only right)
}
Our compare function accepts 2 students plus the counters object and needs to scan the fields and update the relevant counters:
public void compareStudents(Student left, Student right, Counters counters){
if (!StringUtils.isEmpty(left.name) && !StringUtils.isEmpty(right.name) ){
counters.bothStudentsHaveName++;
} else if (StringUtils.isEmpty(left.name) && !StringUtils.isEmpty(right.name)){
counters.onlyRightHasName++;
} else if (!StringUtils.isEmpty(left.name) && StringUtils.isEmpty(right.name))){
counters.onlyLeftHasName++;
}
/// and now??
}
At this point, we can add 100s more triplets of if/else like the above - but we believe there should be a much easier way to do that.
Reflection can be an option or maybe X dimensions arrays, but can we somehow write the code so the comparison and counting will be much more generic?
I have solved your problem with one single loop. But here I'm assuming that naming convention for all the fields will be the same as described in your question. Here I am dynamically accessing the Student fields and updating Counter fields accordingly. Here is the complete solution:
Solution Class:
public class Solution {
public void compareStudents(Student left, Student right, Counter counter) throws Exception {
for (Field field : Student.class.getDeclaredFields()) {
Object leftValue = field.get(left);
Object rightValue = field.get(right);
String fieldName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
if(leftValue != null && rightValue != null) {
Field counterField = Counter.class.getDeclaredField("bothStudentsHave" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
} else if (leftValue != null) {
Field counterField = Counter.class.getDeclaredField("onlyLeftHas" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
} else if (rightValue != null) {
Field counterField = Counter.class.getDeclaredField("onlyRightHas" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
}
}
}
}
Student Class:
class Student {
String name;
String address;
String biologyCourse;
}
Counter Class:
class Counter {
// name
long bothStudentsHaveName;
long onlyLeftHasName;
long onlyRightHasName;
// address
long bothStudentsHaveAddress;
long onlyLeftHasAddress;
long onlyRightHasAddress;
// biologyCourse
long bothStudentsHaveBiologyCourse;
long onlyLeftHasBiologyCourse;
long onlyRightHasBiologyCourse;
// ... and so on
#Override
public String toString() {
return "Counter{" + "\n" +
"\tbothStudentsHaveName = " + bothStudentsHaveName + "\n" +
"\t, onlyLeftHasName = " + onlyLeftHasName + "\n" +
"\t, onlyRightHasName = " + onlyRightHasName + "\n" +
"\t, bothStudentsHaveAddress = " + bothStudentsHaveAddress + "\n" +
"\t, onlyLeftHasAddress = " + onlyLeftHasAddress + "\n" +
"\t, onlyRightHasAddress = " + onlyRightHasAddress + "\n" +
"\t, bothStudentsHaveBiologyCourse = " + bothStudentsHaveBiologyCourse + "\n" +
"\t, onlyLeftHasBiologyCourse = " + onlyLeftHasBiologyCourse + "\n" +
"\t, onlyRightHasBiologyCourse = " + onlyRightHasBiologyCourse + "\n" +
'}';
}
}
Tester Class:
public class Tester {
public static void main(String[] args) throws Exception {
// Creating Dummy Variables
Student student1 = new Student();
student1.name = "Test";
student1.biologyCourse = "Yes";
Student student2 = new Student();
student2.name = "Test1";
student2.address = "abc street";
Counter counter = new Counter();
// Comparing Students
Solution solution = new Solution();
solution.compareStudents(student1, student2, counter);
// Printing Counter
System.out.println(counter);
}
}
Output:
Counter{
bothStudentsHaveName = 1
, onlyLeftHasName = 0
, onlyRightHasName = 0
, bothStudentsHaveAddress = 0
, onlyLeftHasAddress = 0
, onlyRightHasAddress = 1
, bothStudentsHaveBiologyCourse = 0
, onlyLeftHasBiologyCourse = 1
, onlyRightHasBiologyCourse = 0
}
If you keep repreating the same basic pattern of fields, then consider extracting that into a class. For example introduce a FieldComparison class that looks a little like this:
public class FieldComparisonCounter {
public int bothHave;
public int onlyLeftHas;
public int onlyRightHas;
// constructor, getters, setters left as an exercise for the reader
}
Then have a Map<String,FieldComparisonCounter> counters somewhere and a method like this:
public void compareField(String fieldName, String leftValue, String rightValue) {
FieldComparisonCounter counter = counters.get(fieldName);
if (counter == null) {
counter = new FieldComparisonCounter();
counters.put(fieldName, counter);
}
boolean leftHas = !StringUtils.isEmpty(leftValue);
boolean rightHas = !StringUtils.isEmpty(rightValue);
if (leftHas && rightHas) {
counter.bothHave++;
} else if (leftHas) {
counter.onlyLeftHas++;
} else if (rightHas) {
counter.onlyRightHas++;
}
}
Then adding a new field comparison is as simple as calling
compareField("name", left.name, right.name);

Print all the names inside a string array

I'm practicing Java and I have a question about printing all values inside a String array. I would need to print everything inside the String arrays I have created.
I can't seem to make "Arrays.toString" to work in my code and I don't want to have to point out each value inside the array. Is there a way I can print them all at once?
public class MyCode {
public static void main(String[] args) {
String[] majority = {"Congrats, you may enter!", " Awesome!"};
String[] minority = {"I'm sorry, you are too young.", " Ah that's too bad!"};
int permition = 17;
boolean authorization = (permition >= 18);
if (authorization == true) {
System.out.println(majority[0] + majority[1]);
} else {
System.out.println(minority[0] + minority[1]);
}
}
}
So, if the person is above or equal to 18, the result should be "Congrats, you may enter! Awesome!", or if below 18 "I'm sorry, you are too young. Ah that's too bad!".
You can try this
List<String>majorities =
Arrays.asList(majority);
List<String>minorities =
Arrays.asList(minority);
String str_majority = String.join("",
majorities);
String str_minority = String.join("",
minorities);
String final = str_majority +
str_minority

How can a User create dates in my Calender (java)?

I m currently trying to code a Calender with java.
I created 3 classes:
1. Date( includes year, month....)
2. Event(includes people, place, the class Date ... + an option to create dates )
3. Mainclass My mainclass that contains the menu.
My problem is that I don't know how the user is able to create his own date, because I have to create the object Termin myself... So, can somebody help me fix this? Thx in advance!
public class Event {
private String mDescription, mPlace, mNames;
private Date mStart, mEnd;
Termin(String description, String place, String names, Date start, Date end) {
mBetreff = description;
mOrt = place;
mNamen = names;
mBeginn = start;
mEnde = end;
}
public void create() {
Scanner read = new Scanner(System.in);
System.out.println("Enter 1. description 2. place 3. names 4. start 5. end ein");
mDescription = read.nextLine();
mPlace = read.nextLine();
mNames = read.nextLine();
}
public String toString() {
return "Description : " + mDescription + "\nPlace: " + mPlace + "\nNames: " + mNames + "\nIts starts at " + mStart
+ " and ends at " + mEnd;
}
}
public class Date {
private int year, day, month, hours, minutes;
Datum(int year, int month, int day, int hours, int minutes) {
this.day= day;
this.year= year;
this.month= month;
this.hours= hours;
this.minutes= minutes;
}
public String toString() {
return "\n" + day + "." + month + "." + year + " um " + hours+ ":" + minutes;
}
public void enterDate() {
}
}
EDIT:
I asked this question 2 years ago, back when I just started coding and had no idea of oop and encapsulation ...
To answer my own question, for every newbie that also tries to create a terminal calender:
Date needs the following methos:
public setDate() {
this.year = read.nextLine();
...
}
for every member.
Event takes the resulting object Date, either in the constructor or in a setter like method.
Creating an instance-method to create an appointment is kind of... strange since one needs to create an appointment (called Termin in your case) to create an appointment. One possibility would be the builder pattern. By having a public static inner builder class, you can set the constructor(s) private and enforce the use of that builder:
public class Main {
private int value;
private Main(int value) {
this.value = value;
}
public int getValue() {
return (this.value);
}
public static class MainBuilder {
boolean valueWasSet;
int value;
public MainBuilder() {
this.valueWasSet = false;
this.value = -1;
}
public void setValue(int value) {
this.value = value;
this.valueWasSet = true;
}
public Main build() {
if (!this.valueWasSet) {
throw new IllegalStateException("value must be set before a Main can be build.");
}
return (new Main(this.value));
}
}
}
(this is a simplified sketch to show the core mechanism on how to assert that certain values are set before constructing a Main through MainBuilder.
The process of constructing a Main would be:
MainBuilder builder = new MainBuilder();
builder.setValue(100);
// all following Main's will have a value of 100
Main mainOne = builder.build();
Main mainTwo = builder.build();
builder.setValue(200);
// all following Main's will have a value of 200
Main mainThree = builder.build();
Main mainFour = builder.build();

Why don't I get a calclatefee result? Is my Array value overriding my overridden method? [duplicate]

This question already has answers here:
Having inheritance and polymorphism issues with Java
(2 answers)
Closed 6 years ago.
I am trying to output calclatefee of $2 per day after 3 days. I have switched things around and I am left at this which looks a little sloppy. This Array is also making me take the confusing way.
public class Movie {
String rating;
String title;
int id;
int rentTime;
public String setrating() {
return rating;
}
public void rating(String getrating) {
rating = getrating;
}
public int setid() {
return id;
}
public void id(int agetid) {
id = agetid;
}
public String settitle() {
return title;
}
public void title(String gettitle) {
title = gettitle;
}
public int setfees() {
return rentTime;
}
public void fees(int getrentTime) {
rentTime = getrentTime;
}
public Movie() {
title = " ";
rating = " ";
id = 0;
rentTime = 0;
System.out.println("default constructor");
}
public Movie(String title, String rating, int id, int rentTime) {
title = " not overridden ";
rating = " NR ";
id = 0;
rentTime = 0;
System.out.println("Overloaded -" + title + rating + id + rentTime);
}
public static void main(String[] args) {
Movie[] Array = {
new Action(" The 100", " pg-13", 105, 7, 3),
new Comedy(" Supernatural", " pg-13", 5, 2, 0),
new Drama(" Lost 2", " R", 9, 2, 0) };
for (int x = 0; x < Array.length; x++) {
// System.out.println(x);
System.out.println(Array[x].toString());
}
}
}
public abstract class Action extends Movie {
protected double latecost;
protected double latefees = 3;
public Action(String gettitle, String getrating, int getid, int getrentTime, double latecost) {
super(gettitle, getrating, getid, getrentTime);
title = gettitle;
rating = getrating;
id = getid;
rentTime = getrentTime;
latecost = latefees;
System.out.println("Overridden " + title + rating + " " + id + " " + " " + rentTime + " "
+ latecost);
}
public double calclatefees(double latecost, double rentTime) {
if (rentTime > 3)
latefees = ((rentTime - 3) * latecost);
return latefees;
}
#Override
public String toString() {
String x = "\nMovie: " + title + " is rated " + rating + "\nMovie ID number: " + id
+ " and the late fee for action movies is $" + latecost + "\n";
return x;
}
protected void finalize() throws Throwable {
try {
System.out.println("Finalize method");
} finally {
super.finalize();
}
}
public void dispose() {
System.out.println(" dispose method");
}
}
Problems:
There's no calclatefee method to override in the parent class. If you want a child class to override method, it must be present in the parent class, at least as an abstract method (if the parent is abstract or is an interface).
You never call your calclatefee method anywhere, so you shouldn't expect to ever see its result in your output.
Your child class, Action, is abstract -- isn't that backwards? Most often its the parent class that's abstract, so why are you structuring it this way? And as written your main method shouldn't compile since you seem to be trying to create an instance of an abstract class.
Your class overrides the finalize() method, something that is generally not recommended. Fortunately your override doesn't really do anything other than output to the standard out and then call the super's method, but still, why risk it?
Side issues
Your code does not follow Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
You will want to try to improve the formatting of your code that you post in here and your code in general. Good formatting including using an indentation style that is uniform and consistent will help others (us!) to better understand your code, and more importantly, it will help you to better understand your code and thus fix your own bugs. Also it shows that you're willing to put in extra effort to make it easier for the volunteers here to help you, and that effort is much appreciated. I took the liberty of trying to fix this for you.

Converting Units using if statements?

I have to write a program to convert between linear units in, ft, mi, mm, cm, m, km. I know there are easier and better ways to do this. I think we'ere just trying to fully understand if else if statements. But this is what I have so far. I'm just trying to figure out if I am on the right track. I've tried to write out some pseudocode but it just seems like a lot going on so I find it a bit overwhelming. Next I'm going to add a method to convert form in or mm to whatever is selected by the user.
When I test the program i get this: UnitConversion#76c5a2f7 (EDIT: THIS ISSUE WAS FIXED)
Ok I made the suggested changes and that allowed the first part of the program to run properly. I have now added my second method to convert from in/mm to the other measurements.. I was having issues but I figured it out.
Here is my main method;
public class LinearConversion
{
public static void main(String[] args)
{
UnitConversion newConvert = new UnitConversion("km", "m", 100);
System.out.println(newConvert);
}
}
Any suggestions? What am I missing or not understanding about doing this sort of program?
public class UnitConversion
{
private String input;
private String output;
private double value;
private double temp;
private double in, ft, mi, mm, cm, m, km;
private final double inch_feet = 12;
private final double inch_miles = 63360;
private final double inch_millimeters = 25.4;
private final double inch_centimeters = 2.54;
private final double inch_meters = 0.0254;
private final double inch_kilometers = 0.0000254;
private final double millimeters_inch = 0.0393701;
private final double millimeters_feet = 0.00328084;
private final double millimeters_miles = 0.000000622;
private final double millimeter_centimeters = 10;
private final double millimeter_meters = 1000;
private final double millimeter_kilometers = 1000000;
public UnitConversion(String in, String out, double val)
{
input = in;
output = out;
value = val;
}
public String toString()
{
if (input.equals("mi"))
{
in = value * inch_miles;
input = "in";
}
else if (input.equals("ft"))
{
in = value * inch_feet;
input = "in";
}
else
{
in = value;
input = "in";
}
if (input.equals("km"))
{
mm = value * millimeter_kilometers;
input = "mm";
}
else if (input.equals("m"))
{
mm = value * millimeter_meters;
input = "mm";
}
else if (input.equals("cm"))
{
mm = value * millimeter_centimeters;
input = "mm";
}
else
{
mm = value;
input = "mm";
}
return value + input + " " + output;
}
public double getUnit()
{
if (input.equals("in"))
{
if (output.equals("ft"))
{
ft = in * inch_feet;
System.out.println(ft + "ft");
}
else if (output.equals("mi"))
{
mi = in * inch_miles;
System.out.println(mi + "mi");
}
else if (output.equals("mm"))
{
mm = in * inch_millimeters;
System.out.println(mm + "mm");
}
else if (output.equals("cm"))
{
cm = in * inch_centimeters;
System.out.println(cm + "cm");
}
else if (output.equals("m"))
{
m = in * inch_meters;
System.out.println(m + "m");
}
else if (output.equals("km"))
{
km = in * inch_kilometers;
System.out.println(km + "km");
}
else
{
System.out.println(in + "in");
}
}
else
{
if (output.equals("cm"))
{
cm = mm * millimeter_centimeters;
System.out.println(cm + "cm");
}
else if (output.equals("m"))
{
m = mm * millimeter_meters;
System.out.println(m + "m");
}
else if (output.equals("km"))
{
km = mm * millimeter_kilometers;
System.out.println(km + "km");
}
else if (output.equals("in"))
{
in = mm * millimeters_inch;
System.out.println(in + "in");
}
else if (output.equals("ft"))
{
ft = mm * millimeters_feet;
System.out.println(ft + "ft");
}
else if (output.equals("mi"))
{
mi = mm * millimeters_miles;
System.out.println(mi + "mi");
}
else
{
System.out.println(mm + "mm");
}
}
}
Basically, you need/want to give a String argument to System.out.println in order to display it.
Thus, when you use System.out.println with an Object (that is not a String) as the argument, Java actually outputs the result of the toString method on that object.
If you haven't overridden it, the Object class' implementation of toString is used: this is what gives you your current output: UnitConversion#76c5a2f7.
To learn more about how is this default toString implementation generating that String, you can refer to the javadoc entry for Object#toString.
Base on your output, and your provided code, yes! Rename String getInput() to String toString() and your current main() will work, or change your current main()
System.out.println(newConvert.getInput()); // <-- added .getInput()

Categories

Resources