I need to implement something with a heap sort, and I am having a bug with it.
In the Heap class:
private serial[] data;
private int size;
private static final int FRONT = 1;
public Heap(){
serial[] data = new serial[1000]; //serial - object with a String
this.size = 0;
data[0] = new serial("");
}
public void insert(serial t){
size++;
data[size] = t; **<--- Null Pointer EXCEPTION**
int current = size;
while(data[current].serialNumber() > data[parent(current)].serialNumber()){
swap(parent(current), current);
current = parent(current);
}
}
(and more functions of course for the heap implementation).
and the main class:
public class Simulation {
public static void main(String[] args) {
Heap maxHeap = new Heap();
maxHeap.insert(new serial("a"));
maxHeap.insert(new serial("ba"));
maxHeap.print();
}
}
(I insert Strings and return a sorted array based on numbers)
I ran the program, and it returns a Null Pointer Exception (to the insert function, it is written in the code where).
for some reason, it says that: (in the Heap class)
private serial[] data;
was never used.
In the heap constructor I initialized the instance variable again.
Thanks to Seelenvirtuose
Related
I'm sitting on an assignment for university and I'm at a point, where I fear I haven't really understood something fundamental in the concecpt of Java or OOP altogether. I'll try to make it as short as possible (maybe it's sufficient to just look at the 3rd code segment, but I just wanted to make sure, I included enough detail). I am to write a little employee management. One class within this project is the employeeManagement itself and this class should possess a method for sorting employees by first letter via bubblesort.
I have written 3 classes for this: The first one is "Employee", which contains a name and an ID (a running number) , getter and setter methods and one method for checking whether the first letter of one employee is smaller (lower in the alphabet) than the other. It looks like this:
static boolean isSmaller(Employee source, Employee target) {
char[] sourceArray = new char[source.name.length()];
char[] targetArray = new char[target.name.length()];
sourceArray = source.name.toCharArray();
targetArray = target.name.toCharArray();
if(sourceArray[0] < targetArray[0])
return true;
else
return false;
}
I tested it and it seems to work for my case. Now there's another class called EmployeeList and it manages the employees via an array of employees ("Employee" objects). The size of this array is determined via constructor. My code looks like this:
public class EmployeeList {
/*attributes*/
private int size;
private Employee[] employeeArray;
/* constructor */
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
}
/* methods */
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/* adds employee to end of the list. Returns false, if list is too small */
boolean add(Employee m) {
int id = m.getID();
if (id > employeeArray.length) {
return false;
} else {
employeeArray[id] = m;
return true;
}
}
/* returns employee at certain position */
Employee get(int index) {
return employeeArray[index];
}
/* Sets employee at certain position. Returns null, if position doesn't exist. Else returns old value. */
Employee set(int index, Employee m) {
if (employeeArray[index] == null) {
return null;
} else {
Employee before = employeeArray[index];
employeeArray[index] = m;
return before;
}
}
Now comes my real problem: In a third class called "employeeManagement" I am supposed to implement the sorting algorithm. The class looks like this:
public class EmployeeManagement {
private EmployeeList ml = new EmployeeList(3);
public boolean addEmployee(Employee e) {
return ml.add(e);
}
public void sortEmployee() {
System.out.println(ml.getSize()); // I wrote this for debugging, exactly here lies my problem
for (int n = ml.getSize(); n > 1; n--) {
for (int i = 0; i < n - 1; i++) {
if (Employee.isSmaller(ml.get(i), ml.get(i + 1)) == false) {
Employee old = ml.set(i, ml.get(i + 1));
ml.set(i+1, old);
}
}
}
}
The "println" before my comment returns "0" in console... I am expecting "3" as this is the size I gave the "EmployeeList" as parameter of the constructor within my "EmployeeManagement" class. Where is my mistake ? And how can I access the size of the object I created in the "EmployeeManagement" class (the "3") ? I'm really looking forward to your answers!
Thanks,
Phreneticus
You are not storing size in your constructor. Something like,
public EmployeeList(int size) {
this.employeeArray = new Employee[size];
this.size = size; // <-- add this.
}
Also, setSize isn't going to automatically copy (and grow) the array. You will need to copy the array, because Java arrays have a fixed length. Finally, you don't really need size here since employeeArray has a length.
The size variable you are calling is the class field. If you take a quick look at your code, the getter is getting the field (which is initialized as zero when created). The size you are using it. The good way of doing it would be to get the size of the array in the getter like this:
public int getSize() {
return employeeArray.length;
}
This would return the size of the array in the object.
I read some material about Java memory leak. It implements FIFO Queue with array to semantically leak memory. But I don't understand why it will cause memory leak. Is it because it didn't nullify the unused slot in the 'pop' operation? Anyone can explain to me?
queue[head] = null
The FIFO Queue implementation is as follows:
public class FIFOQueue {
private Object[] queue;
private int size = 0, head = 0, tail = 0;
private static final int INITIAL_CAPACITY = 16;
public FIFOQueue() {
queue = new Object[INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
queue[tail] = e;
size++;
tail = increment(tail);
}
public Object pop() throws EmptyStackException {
if (size == 0)
throw new EmptyStackException();
size–;
Object returnValue = queue[head];
head = increment(head);
return returnValue;
}
/** doubling the capacity each time the array needs to grow. */
private void ensureCapacity() {
if (queue.length == size)
queue = Arrays.copyOf(queue, 2 * size + 1);
}
/** make sure the pointers are wrapped around at the end of the array */
private int increment( int x ) {
if( ++x == queue.length )
x = 0;
return x;
}
}
You answered your own Question:)
Since you don't clean queue reference Garbage Collector, can't clean it from memory, because you have valid reference to this Object in your FIFOQueue. That way you pollute your memory with unused Objects, reducing memory effectively available to your program.
Also as pointed in comments, your ensureCapasity function will only work, when the tail is at the end of an array, otherwise you'll be loosing elements in your queue on push, this is more critical then queue[head] reference problem.
This is a class I've written and it feels 'clunky', like there should be a better way to set this up without needing the extra method setList() to instantiate the array. I'm trying to only leave in the parts relevant to my question, as well as an example of what I did the first time that threw a runtime (not compiletime) error. I'm still mostly used to interpreted languages, so the stricter rules of Java are taking some getting used to.
public class Numbersplode
{
// fields
private int before;
private int goal;
private int[] processed;
// constructors
Numbersplode(int begin, int finish)
{
this.before = begin;
this.goal = finish;
this.processed = this.setList(begin);
this.transList();
}
// mutators
private int[] setList(int begin)
{
int[] result = new int[begin];
return result;
}
public void transList()
{
// transforms the list
int count;
double temp;
for (count = 0; count < this.before; count++)
{
temp = (double)count/(double)this.before * (double)this.goal;
this.processed[count] = (int)temp;
}
}
}
It seems like I should be able to avoid having the setList() method, but when I tried this (everything else the same):
public class Numbersplode
{
// fields
private int before;
private int goal;
private int[] processed = new int[before];
// constructors
Numbersplode(int begin, int finish)
{
this.before = begin;
this.goal = finish;
this.transList();
}
[..............]
I receive java.lang.ArrayIndexOutOfBoundsException: 0 since processed[] apparently can't be defined that way.
That extra class seems to solve the problem, but it seems to me that the Constructor should define those variables all at the same time of object creation, thus allowing for the array processed to be defined at the same time in that way.
So is there a more elegant solution I'm missing? If I find one before this is solved I'll post it up here.
EDIT
Just to be clear, if I compile the class (or even a program that creates an object from that class) I don't have any problems until I actually run the program (thus the runtime problem vs compiletime, but wanted to be clear)
And why even have a setList() method -- a private(?) mutator. Why not simply set processed = new int[before] in your constructor?
Numbersplode(int before, int goal) {
this.before = before;
this.goal = goal;
processed = new int[before];
transList();
}
I recently came across a very stupid (at least from my point of view) implementation inside Androids Parcel class.
Suppose I have a simple class like this
class Foo implements Parcelable{
private String[] bars;
//other members
public in describeContents(){
return 0;
}
public void writeToParcel(Parcel dest, int flags){
dest.writeStringArray(bars);
//parcel others
}
private Foo(Parcel source){
source.readStringArray(bars);
//unparcel other members
}
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>(){
public Foo createFromParcel(Parcel source){
return new Foo(source);
}
public Foo[] newArray(int size){
return new Foo[size];
}
};
}
Now, if I want to Parcel a Foo Object and bars is null I see no way to recover from this situation (exept of catching Exceptions of course). Here is the implementation of these two methods from Parcel:
public final void writeStringArray(String[] val) {
if (val != null) {
int N = val.length;
writeInt(N);
for (int i=0; i<N; i++) {
writeString(val[i]);
}
} else {
writeInt(-1);
}
}
public final void readStringArray(String[] val) {
int N = readInt();
if (N == val.length) {
for (int i=0; i<N; i++) {
val[i] = readString();
}
} else {
throw new RuntimeException("bad array lengths");
}
}
So writeStringArray is fine if I pass bars which are null. It just writes -1 to the Parcel. But How is the method readStringArray supposed to get used? If I pass bars inside (which of course is null) I will get a NullPointerException from val.length. If I create bars before like say bars = new String[???] I don't get any clue how big it should be. If the size doesn't match what was written inside I recieve a RuntimeException.
Why is readStringArray not aware of a result of -1 which gets written on null objects from writeStringArray and just returns?
The only way I see is to save the size of bars before I call writeStringArray(String[]) which makes this method kind of useless. It will also redundatly save the size of the Array twice (one time for me to remember, the second time from writeStringArray).
Does anyone know how these two methods are supposed to be used, as there is NO java-doc for them on top?
You should use Parcel.createStringArray() in your case.
I can't imagine a proper use-case for Parcel.readStringArray(String[] val) but in order to use it you have to know the exact size of array and manually allocate it.
It's not really clear from the (lack of) documentation but readStringArray() is to be used when the object already knows how to create the string array before calling this function; for example when it's statistically instanciated or it's size is known from another previously read value.
What you need here is to call the function createStringArray() instead.
Ok, here is the code and then the discussion follows:
public class FlatArrayList {
private static ArrayList<TestWrapperObject> probModel = new ArrayList<TestWrapperObject>();
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] currentRow = new int[10];
int counter = 0;
while (true) {
for (int i = 0; i < 10; i++) {
currentRow[i] = probModel.size();
}
TestWrapperObject currentWO = new TestWrapperObject(currentRow);
probModel.add(counter, currentWO);
TestWrapperObject testWO = probModel.get(counter);
// System.out.println(testWO);
counter++;
if (probModel.size() == 10) break;
}
// Output the whole ArrayList
for (TestWrapperObject wo:probModel) {
int [] currentTestRow = wo.getCurrentRow();
}
}
}
public class TestWrapperObject {
private int [] currentRow;
public void setCurrentRow(int [] currentRow) {
this.currentRow = currentRow;
}
public int [] getCurrentRow() {
return this.currentRow;
}
public TestWrapperObject(int [] currentRow) {
this.currentRow = currentRow;
}
}
What is the above code supposed to do? What I am trying to do is load an array as a member of some wrapper object (TestWrapperObject in our case). When I get out of the loop,
the probModel ArrayList has the number of elements it is supposed to have but all have the same value of the last element (an array of size 10 with each item equal to 9). This is not the case inside the loop. If you perform the same "experiment" with a primitive int value everything works fine. Am I missing something myself regarding arrays as object members? Or did I just encounter a Java bug? I am using Java 6.
You are only creating one instance of the currentRow array. Move that inside the row loop and it should behave more like you expect.
Specifically, the assignment in setCurrentRow does not create a copy of the object, but only assigns the reference. So each copy of your wrapper object will hold a reference to the same int[] array. Changing the values in that array will make the values appear to change for all other wrapper objects that hold a reference to the same instance of the array.
i don' t want to sound condescending, but always try to remember tip #26 from the excellent pragmatic programmer book
select isn't broken
it is very rare to find a java bug. keeping this in mind often helps me to look over my code again, turn it around, and shake out the loose bits until i finally discover where i was wrong. of course asking for help early enough is very encouraged, too :)