I am new to using arrays of objects but can't figure out what I am doing wrong and why I keep getting a Null pointer exception. I am trying to create an Theatre class with an array of spotlight objects that are either set to on or off. But - whenever I call on this array I get a null pointer exception.
package theatreLights;
public class TheatreSpotlightApp {
public static void main(String[] args) {
Theatre theTheatre = new Theatre(8);
System.out.println("element 5 " + theTheatre.arrayOfSpotlights[5].toString());
}
}
package theatreLights;
public class Theatre {
spotlight[] arrayOfSpotlights;
public Theatre(int N){
arrayOfSpotlights = new spotlight[N];
for (int i = 0; i < arrayOfSpotlights.length; i++) {
arrayOfSpotlights[i].turnOn();
}
}
}
package theatreLights;
public class spotlight {
int state;
public spotlight(){
state = 0;
}
public void turnOn(){
state = 1;
}
void turnOff(){
state = 0;
}
public String toString(){
String stringState = "";
if(state == 0){
stringState = "is off";
}
else if(state==1){
stringState = "is on";
}
return stringState;
}
}
I must be doing something basic wrong in creating the array but can't figure it out.
replace
arrayOfSpotlights[i].turnOn();
with
arrayOfSpotLights[i] = new Spotlight();
arrayOfSpotlights[i].turnOn();
The line
arrayOfSpotlights = new spotlight[N];
will create an array of spotlights. It will however not populate this array with spotlights.
When you do "arrayOfSpotlights = new spotlight[N];" you init an array of length N, what you need to do is also init each object in it:
for i=0; i<N; i++
arrayOfSpotlights[i] = new spotlight();
arrayOfSpotlights[i].turnOn();
Hope I'm correct :)
You are not creating an spotlight objects.
arrayOfSpotlights = new spotlight[N];
This just creates an array of references to spotlights, not the objects which are referenced.
The simple solution is
for (int i = 0; i < arrayOfSpotlights.length; i++) {
arrayOfSpotlights[i] = new spotlight();
arrayOfSpotlights[i].turnOn();
}
BTW You should use TitleCase for class names.
You could write your class like this, without using cryptic code like 0 and 1
public class Spotlight {
private String state;
public Spotlight() {
turnOff();
}
public void turnOn() {
state = "on";
}
void turnOff() {
state = "off";
}
public String toString() {
return "is " + state;
}
}
You declared the array arrayOfSpotlights, but didn't initialize the members of the array (so they are null - and you get the exception).
Change it to:
public class Theatre {
spotlight[] arrayOfSpotlights;
public Theatre(int N){
arrayOfSpotlights = new spotlight[N];
for (int i = 0; i < arrayOfSpotlights.length; i++) {
arrayOfSpotlights[i]=new spotlight();
arrayOfSpotlights[i].turnOn();
}
}
}
and it should work.
Related
So I'm currently working on a project that is recreating methods for Array String Lists and Linked String Lists. There is a StringList interface, that both ArrayStringList and LinkedStringList implement. We are not allowed to see the source code for the interface - only the API documentation. For each class, we have to create a default constructor and copy constructor for both classes. I've ran tests, and the default constructors both pass but the ArrayStringList copy constructor does not work and has been throwing the error message of "null" or "-1". I am pretty new to inheritance and interfaces, and I think the object parameters vs string array data types are throwing me off a bit.
Here is the code I have so far, and the methods used in the constructor:
My Copy Constructor:
private String[] stringArray;
private int size;
public ArrayStringList(StringList sl) {
size = sl.size();
ArrayStringList asl = new ArrayStringList();
for(int i = 0; i < size-1; i++) {
if(sl.get(i) != null) {
asl.set(i,sl.get(i).toString());
} //if
} // for
} // copy constructor
Size Method:
public int size() {
return stringArray.length;
} // size
Get Method:
public String get(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException("out of bounds");
} else {
return stringArray[index];
}
} //get
Set Method:
public String set(int index, String s) {
String old = stringArray[index];
stringArray[index] = s;
return old;
} // set
In the project, the description of the copy constructor was as follows:
The implementing class must explicitly define a copy constructor. The copy constructor should take exactly one parameter of the interface type StringList. It should make the newly constructed list object a deep copy of the list referred to by the constructor's parameter. Therefore, the initial size and string elements of the new list object will be the same as the other list. To be clear, the other list can be an object of any implementation of the StringList interface. No other assumptions about the type of the object should be made.
public class ArrayStringList implements StringList {
private static final int INITIAL_CAPACITY = 10;
private String[] stringArray;
private int size;
public ArrayStringList(StringList sl) {
stringArray = sl.toArray();
size = stringArray.length;
}
public ArrayStringList() {
stringArray = new String[INITIAL_CAPACITY];
size = 0;
}
// TODO: Extract 'if-cascade' to an validate(..) method
#Override
public String set(int index, String s) {
if (index >= size) {
throw new IndexOutOfBoundsException("")
} else if (s == null) {
throw new NullPointerException("the specified string is null");
} else if (s.isEmpty()) {
throw new IllegalArgumentException("specified string is empty");
}
String old = stringArray[index];
stringArray[index] = s;
return old;
}
// TODO: Check if posible to extend the stringArray
#Override
public boolean add(String s) {
if (s == null) {
throw new NullPointerException("the specified string is null");
} else if (s.isEmpty()) {
throw new IllegalArgumentException("specified string is empty");
}
if (size == stringArray.length) {
int newListCapacity = stringArray.length * 2;
stringArray = Arrays.copyOf(stringArray, newListCapacity);
}
stringArray[++size] = s;
return true;
}
// TODO: implement other methods ...
}
Keep in mind that this implementation is still buggy, but you can use it as a starting point
public void ArrayStringList(StringList sl) {
size = sl.size();
ArrayStringList asl = new ArrayStringList();
for(int i = 0; i < size; i++) {
if(sl.get(i) != null) {
String s = asl.set(i,sl.get(i).toString());
System.out.println(s);
} //if
} // for
}
Change set method like below. And call it by the help of class object. it will set value in global static list.
//Change set method like this
public String set(int index, String s) {
stringArray[index] = s;
return stringArray[index];
}
I would initialise the internal array to the value of size and also make use of the fact that the String class also has a copy-constructor
public ArrayStringList(StringList sl) {
this.size = sl.size();
this.stringArray = new String[size];
for(int j = 0; j < size; j++) {
this.stringArray[j] = new String(sl.get(i));
}
}
For my project I need to add a Creature into an array of creatures thats created in a room
public class Room
{
String name;
String description;
String state;
Creature [] creatures = new Creature[10];
public Room(String roomName)
{
name = roomName;
}
public String toString()
{
String retValue = "";
for (int i = 0; i < creatures.length; i++) {
retValue = retValue + creatures[i].toString();
}
return retValue;
}
public void addCreature(String creatureName)
{
for (int i = 0; i < creatures.length; i++)
{
if(creatures[i] == null)
{
creatures[i] = new Creature(creatureName);
}
}
}
}
when I do this, it overwrites the entire array, what can I do to add a single creature to the array?
Use break statement.
if(creatures[i] == null)
{
creatures[i] = new Creature(creatureName);
break;
}
Arrays have only a fixed size. When you write new Creatures[10], it means that your creatures array has at maximum 10 elements inside of it.
You can add items in two different ways:
You can copy the array and make it bigger, and then add the item
You can use ArrayList, which is a class which automatically does #1 for you
I would recommend ArrayList:
ArrayList:
List<Creature> creatures = new ArrayList<>();
public void addCreature(String creatureName) {
creatures.add(new Creature(creatureName));
}
Seems you miss one condition in if clause. I guess it should be
if(current == null || current.getCreatureName() == null) {
creatures[i] = new Creature(creatureName);
}
I am working to create a "basic" UI connect4 game. I am having trouble figuring out why when I call to print the "board", I am getting null, in return. Have I not initialize the array? If so, how do I do so? ~Thanks
My constructor...
public class Connect4{
private String game[][];
public Conncet4(String game[][]){
this.game = game;
}
with one of my methods...
public void dropChipX(int colm){
for(int i = 0; i<game.length;i++) {
for(int j = 0; j<game[0].length;j++) {
if( j%2 == 0 )
game[game.length-1][col] = "|";
else
game[i][j] = " ";
}
}
if(game[game.length-1][colm] == " ")
game[game.length-1][colm] = "X";
else
game[(game.length-1)-count][col] = "X";
count++;
}
I also have a toString to print out the array
public String toString() {
String result = "";
for(int i = 0; i<game.length;i++) {
for(int j = 0; j<game[0].length;j++)
result = (game[i][j]);
result += "\n";
}
return result;
}
The thing I am having trouble with is that when I do run my main, its returning null
public class Connect4TextConsole {
public static void main(String[] args) {
String fun[][] = new String[6][15];
Connect4 connect = new Connect4(fun);
connect.dropChipX(3);
System.out.print(connect);
connect.dropChipY(2);
System.out.print(connect);
}
}
I would advise you to reconsider this code:
public class Connect4{
private String game[][];
public Conncet4(String game[][]){
this.game = game;
}
}
You should make a defensive copy of that 2D array inside the constructor.
Any code that gave you the reference to the game 2D array that's passed to the constructor can modify that mutable reference. Your private designation means nothing.
I discovered what i think is a bug whilst using netbeans. When i call up my method to sort an array containing names(ob.sort) in alphabetical order it automatically sorts another array which contains the original names when it isn't supposed to as the original names is not assigned to anything after it has been populated with input at the beginning(ob.input).
I experienced this problem whilst writing larger programs(encountered more than once), but i made a simpler one to demonstrate this problem. It looks like much as i copied the class methods an pasted it below the main class making it easier for you to trace the variables in the program.
public static void main(String args[]){
ObjectTest ob = new ObjectTest();
ob.input();
String x[] = ob.getNames();
System.out.println(x[0]);
ob = new ObjectTest(x);
System.out.println(x[0]);
ob.sort();
System.out.println(x[0]);
String y[] = ob.getNamesrt();
System.out.println(x[0]);
}
}
/*import java.io.*;
import javax.swing.*;
public class ObjectTest {
String name[];
String namesrt[];
public ObjectTest(){
name = new String[3];
namesrt = new String[3];
}
public ObjectTest(String j[]){
namesrt = j;
}
public void input(){
for(int i = 0; i < name.length; i++){
name[i] = JOptionPane.showInputDialog("Enter name");
}
}
public void sort(){
if(!(namesrt == null)){
for(int i = 0; i < namesrt.length; i++){
for(int c = i + 1; c < namesrt.length; c++){
if(namesrt[i].compareToIgnoreCase(namesrt[c]) > 0){
String n = namesrt[i];
namesrt[i] = namesrt[c];
namesrt[c] = n;
}
}
}
}
else{JOptionPane.showMessageDialog(null,"Names not received");}
}
public String[] getNames(){
return name;
}
public String[] getNamesrt(){
return namesrt;
}
public void setNames(String j[]){
name = j;
}
public void setNamesrt(String j[]){
namesrt = j;
}
}*/
I discovered what i think is a bug whilst using netbeans.
Well, it may be a bug in your code. It's not a bug in Java or in Netbeans. It's just demonstrating the fact that arrays are reference types in Java, and the way that objects work.
Here's a short but complete program demonstrating the same effect:
public class Test {
public static void main(String[] args) {
String[] x = { "hello" };
// Copy the *reference*
String[] y = x;
System.out.println(y[0]); // Prints "hello"
x[0] = "new value";
System.out.println(y[0]); // Prints "new value"
}
}
The values of x and y here are references to the same array object... so if the array is changed "through" x, that change is still visible as y[0].
If you want to make your code create independent objects, you'll want to change this:
public ObjectTest(String j[]){
namesrt = j;
}
to:
public ObjectTest(String j[]){
namesrt = j.clone();
}
(Ideally change it to declare the parameter as String[] j, or better yet fix all your variable names to be more meaningful, but that's a different matter.)
I am making a program for airplane seating arrangements for a class and i ended up making two toString methods but when I run the program the toString method in my airplane class is making something not work specifically:
str= str + seats[i][j].toString();
I believe that simply deleting the toString method in the seat class and somehow putting it back into the airplane class toString method would fix the problem or make it simpler. What's wrong?
Airplane class:
public class Airplane
{
private Seat [ ] [ ] seats;
public static final int FIRST_CLASS = 1;
public static final int ECONOMY = 2;
private static final int FC_ROWS = 5;
private static final int FC_COLS = 4;
private static final int ECONOMY_ROWS = 5;
private static final int ECONOMY_COLS = 6;
public Airplane()
{
seats = new Seat[FC_ROWS][ECONOMY_COLS];
}
public String toString()
{
String str = "";
for (int i=0; i<FC_ROWS; i++) {
for (int j=0; j<ECONOMY_COLS; j++)
{
str= str + seats[i][j].toString();
}
str = str + "\n";
}
return str;
}
}
Seat Class:
public class Seat
{
private int seatType;
private boolean isReserved;
public static final int WINDOW = 1;
public static final int AISLE = 2;
public static final int CENTER = 3;
public Seat(int inSeatType)
{
seatType = inSeatType;
isReserved = false;
}
public int getSeatType()
{
return seatType;
}
public void reserveSeat()
{
isReserved = true;
}
public boolean isAvailable()
{
if (!isReserved)
{
return true;
}
else return false;
}
public String toString()
{
if(isReserved == false)
{
return "*";
}
else return "";
}
}
In Seat.toString you should print a " " not "".
You're array is FC_ROWS by ECONOMY_COLS, so you're not creating all the seats. You should probably have two arrays (one for FC, one for Economy), since FC_ROWS != ECONOMY_ROWS.
You aren't actually creating Seats in your constructor. Use a nested loop to create them, otherwise you will get a NullPointerException. Creating an array doesn't create the objects contained in the array.
When you're creating the seats in the Airplane constructor, use if statements to figure out if the seat is supposed to be a Window, Aisle, etc.
seats seems to does not have Seat's instance.
Add this code :
for (int i=0; i<FC_ROWS; i++) {
for (int j=0; j<ECONOMY_COLS; j++)
{
seats[i][j] = new Seat();
}
}
below this :
seats = new Seat[FC_ROWS][ECONOMY_COLS];
I think that in Seat::toString, you mean to return " " (a space) if it isn't reserved.