I'm trying to make a Grid Class to use in a Sketch I want to make (I'm using Processing) but I get a NullPointerException when trying to access the grid variable from a method printGrid() of the Grid Class.
Code:
Grid_Proj:
Grid gridObj;
void setup() {
size(480, 360);
background(0);
gridObj = new Grid(10, 10);
gridObj.printGrid();
}
Grid:
class Grid {
int[][] grid; // Declare the Grid
Grid(int size_x, int size_y) {
int grid[][] = new int[size_x][size_y]; // Initialize the Grid
for (int x=0;x<size_x;x++) {
for (int y=0;y<size_y;y++) {
grid[x][y] = 0;
}
}
println("Created Grid Object with: ", size_x, size_y);
}
void printGrid() {
for (int x=0;x<10;x++) {
for (int y=0;y<10;y++) {
print(grid[x][y]); // NPE Error here
}
print('\n');
}
}
}
I'm obviously doing something wrong here, but I can't figure out what.
I also tried using
this.grid[x][y]
to no avail.
int grid[][] = new int[size_x][size_y];
You are declaring a new local grid variable here, not initializing the field. Therefore, the grid field remains null and you receive an NPE when you try to index it. Try this instead:
grid = new int[size_x][size_y]; // use the field `grid`
As an aside, it's recommended in Java to put the [] of array declarations directly after the array type:
int[][] grid // good
int grid[][] // bad
You do this correctly when declaring the field, but not in the local variable declaration.
In your constructor, you're initializing grid as a method-scoped variable, so you're never assigning any value to your instance field.
That's why you're instance method printGrid, which does reference the instance field, throws a NullPointerException.
Just remove int from the assignment in the constructor.
It's because in your constructor, you create a local grid array. Just don't create the local variable and you should be fine:
public Grid(int size_x, int size_y) {
this.grid = new int[size_x][size_y];
for (int x=0;x<size_x;x++) {
for (int y=0;y<size_y;y++) {
this.grid[x][y] = 0;
}
}
}
Related
I'm trying to create a method which will create an object which contains a 2D boolean array, with int parameters as the number of rows and columns. Then inside the class, I have methods that try to grab the length and width of that array. The two ways I tried to solve this problem were:
public GameOfLife(int rows, int cols) {
boolean[][] society = new boolean[rows][cols];
}
public int numberOfRows() {
return society.length;
}
In my tests, this attempt was giving me the error that society cannot be resolved to a variable. Then I tried:
private boolean[][] society;
public GameOfLife(int rows, int cols) {
boolean[][] temp = new boolean[rows][cols];
society = temp;
}
EDIT: Oops, forgot to add my method for numberOfColumns:
public int numberOfColumns() {
return cols;
}
But the issue with this one was that it was returning 0 instead of 4 when I tried:
#Test
public void FailedTestingRowsAndCols(){
GameOfLife g1 = new GameOfLife(4,4);
assertEquals(4, g1.numberOfColumns());
}
I'm rather new to this, so I apologize if this is a dumb question, but I'm not really sure about all the details of where and when variables expire, which is giving me a lot of difficulties. THank you for any help!
When I create a 2D array outside of my constructor, I'm not able to resize it, but when I create one inside of it, I'm not able to access it
Take note that you will never be able to resize an array. An array once created has its size fixed. You are merely assigning your current array to reference to another newly created array (which gives you the illusion that you successfully resized it).
As for your question of not being able to access it is highly likely the variable you created exist within different scope.
You can use the following codes (which is very similar to yours), it works fine for me. Hence I am guessing your error does not actually comes from the code snippet you showed.
class TestRunner
{
public static void main(String[] args){
GameOfLife gol = new GameOfLife(5, 3);
System.out.println(gol.getColumns());
System.out.println(gol.getRows());
}
}
class GameOfLife
{
private boolean[][] society;
public GameOfLife(int rows, int cols){
society = new boolean[rows][cols];
}
public int getColumns(){
return society[0].length;
}
public int getRows(){
return society.length;
}
}
Output:
5
3
I don't see any problems with what you have posted so far. The below example works fine for me:
public class GameOfLife {
public static void main(String[] args) {
GameOfLife g1 = new GameOfLife(4,4);
System.out.println(g1);
}
private boolean[][] society;
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("GameOfLife{");
sb.append("society=").append(society == null ? "null" : Arrays.deepToString(society));
sb.append('}');
return sb.toString();
}
public GameOfLife(int rows, int cols) {
boolean[][] temp = new boolean[rows][cols];
society = temp;
}
}
So pretty much I'm making an array of obvjects called Spots which symbolise the different faces of a dice.
It takes user input (manually set to three for this example), and then creates that make Spots and rolls a random number from 1 to 6.
However when I go to use the rollAgain() method on the aleady created array of Spots I get a null pointer even though I am using the same variable length in both for loops (the one that creates and one that rolls the spots).
My code
Global Variables
private Spots[] spots;
private int x = 3;
Contructor
public Director(JFrame window, String args[]) {
JMenuBar menus = new JMenuBar();
window.setJMenuBar(menus);
menus.add(makeFileMenu());
window.getContentPane().add(makePanel(), BorderLayout.WEST);
window.getContentPane().add(makeSpots(x), BorderLayout.CENTER);
rollAgain();
}
rollAgain() method
public void rollAgain() {
int v = 1 + (int) (Math.random() * 6);
for (int i = 0; i < x; i++) {
spots[i].setValue(v);
}
}
makeSpots() method
private JComponent makeSpots(int x) {
JPanel p = new JPanel();
p.setBorder(BorderFactory.createTitledBorder("Dice"));
Spots[] spots = new Spots[x];
for (int i = 0; i < x; i++) {
spots[i] = new Spots(200, 200);
spots[i].setBorder(BorderFactory.createEtchedBorder());
p.add(spots[i]);
}
return p;
}
You are setting a local variable
Spots[] spots = new Spots[x];
This doesn't change the field (which happens to have the same name)
private Spots[] spots;
The simplest solution is to not have a local variable
this.spots = new Spots[x];
You need to instantiate a new Spots array in your constructor.
this.spots = new Spots[x];
spots[i].setValue(v);
Judging from this line, my guess is that the Spot object in the array in null.
The error is in your makeSpots() method. You don't update the value of the field x, but use a local variable. Add this.x = x at the beginning of the method.
In your makeSpots() method, you are creating a new Spots object called spots:
Spots[] spots = new Spots[x];
This effectively hides your private member variable spots from the method. Instead, do this in your makeSpots() method:
spots = new Spots[x];
You are declaring a global 'spots' array and then in the makeSpots() you create the spots with a local variable also named 'spots'. Just substitute
Spots[] spots = new Spots[x];
by
spots = new Spots[x];
so the global variable gets a value.
How do I make a value global?
For example I have a few lines of code here
public class A
{
int number;
JLabel[] l = new JLabel[number]; // Problem is at here because the number
public A( int num )
{
number = num; // Receive the value from previous file
}
}
Problem is at the line where I state in the commnet.
As far as I know, the number doesn't passed on to creation of JLabel. Is there anyway for me to pass the value taken from previous file to the creation of JLabel?
I need to create the JLabel globally because I need to access it at the public void actionPerformed(ActionEvent e).
If I create it inside the method I couldn't access at the public void actionPerformed(ActionEvent e) or is there anyway I could access the JLabel I creatd in a method?
Just leave the top line as JLabel[] l; and add l = new JLabel[number]; in your constructor. The problem is that your code as is will try to access number before calling the constructor, so it is not yet set.
When you are creating your class, you declare int variable, which is not initialised, and then you go on to create JLabel array using this variable. To solve this, you can initialize number in your constructor, and also there, create your JLabel, like so:
public class A
{
int number;
JLabel[] l;
public A( int num )
{
number = num; // Receive the value from previous file
l = new JLabel[number]
}
}
I want to create a 2D Array that creates a mini seating chart of an airplane. So far, I've gotten it to successfully print out something that looks like this:
1A(0) || 1B(0) || 1C(0)
2A(0) || 2B(0) || 2C(0)
3A(0) || 3B(0) || 3C(0)
4A(0) || 4B(0) || 4C(0)
The zeroes represent an empty seat, and the number one is used to represent an occupied seat.
I first created the program with arrays that were class variables for a First Class, but I wanted to make this program usable for an Economy Class section. The only difference between the two sections is the size of the array so I edited my code to look like this:
public class Seating
{
private int FIRSTCLASS= 12;
private int ECONOMYCLASS= 240;
private int occupied, column;
private String[][] seatchart;
private int[][] seatlist;
private String[][] namelist;
private String name;
public String customer;
public Seating(String seatclass)
{
seatclass.toUpperCase();
if (seatclass.equals("FIRSTCLASS"))
{
seatchart= new String[FIRSTCLASS/3][3];
seatlist= new int[FIRSTCLASS/3][3];
namelist= new String[FIRSTCLASS/3][3];
}
else
if (seatclass.equals("ECONOMY"))
{
seatchart= new String[ECONOMYCLASS/3][3];
seatlist= new int[ECONOMYCLASS/3][3];
namelist= new String[ECONOMYCLASS/3][3];
}
}
public void Creation()
{
for (int i=0; i< seatlist.length; i++)
{
for (int j=0; j<seatlist[i].length; j++)
{
seatlist[i][j]= 0 ;
}
}
I get an null pointer exception error around for (int i=0; i< seatlist.length; i++)
How can I fix this error?
Thanks in advance!
The problem is with this line:
seatclass.toUpperCase();
Replace it with:
seatclass = seatclass.toUpperCase();
I think you are creating the class with a string like "firstclass" rather than "FIRSTCLASS" right? Those aren't the same strings and just invoking the toUpperCase method on the string without assigning the result to a variable to then be tested means nothing happens.
Then since none of your if conditions are met, the arrays are not initialized and a null pointer exception is thrown when Completion() is called.
I'm not sure if you are new to java programming, but I wanted to add a few recommendations to your class:
public class Seating {
private static int FIRSTCLASS= 12; // Make these constants static since they pertain to all
private static int ECONOMYCLASS= 240; // instances of your class. That way there is exactly on
// copy of the variables, which is more memory efficient.
private int occupied;
private column; // Okay but Java convention is to declare each member variable on its own line
// increases code readability.
private String[][] seatchart;
private int[][] seatlist;
private String[][] namelist;
private String locSeatClass;
private String name;
public String customer; // Okay but better to leave this private and then provide getter and
// setter methods to provide access to this string. Much easier to track
// down who is changing its value in your code.
public Seating(String seatclass) { // Java convention is to place the opening bracket here not
// on the next line.
// Make sure that seatClass is not null or empty. NOTE: This is a neat trick for
// simultaneously checking for both null and empty strings in one shot. Otherwise, you have
// you have to check for null and then examine the string's length which is more code.
if ("".equalsIgnoreCase(seatClass) {
throw new IllegalArgumentException("Seat class undefined.");
}
// Store the seat class in a member variable for use. Could also be a local variable.
// My original solution is problematic because it changes the original value of the seat
// class that was passed into the constructor (you might want that information).
locSeatClass = seatclass.toUpperCase();
if (locSeatClass.equals("FIRSTCLASS"))
{
seatchart= new String[FIRSTCLASS/3][3];
seatlist= new int[FIRSTCLASS/3][3];
namelist= new String[FIRSTCLASS/3][3];
}
else if (locSeatclass.equals("ECONOMY")) {
seatchart= new String[ECONOMYCLASS/3][3];
seatlist= new int[ECONOMYCLASS/3][3];
namelist= new String[ECONOMYCLASS/3][3];
}
else {
// Throw an exception if someone passes in an unknown seat class string.
throw new IllegalArgumentException("Unknown seat class detected.")
}
}
public void creation() { // NOTE: Java convention is to begin method names with a lower
// case letter.
// This method is unnecessary. Arrays of integers are initialized with an initial value
// of zero by default. However, if you want to make your class reusable, you could change
// change the name of the this method to clear, which would allow you to clear the arrays of
// an existing object.
for (int i=0; i< seatlist.length; i++)
{
for (int j=0; j<seatlist[i].length; j++)
{
seatlist[i][j]= 0 ;
}
}
}
The only way that line of code can generate a NPE is if seatlist is null. Unless you assign null to seatlist somewhere else in your class, the only way it can be null is if the argument that you pass to the Seating constructor does not match either "FIRSTCLASS" or "ECONOMY". Check your call to the constructor. Also, you might want to just use seatclass.equalsIgnoreCase().
You should modify your constructor to at least warn about that eventuality, since it is vital to the proper operation of the class that any instances of Seating have valid seatlist and namelist arrays.
I have extended a class in hope to store a global array (make the array within the class be seen by another object) by using the set1sub(sub.local) method
public class BattleShipsClient extends ShipLocations implements Runnable, BattleShipConstants
{
BattleShipsClient()
{
}
public void placeBoard(int player) throws IOException// this is only called once and not updated when clicked again
{
while(getLocations())
{
while(isWaiting())//true
{
toServer.writeInt(player);
int row = getRowSelected();
int col = getColumnSelected();
int choice=Integer.parseInt(JOptionPane.showInputDialog("Please 1 for a sub, 2 for a battleship and 3 for a destroyer"));
clickCount ++;
if(clickCount >2)
{
setLocation(false);
continueToPlay=true;
}
if (choice ==1 &&sub.placed==false)
{
String orientation =JOptionPane.showInputDialog("please enter your orientations");
if(orientation.equalsIgnoreCase("h"))
{
//row os the same
//column number will be sent, then plus one on the other side
sub.local = new int[2][2];
sub.local[0][0] =row;
sub.local[0][1]=col;
sub.local[1][0]=row;
sub.local[1][1] =col+1;
toServer.writeInt(row);
toServer.writeInt(col);
toServer.writeChar('s');
sub.placed=true;
setp1sub(sub.local);
/*setp1sub(new int[][]{{row,col},
{row,col+1}});*/
grid[row][col+1].setToken(getMyToken());
}
I then have a ship Locations class however when i create a new object of the ship locations class and try to read this array it always is set to [[0, 0], [0, 0]], ive tried making it static and atomic
public class ShipLocations {
int [][] p1sub;
public ShipLocations()
{
p1sub = new int[2][2];
}
public int[][] getp1sub()
{
return p1sub;
}
public void setp1sub(int[][] local) {
for (int i = 0;i <local.length;i++)
{
for(int j = 0;j<local.length;j++)
{
p1sub [i][j]= local[i][j];
}
}
}
}
Whenever you create a new instance of ShipLocations(or a subclass) the constructor is called, which in your case, reinitializes the p1sub array.
In your design, you are overusing inheritance. You should not inherit from a class just to use its methods and variables.
To store a global variable in a class:
public class ShipLocations {
static int [][] p1sub;
static{
p1sub = new int[2][2];
}
public static void setp1sub(...){...}
public static int[][] getp1sub(){...}
}
And then use it by class name instead of creating instances:
int [][] x = ShipLocations.getp1sub();
Though the use of global variables shoud be avoided when possible. It is considered bad design and might be a problem when reusing the code.
The correct way of doing this is to have the ShipLocations object as a local variable in BattleShipsClient and set it when initializing new instance. You will then first create a common ShipLocation object and hand it to every client that should see the same array.