I'm currently teaching myself Java from a textbook, and found a piece of code that I don't understand - why does the final variable id change it's value?
import static net.mindview.util.Print.*;
class Shared {
private int refcount = 0;
private static int counter = 0;
private final int id = counter++;
public Shared() {
print("Creating " + this);
}
public void addRef() { refcount++; }
protected void dispose() {
if(--refcount == 0)
print("Disposing " + this);
}
protected void finalize() {
if(refcount != 0)
print("Error: object is not properly cleaned-up!");
}
public String toString() { return "Shared " + id; }
}
class Composing {
private Shared shared;
private static int counter = 0;
private final int id = counter++;
public Composing(Shared shared) {
print("Creating " + this);
this.shared = shared;
this.shared.addRef();
}
protected void dispose() {
print("disposing " + this);
shared.dispose();
}
public String toString() { return "Composing " + id; }
}
public class E13_VerifiedRefCounting {
public static void main(String[] args) {
Shared shared = new Shared();
Composing[] composing = { new Composing(shared),
new Composing(shared), new Composing(shared),
new Composing(shared), new Composing(shared) };
for(Composing c : composing)
c.dispose();
This:
private static int counter = 0;
private final int id = counter++;
public Shared() {
print("Creating " + this);
}
is the same as this:
private static int counter = 0;
private final int id;
public Shared() {
id = counter++;
print("Creating " + this);
}
That is, the id is assigned every time the constructor executes, with the side effect that counter is incremented.
id is an instance variable, so each instance of shared gets its own id value.
private final int id = counter++;
If by change you are asking why does the value of id is counter + 1 instead of just counter, that's because first the sum counter + 1 is calculated, and then it is set into id. After that, the value of id cannot change.
Related
I have a following codes, is there a nice way to count number in State enum ??
I want to move StateHolders's function to State enum, but I don't know how to correspond start number to end number.
public enum State{
START("start"),
END("end");
public String msg;
private State(String msg){
this.msg = msg;
}
}
public class StateHolder{
private static AtomicInteger counter = new AtomicInteger();
private int current;
public String start(){
current = counter.getAndIncrement();
return State.START.msg + " " + current;
}
public String end(){
return State.END.msg + " " + current;
}
}
public static void main(String[] args){
StateHolder sh1 = new StateHolder();
StateHolder sh2 = new StateHolder();
System.out.println(sh1.start); // start 0
System.out.println(sh2.start); // start 1
System.out.println(sh1.end); // end 0
System.out.println(sh2.end); // end 1
}
What about this:
public enum State {
...
private static AtomicInteger counter = new AtomicInteger();
public AtomicInteger counter() {
return counter;
}
...
}
public class StateHolder {
private int current;
public String start() {
current = State.START.counter().getAndIncrement();
return State.START.msg + " " + current;
}
...
}
I try to make a thread safe class which allows to follow the scan of something. My class is:
import java.util.concurrent.atomic.AtomicInteger;
public class ScanInProgress {
private final Integer scanId;
private final int nbScans;
private AtomicInteger nbResponses = new AtomicInteger(0);
private AtomicInteger nbErrors = new AtomicInteger(0);
public ScanInProgress(Integer scanId, int nbSites) {
this.scanId = scanId;
this.nbScans = nbSites;
}
public Integer getScanId() {
return scanId;
}
public boolean addSuccess() {
addResponse();
return isDone();
}
public boolean addError() {
addResponse();
nbErrors.incrementAndGet();
return isDone();
}
private void addResponse() {
nbResponses.incrementAndGet();
}
private boolean isDone() {
return nbResponses.get() == nbScans;
}
public int getNbSuccesses() {
return nbResponses.get() - nbErrors.get();
}
public int getNbResponses() {
return nbResponses.get();
}
}
I have the following unit tests class:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ScanInProgressTest {
#Test
public void testConcurrency() throws Exception {
// given
Integer scanId = 1;
int nbScans = 500_000;
ScanInProgress scanInProgress = new ScanInProgress(scanId, nbScans);
// when
for (int i = 1; i <= nbScans / 2; i++) {
new AddError(scanInProgress).start();
new AddSuccess(scanInProgress).start();
}
Thread.sleep(1000);
// then
assertEquals(nbScans, scanInProgress.getNbResponses());
assertEquals(nbScans / 2, scanInProgress.getNbSuccesses());
}
private class AddError extends Thread {
private ScanInProgress scanInProgress;
public AddError(ScanInProgress scanInProgress) {
this.scanInProgress = scanInProgress;
}
#Override
public void run() {
int before = scanInProgress.getNbResponses();
scanInProgress.addError();
int after = scanInProgress.getNbResponses();
assertTrue("Add error: before=" + before + ", after=" + after, before < after);
}
}
private class AddSuccess extends Thread {
private ScanInProgress scanInProgress;
public AddSuccess(ScanInProgress scanInProgress) {
this.scanInProgress = scanInProgress;
}
#Override
public void run() {
int beforeResponses = scanInProgress.getNbResponses();
int beforeSuccesses = scanInProgress.getNbSuccesses();
scanInProgress.addSuccess();
int afterResponses = scanInProgress.getNbResponses();
int afterSuccesses = scanInProgress.getNbSuccesses();
assertTrue("Add success responses: before=" + beforeResponses + ", after=" + afterResponses, beforeResponses < afterResponses);
assertTrue("Add success successes: before=" + beforeSuccesses + ", after=" + afterSuccesses, beforeSuccesses < afterSuccesses);
}
}
}
When I run my test I can see regularly this error in logs:
Exception in thread "Thread-14723" java.lang.AssertionError: Add success successes: before=7362, after=7362
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.assertTrue(Assert.java:41)
The assertion lets me think that when I call the method scanInProgress.addSuccess() and then scanInProgress.getNbSuccesses(), the instruction in first method nbResponses.incrementAndGet() is not yet acknowledged whereas the instruction in second method nbResponses.get() returns something.
What can I do to correct this ?
As far as I unsterstand the problem I think you need to use locks. Before you get or set an variable you need to aquire a lock. This way a variable can't be set and read at the same time. You get something like the code below.
public final static Object LOCK = new Object();
private int yourvariable;
public void setVar(int var){
synchronized(LOCK){
yourvariable = var;
}
}
public int getVar(){
int toReturn;
synchronized(LOCK){
toReturn = yourvariable;
}
return toReturn;
}
note: If your ScanInProgessClass is the only the ScanInProgressClass class, you can use this instead of a LOCK object.
I have three classes
employee
production workers
shift supervisor class
My idea is to make production and shift supervisor extend the employee class and then create another class, EmployeeList to fill it with information about production workers and shift supervisors.
How can i get the names and info from employee class to iterate into an arraylist?
How can i add a random list of employees more than half being prod. workers and the rest shift supervisors?
Employee:
public class Employee {
public String EmployeeName;
public String EmployeeNumber;
public int hireyear;
public double WeeklyEarning;
public Employee()
{
EmployeeName = null;
EmployeeNumber = null;
hireyear = 0;
WeeklyEarning = 0;
}
public static final String[] Enum = new String[] {
"0001-A", "0002-B","0003-C","0004-D","0002-A",
"0003-B","0004-C","0005-D","0011-A", "0012-B",
"0013-C","0014-D","0121-A", "0122-B","0123-C" };
public static final String[] Ename = new String[] {
"Josh", "Alex", "Paul", "Jimmy", "Josh", "Gordan", "Neil", "Bob",
"Shiv", "James", "Jay", "Chris", "Michael", "Andrew", "Stuart"};
public String getEmployeeName()
{
return this.EmployeeName;
}
public String getEmployeeNumber()
{
return this.EmployeeNumber;
}
public int gethireyear()
{
return this.hireyear;
}
public double getWeeklyEarning()
{
return this.WeeklyEarning;
}
public String setEmployeeName(String EName)
{
return this.EmployeeName = EName;
}
public String setEmployeeNumber(String ENumber)
{
return this.EmployeeNumber = ENumber;
}
public int setEmployeehireyear(int Ehireyear)
{
return this.hireyear = Ehireyear;
}
public double setEmployeeweeklyearning(double Eweeklyearning)
{
return this.WeeklyEarning = Eweeklyearning;
}
}
ProductionWorker:
import java.util.Random;
public class ProductionWorker extends Employee {
public double HourlyRate;
public ProductionWorker()
{
super();
HourlyRate = 0;
}
public static void main(String[] args) {
ProductionWorker pw = new ProductionWorker();
Random rnd = new Random();
int count =0;
// adding random Employees.....
while(count<5)
{
int num= rnd.nextInt(Enum.length);
int decimal = rnd.nextInt(10);
double dec = decimal/10;
pw.setEmployeeName(Ename[num]);
pw.setEmployeeNumber(Enum[num]);
pw.setEmployeehireyear(rnd.nextInt(35) + 1980);
pw.setEmployeeweeklyearning(rnd.nextInt(5000) + 5000);
pw.setHourlyRate(rnd.nextInt(44) + 6 + dec);
System.out.println("EmployeeName: " + pw.getEmployeeName() + "\nEmployeeNumber: " + pw.getEmployeeNumber() +
"\nHireYear: " + pw.gethireyear() + "\nWeeklyEarning: " + pw.getWeeklyEarning() +
"\nHourlyRate: " + pw.getHourlyRate() +"\n");
count++;
}
}
public double getHourlyRate()
{
return this.HourlyRate;
}
public void setHourlyRate(double hourlyrate)
{
this.HourlyRate = hourlyrate;
}
}
ShiftSupervisor:
import java.util.Random;
public class ShiftSupervisor extends Employee{
public double YearlySalary;
public int GoalsCleared;
public ShiftSupervisor()
{
super();
YearlySalary = 0;
}
public static void main(String[] args) {
ShiftSupervisor S = new ShiftSupervisor();
Random rnd = new Random();
int count =0;
// adding random Employees.....
System.out.println("Adding Employees..");
while(count<5)
{
int num= rnd.nextInt(Enum.length);
S.setEmployeeName(Ename[num]);
S.setEmployeeNumber(Enum[num]);
S.setEmployeehireyear(rnd.nextInt(35) + 1980);
S.setEmployeeweeklyearning(rnd.nextInt(100) * 100);
S.setYearlySalary(rnd.nextInt(40000) + 40000);
System.out.println("EmployeeName:" + S.getEmployeeName() + "\nEmployeeNumber: " + S.getEmployeeNumber() +
"\nHireYear: " + S.gethireyear() + "\nWeeklyEarning: " + S.getWeeklyEarning() +
"\nearlySalary: " + S.getYearlySalary() +"\n");
count++;
}
}
// returns yearly salary
public double getYearlySalary()
{
return this.YearlySalary;
}
// returns goals cleared
public int getGoalsCleared()
{
return this.GoalsCleared;
}
// set yearly salary
public void setYearlySalary(double yearlysalary)
{
this.YearlySalary = yearlysalary;
}
}
The first thing I would do is have all necessary fields set in the constructor. If an Employee doesn't "exist" until it has a name, then that should be part of the constructor.
Then, I would suggest you consider renaming some of your fields. When I first saw Enum as a String[] and highlighted as a type, it took me a moment to figure out what exactly was going on. Renaming it to employeeNumbers could solve this.
Next, I think you should have an EmployeeGenerator class whose sole purpose is generating Employees.
public class EmployeeGenerator {
public ProductionWorker generateProductionWorker() {
Random rng = new Random();
int numberOfEmployeeNames = employeeNames.length;
String employeeName = employeeNames[rng.nextInt(numberOfEmployeeNames)];
int numberOfEmployeeNumbers = employeeNumbers.length;
String employeeNumber = employeeNumbers[rng.nextInt(numberOfEmployeeNumbers)];
ProductionWorker worker = new ProductionWorker(employeeName, employeeNumber);
int yearHired = rng.nextInt(100) + 1900;
worker.setHireYear(yearHired);
int hourlyRate = rng.nextInt(20) + 10;
worker.setHourlyRate(hourlyRate);
// any other fields...
return worker;
}
// method to generate shift supervisor
}
And then you can simply do
public static void main(String[] args) {
Random rng = new Random();
int numberOfEmployeesToGenerate = 1000;
int minimumNumberOfProductionWorkers = numberOfEmployeesToGenerate / 2;
int numberOfProductionWorkersToGenerate =
minimumNumberOfProductionWorkers + rng.nextInt(100);
int numberOfSupervisorsToGenerator =
numberOfEmployeesToGenerate - numberOfProductionWorkersToGenerate;
List<Employee> employees = new ArrayList<>();
EmployeeGenerator generator = new EmployeeGenerator();
for (int i = 0; i < numberOfProductionWorkersToGenerate; i++) {
ProductionWorker worker = generator.generateProductionWorker();
employees.add(worker);
}
for (int i = 0; i < numberOfSupervisorsToGenerate; i++) {
Supervisor supervisor = generator.generateSupervisor();
employees.add(supervisor);
}
}
This should hopefully give you a point in the right direction. This isn't perfect code, and there are other ways to refactor this to make it more maintainable and performant.
When you say you want to add a random list of employees, What do you mean exactly?
Currently you instantiate only one ProductionWorker and one ShiftSupervisor, change the values of the member variables, and print some text to StdOut.
Do you want to store instances in a list or is the console output sufficient?
Also, you have two main-methods. Which one will be performed? It might be better to have one Main class as an entry point for your application and from there create the instances.
In general you can do something like that:
public class Main {
public static void main(String[] args) {
List<Employee> emps = new ArrayList<>();
for (int i = 0; i < 5; i++) {
//create new employee
emps.add(newEmployee);
}
//do something with list
}
}
Here is my counter class.
public class Counter {
private int value;
public int getValue() {
return value;
}
public void click() {
value = value + 1;
}
public void unclick() {
value = value - 1;
}
public void reset() {
value = 0;
}
public void setLimit(int maximun) {
maximun = 10;
}
}
and here is my tester
public class counterDemo {
public static void main(String[] args) {
Counter tally = new Counter();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
tally.click();
int result = tally.getValue();
System.out.println("results: " + result);
}
}
I'm asked to use math.min(n, limit) to make it so if the click is used more often than limit, it has no effect. Could anyone help me? This seems really simple but I haven't seen something like this used and cant figure it out. Thanks
Math.min, returns a value.
you should use it like this.
public void click()
{
value = Math.min(10, value + 1);
}
or if you want to use that variable...
public void click()
{
value = Math.min(maximun, value + 1);
}
just make sure that you have a maximun as an instance variable of counter
public class Counter {
private int value;
private int maximun;
public void setLimit(int maximun) {
this.maximun = maximun;
}
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I got to what I thought was a finished program and now java is pulling this on me.
The error I get is as follows:
Exception in thread "main" java.lang.NullPointerException
at hirecardemo.HireCar.isAvailable(HireCar.java:68)
at hirecardemo.HireCarDemo.runSimulation(HireCarDemo.java:49)
at hirecardemo.HireCarDemo.main(HireCarDemo.java:25)
Java Result: 1
Main Class:
package hirecardemo;
import java.util.Random;
public class HireCarDemo {
public static void main(String[] args) {
HireCar car0 = new HireCar("Toyota", "AV77 FGJ", 6000, 12300, 41500);
HireCar car1 = new HireCar("Mercedes", "DI99 FTZ", 6700, 7000, 91800);
HireCar car2 = new HireCar("Toyota", "FG82 FTP", 25000, 12000, 72000);
HireCar car3 = new HireCar("Vauxhall", "TW56 LTS", 10000, 11000, 19001);
HireCar car4 = new HireCar("Ford", "TD85 LTU", 13000, 12300, 12000);
HireCar car5 = new HireCar("Susuki", "GU12 UTJ", 12000, 10000, 50000);
HireCar[] fleet = {car0, car1, car2, car3, car4, car5};
int minMileage = 1000;
int maxMileage = 60000;
int numberOFevents = 12;
String [] results = HireCarDemo.runSimulation(fleet, numberOFevents,
minMileage, maxMileage);
for(int i = 0; i < numberOFevents; i++) {
System.out.println(results[i]);
}
}
/**
* #param fleet the fleet of hire cars
* #param numberOFevents the size of the events table to be generated
* #param minMileage the assumed minimum mileage driven by any hired
* car
* #param maxMileage the assumed maximum mileage driven by any hired
* car
* #return table of events generated during the simulation
*/
public static String[] runSimulation(HireCar [] fleet, int numberOFevents,
int minMileage, int maxMileage) {
int n = fleet.length; // Number of cars in the fleet.
Random carGenerator = new Random();
String [] events = new String [numberOFevents];
for(int i = 0; i < numberOFevents; i++) {
int randomNumber = carGenerator.nextInt(n-1);
if(fleet[randomNumber].isAvailable() == true)
{
fleet[randomNumber].hireOut();
events[i] = fleet[randomNumber].getRegNumber() + " <HIRE OUT>";
}
else if(fleet[randomNumber].isOnHire() == true)
{
Random mileage = new Random();
int randomMileage = mileage.nextInt(maxMileage - minMileage);
if(fleet[randomNumber].isBeingServiced() == true)
{
events[i] = fleet[randomNumber].getRegNumber() +
" <RETURN FROM HIRE>" + " <SEND FOR SERVICE>";
} else {
events[i] = fleet[randomNumber].getRegNumber() +
" <RETURN FROM HIRE>";
}
}
else
{
fleet[randomNumber].makeAvailable();
events[i] = fleet[randomNumber].getRegNumber() +
" <RETURN FROM SERVICE>";
}
}
return events;
}
}
Here is my separate class that goes along with this:
//******************************************************************************
// HireCar.java Author: Ryan Holder
//
// Represents the car hire company's fleet of cars and the information on them.
//******************************************************************************
package hirecardemo;
public class HireCar {
private String manufacturer, regNumber, carStatus;
private int mileage, serviceInterval, lastService; // All in miles.
private boolean serviceDue() {
if((mileage- lastService) >= serviceInterval) {
this.sendForService();
return true;
} else {
return false;
}
}
private void sendForService() {
carStatus = "Servicing";
}
//--------------------------------------------------------------------------
// Default Constructor: Sets information for a new car.
//--------------------------------------------------------------------------
public HireCar(String demoManufacturer, String demoRegNumber) {
manufacturer = demoManufacturer;
regNumber = demoRegNumber;
carStatus = "Available";
serviceInterval = 0;
lastService = 0;
mileage = 0;
}
public HireCar(String demoManufacturer, String demoRegNumber,
int demoMileage, int demoServiceInterval, int lastInterval) {
manufacturer = demoManufacturer;
regNumber = demoRegNumber;
mileage = demoMileage;
}
public void setMileage(int demoMileage) {
mileage = demoMileage;
}
public void setServiceInterval(int demoServiceInterval) {
serviceInterval = demoServiceInterval;
}
public void setLastService(int demoLastService) {
lastService = demoLastService;
}
public String getRegNumber() {
return regNumber;
}
public void makeAvailable() {
carStatus = "Available";
}
public boolean isAvailable() {
if(carStatus.equals("Available") || carStatus.equals("Return from Service")) {
return true;
} else {
return false;
}
}
public boolean isOnHire() {
if(carStatus.equals("On Hire")) {
return true;
} else {
return false;
}
}
public boolean isBeingServiced() {
if(carStatus.equals("Being Serviced")) {
return true;
} else {
return false;
}
}
public void hireOut() {
carStatus = "On Hire";
}
public void returnFromHire() {
if(this.serviceDue() == true) {
carStatus = "Being Serviced";
} else {
carStatus = "Available For Hire";
}
}
public void returnFromService() {
carStatus = "Return From Service";
}
public String ToString() {
return("Manufacturer: <" + this.manufacturer + ">/n "
+ "Registration Number: <" + this.regNumber + ">/n"
+ "Mileage: <" + this.mileage + ">/n"
+ "Service Interval: <" + this.serviceInterval + "</n"
+ "Last Service: <" + this.lastService + "</n"
+ "Status: <" + this.carStatus + "</n");
}
}
You are using 5-arg constructor to construct your HireCar instance: -
new HireCar("Toyota", "AV77 FGJ", 6000, 12300, 41500);
And in that constructor, you haven't set the value for - "carStatus".
public HireCar(String demoManufacturer, String demoRegNumber,
int demoMileage, int demoServiceInterval, int lastInterval) {
manufacturer = demoManufacturer;
regNumber = demoRegNumber;
mileage = demoMileage;
}
So, carStatus is still null. (You should set every field in this constructor. At least the references, because their default value is null)
So, when you invoke the isAvailable method for any of the instance you added in your array: -
fleet[randomNumber].isAvailable()
It will result in a NPE, as in isAvailable method, you are invoking equals method on carStatus: -
if(carStatus.equals("Available") || carStatus.equals("Return from Service"))
^^^
This is null here
The stacktrace is telling you that the isAvailable method is throwing a NullPointerException, so let's look at that.
public boolean isAvailable() {
if(carStatus.equals("Available") || carStatus.equals("Return from Service")) {
return true;
} else {
return false;
}
}
Unnecessary return true/false aside, the only thing here that gets dereferenced is car status, so when can it be null?
Well, look at the constructor you're using: the one with 5 arguments. At no point does it ever set the status, so it remains null. Hence the null pointer.
Use an Enum in place of String for carStatus
Initialize all the attributes in ALL constructors (the second left carStatus = null)
you are initializing carStatus in a constructor with 2-args and you never invoke that constructor, thus, carStatus is still null when you call equals() in isAvailable() method.
if(carStatus.equals("Available") || carStatus.equals("Return from Service")) {
^^^ This is **null** as it is not initialized yet, Thus **NPE**.
you should also intialize carStatus in your 5-args Constructor in-order for your current code to work.
public HireCar(String demoManufacturer, String demoRegNumber,
int demoMileage, int demoServiceInterval, int lastInterval) {
manufacturer = demoManufacturer;
regNumber = demoRegNumber;
mileage = demoMileage;
carStatus="someval" ; //initialize carStatus here
}