This question already has answers here:
Non-static variable cannot be referenced from a static context
(15 answers)
Closed 9 years ago.
I've read the Oracle documents regarding scope and controlling access yet it just isn't sticking, so I'm assuming that my issue comes from my failure to understand... Anyways Here's my code. I'm trying to access the unique Player objects created in an array, and change their unique variables like their balances, using methods from the Player class. Any solutions and ESPECIALLY explanations are welcome!
public class Player
{
private int currentBal;
private String myName;
private int rollOne;
private int rollTwo;
private int rollTotal;
private int doublesCount;
private int currentPosition;
private int currentDoubles;
private int move;
private int moveMult;
private int newBal;
private boolean rollAgain;
private boolean inJail;
public Player(String userName, int changeInMoney)
{
myName = userName;
currentBal -= changeBalance(changeInMoney);
}
public int changeBalance(int changeInMoney){newBal -= changeInMoney; return newBal;}
public int viewBalance(){return currentBal;}
Here is my PlayerArray class.
public class PlayerArray
{
Scanner scan = new Scanner(System.in);
private int numbHuman;
private Player[] arr;
private String[] userName;
private int startingMoney;
public PlayerArray()
{
Scanner scan = new Scanner(System.in);
System.out.println("There will be 4 players, how many do you wish to be human? 0><4");
numbHuman = scan.nextInt();
while (numbHuman < 1 || numbHuman > 4)
{
System.out.println("Invalid entry, try again.");
numbHuman = scan.nextInt();
}
arr = new Player[numbHuman];
userName = new String[numbHuman];
startingMoney = 1500;
for(int i = 0; i < arr.length; i++)
{
System.out.println("Player " + (i + 1) + ", Please enter your first name:");
userName[i] = scan.next();
arr[i] = new Player(userName[i],startingMoney);
}
}
public Player[] getPlayerArray()
{
int charge = 500;
arr[0].changeBalance(charge);
System.out.println(arr[0].viewBalance()); //look here as example
return arr;
}
}
this is my player class, minus some methods I can't use till later. Bellow is my main method to call it,
import java.util.Scanner;
import java.util.Random;
public class Launcher
{
private Planet myTest;
private PlanetInfo myPlanetInfo;
private static Player[] arr;
public static void main(String[] args)
{
Launcher testLauncher = new Launcher();
PlayerArray myArray = new PlayerArray();
Pay myCharge = new Pay(); // continue work on charges
myArray.getPlayerArray();
//STILL TRYING TO GET BELLOW LINE TO WORK LAST NIGHT!!!
int testBal = arr[0].viewBalance(); //ERROR HERE
System.out.println("player 1's balance: " + testBal);
}
}
Error "Java.lang.NullPointerException: null"
Your main method is a static method. It actually exists before any object is created from your class, and thus cannot access instance variables and methods directly. You cannot access non static methods or variables from the same class unless you create an object for the class, i.e Launcher launcher = new Launcher();.
In this case, your player array arr is not static. You either need to make this static or create a Launcher object and access the variable from there. In the latter case, you will need to make the arr array public.
The first option requires you to change your player array declaration to private static Player arr;.
The second requires you to change the access of the arr array to public and access it like so: launcher.arr.
Regarding your second error, you need to either do this: arr = myArray.getPlayerArray();
or just access the array directly like this: myArray.getPlayerArray()[0] (for the first item in that array).
Variable 'Player[] arr' is instance variable, i.e. it should belongs to particular instance. Static method 'main' can't directly access an instance variable from the class it's in, because it doesn't have an explicit reference to any particular instance of the class (simply said at this point, you don't have an instance to whom your Player[] arr belongs).
Make your variables static, since main is a static method, you can't reference non-static methods.
so make your variables on top something like:
private static Player[] arr;
Since your Launcher has no instance none of its non static members exist. Static method main cannot access such - in this case your arr does not exist. You may want to make it static to make it work.
Read static and instance members
Related
I am learning Java, so I understand this is a very simple question, but I still want to understand it.
I want to let my code automatically generate soldiers, and the number automatically increases, but I failed.
the Soldier.class:
package com.mayer;
import java.util.Random;
public class Soldier {
private int number=0;
private int ATK;
private int HP;
Random ra = new Random();
public Soldier(){
this.number++;
this.ATK = ra.nextInt(10)+90;
this.HP = ra.nextInt(20)+180;
}
public void report(){
System.out.println("number:"+this.number+"\t"+
"ATK:"+this.ATK+"\t"+
"HP:"+this.HP);
}
}
the main.class
package com.mayer;
public class Main {
public static void main(String[] args) {
Soldier[] soldiers = new Soldier[5];
int i = 0;
while(i<5){
soldiers[i] = new Soldier();
i++;
}
for(Soldier sol:soldiers){
sol.report();
}
}
}
That's what I get:
number:1 ATK:94 HP:187
number:1 ATK:94 HP:181
number:1 ATK:96 HP:193
number:1 ATK:90 HP:183
number:1 ATK:95 HP:193
So you see,each of this number is 1.
You have added number field which is instance field. It will initialize per instance. You are looking for static type variable. Please check static into java.
Instance Variables (Non-Static Fields) Technically speaking, objects
store their individual states in "non-static fields", that is, fields
declared without the static keyword. Non-static fields are also known
as instance variables because their values are unique to each instance
of a class (to each object, in other words); the currentSpeed of one
bicycle is independent from the currentSpeed of another.
Class Variables (Static Fields) A class variable is any field declared with the static modifier; this tells the compiler that there
is exactly one copy of this variable in existence, regardless of how
many times the class has been instantiated. A field defining the
number of gears for a particular kind of bicycle could be marked as
static since conceptually the same number of gears will apply to all
instances. The code static int numGears = 6; would create such a
static field. Additionally, the keyword final could be added to
indicate that the number of gears will never change.
The constructor is changed to:
public Soldier(int number){
this.number = number;
this.ATK = ra.nextInt(10)+90;
this.HP = ra.nextInt(20)+180;
}
As others have said, each Soldier instance has its own separate number field which starts with 0. You can use a static field to count the instances:
public class Soldier {
private static int counter = 0;
private int number;
// other fields left out for clarity
public Soldier(){
Soldier.counter++; // field shared among all Soldier instances
this.number = counter; // number belongs to this instance only
// ...
}
// ...
}
However, I wouldn't recommend doing it this way. When you get more advanced, you'll learn that using a static field like this can cause problems in a multi-threaded application. I would instead advise passing the number to the Soldier constructor:
public class Soldier {
private int number;
// ...
public Soldier(int number){
this.number = number;
// ...
}
// ...
}
And then:
public static void main(String[] args) {
Soldier[] soldiers = new Soldier[5];
int i = 0;
while(i<5){
soldiers[i] = new Soldier(i);
i++;
}
Soldier.class
all-uppercase field names tend to be used for constants.. basic fields use headless camel-case.. They should also be descriptive, i.e. you should look at them an it should be apparent what they represent - for example a variable "number" is not a good idea, because it's ambiguous
Random can be converted to a local variable, no need to keep it on the class level
The mechanism by which soldiers are assigned IDs should be on a higher level - it can't be managed by the soldier object itself, hence the constructor with an argument
overriding the toString method is the traditional way of transforming the object to string for debugging purposes.. also most IDEs can generate it with a press of a button so no space for human error
You will obviously need getters and setters for your variables, if you wish to read or change them from elsewhere, but I don't think that's necessary to post here.
private int soldierID;
private int attack;
private int health;
public Soldier(int id){
this.soldierID = id;
Random random = new Random();
this.attack = random.nextInt(10) + 90;
this.health = random.nextInt(20) + 180;
}
#Override
public String toString() {
return "Soldier{" +
"soldierID=" + soldierID +
", attack=" + attack +
", health=" + health +
'}';
}
Main.class
it's perfectly fine and actually preferred to use a List instead of an array, because it's more comfortable to work with
this way it's even much easier to add them dynamically and use the iterator for ID
you can "report" in the creation cycle
This even shortens the method a bit, not that it's that important here.
public static void main(String[] args){
List<Soldier> soldiers = new ArrayList<>();
for(int i=0; i<5; i++){
Soldier newSoldier = new Soldier(i);
soldiers.add(newSoldier);
System.out.println(newSoldier.toString());
}
}
This way when you define the soldier IDs it's not from within the Soldier class but rather from something that is "observing" all the soldier classes and knows which is which.
I have a main class "number guess game" but now I need to create an object to get from. I'm trying to add the constructor to the Object class that takes an integer value for the upper limit and uses it to set the upper limit instance variable. Then, generate the number that the user should try to guess and set that instance variable. Finally, initialize the instance variable for the number of guesses to 1.
here is my code
public class NumberGame {
//instance variable
private int upperLimit;
private int number;
private int guess;
//constructor
public NumberGame(int upperLimit){
this.upperLimit = upperLimit;
this.number = number;
this.guess = guess;
}
}
unsure if I am on the right path or need to change my variables or add to the constructor. Still learning about instance variables and constructors any help would be greatly appreciated! thank you!
When you are saying "this.xx" you are referring to the instance variable, when you don't use "this" you are referring to local variables that are getting passed to the constructor. Because you are only passing the upper limit, what you want to do is only set that in the constructor. If the number of guesses always needs to start at "1", you can just initialize it to one in the object class. Lastly,if I'm understanding the question correctly, if you have a method to generate the random number they need to guess, you can call it in your constructor, so you'd end up with something like this:
public class NumberGame {
//instance variable
private int upperLimit;
private int number;
private int guess = 1; //number of guesses to 1
//constructor
public NumberGame(int upperLimit){
this.upperLimit = upperLimit;
this.number = generateNumber() //or some method you are using to generate the number for the user to guess
}
}
I am trying to model the classic water jug problem in AI. I have made a class "JugsState" that stores the current state of two jugs, i.e. how many liter of water is in jug1 and how many liter of water in jug2. In addition, I want to store the maximum amount of water each jug can hold, which I will take from the user as input. Since this(capacity of the two jugs) will be constant throughout , I am declaring them as static final variables. But I am unable to initialize them inside the constructor. Is there any other alternative to this, which maintains the encapsulation of max_jug variables inside the class JugsState?
class JugsState
{
private static final int max_jug1,max_jug2;
private int jug1,jug2; //stores the current amount of water in the jugs.
JugsState(int a1,int a2)
{
max_jug1 = a1;
max_jug2 = a2;
}
}
error: "cannot assign a value to final variable max_jug1"
error: "cannot assign a value to final variable max_jug2"
You can't change a final variable because it is final. However, you can set it to anything you want when it is declared. You can create a static function that gets the maximum for a jar. It could be something like this, if you want to get it from System.in:
private static int getMax(){
System.out.println("Enter the maximum for a jar:");
Scanner in=new Scanner(System.in);
return in.nextInt();
}
Then use
private static final int max_jug1=getMax();
private static final int max_jug2=getMax();
in place of
private static final int max_jug1, max_jug2;
That will set those variables for the rest of the time that the program runs.
If your class represents a jug, it should not hold information about two jugs.
maxAmount or volume should be a non-static member of the class:
public class Jug {
public final double volume;
private double currentAmount = 0;
public Jug(double vol) { volume = vol; }
...
}
If a variable is static, then it would be re-initialized every time the constructor is called. If it is final it can be set only once.
Something close to what you described could be the following (notice the static method setMaxJug1 )
class jug
{
private static int max_jug1,max_jug2;
private int jug1,jug2; //stores the current amount of water in the jugs.
jug(){
// Your constructor stuff
}
public static void setMaxJug1(int m){
max_jug1 = m;
}
}
Then in the main you can call
jug.setMaxJug1(m);
Probably there are other ways of doing what you ask, but I tried not to change too much of your code.
Just to mention, one alternative is to have those variables not static, as in:
class jug
{
private final int max_jug1,max_jug2;
private int jug1,jug2; //stores the current amount of water in the jugs.
jug(int a1,int a2)
{
max_jug1 = a1;
max_jug2 = a2;
}
}
Then you could use your original constructor. However, every jug Object will have (in general) a different value for max_jug1 and max_jug2, depending on the values (a1,a2) you pass in the constructor.
The right choice depends on how you want to use jug objects.
I have 2 classes right now, the first class has the arraylist in it. But on the second class when I try to access the arraylist it keeps giving me the red line underneath saying that the variable doesn't exist.
Here is class one...
public class BankMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
BankMain main = new BankMain();
menu();
}
public static void cardNumbers(){
ArrayList<Integer> cardNum = new ArrayList<Integer>();
Scanner cards = new Scanner(System.in);
Scanner input = new Scanner(System.in);
Scanner keyboard = new Scanner(System.in);
System.out.println("Please select a 5 digit card number");
cardNum.add(input.nextInt());
System.out.println("Thank you! You're card number is " +cardNum);
System.out.println("Type 'c' to go back to main menu.");
String value = keyboard.next();
if(value.equalsIgnoreCase("c")){
menu();
}
else if (!keyboard.equals('c')){
System.out.println("Invalid Entry!");
}
}
public static void menu(){
System.out.println("What Would you like to do today?");
System.out.println();
System.out.println("Create Account = 1");
System.out.println("Login = 2");
System.out.println("Exit = 3");
query();
}
public static void query(){
Scanner keyboard = new Scanner(System.in);
double input = keyboard.nextInt();
if (input == 2){
BankMainPart2 main2 = new BankMainPart2();
System.out.println("Please enter your 5 digit card number.");
main2.loginCard();
}
else if (input == 1){
cardNumbers();
}
else if (input == 3){
System.out.println("Thank you, have a nice day!");
System.exit(0);
}
}
}
Here is the second class...
public class BankMainPart2 {
public static void loginCard(){
if (cardNum.contains(name)) {
}
}
}
I know I haven't entered anything in the if statement yet on the second class but I'm just trying to get my array list to work on both classes.
The code looks very naive. A very simple answer to your question is
You have not declared any cardNum in BankMainPart2 as global variable or in loginCard as local variable, how do you think it will be available in the loginCard method?
ArrayList<Integer> cardNum = new ArrayList<Integer>();
is local to cardNumbers method.
How can you access it from other class?
A local variable cannot be accessed from outside the method, so first thing, make cardNum class level variable
Make the variable public if you want other classes to be able to access it directly, else make the variable private and create getter method (setter if required).
You can also send the variable when calling the method as argument
If this is class level variable, make it static and use Classname.variable.
--Edit--
As you have asked for details let me give you a quick overview of the different approaches.
A variable declared inside a method is local. as name suggest "local", no one but the method knows there is such a variable. No other method in the class knows about existence of this variable, let alone some outside class.
I say you can make it static, but static should strictly be used for class level storage, not object level. Say a list which is modified by multiple objects of the same class (I hope you know concepts of objects, else go to the basics otherwise it will not be clear). Now as per your example, I guess this is not what you want.
A public variable is generally no - no, only in few cases it will be useful (for example in android programming where performance is utmost important). Normally we will create a variable and provide getter setters. A getter or setter is used normally when we want to give access to the variable, which again does not look like what you want.
Last, the variable is private to you class, but if you want some method to do something about it, you can pass it as argument, this looks the case for you.
Step by step
take the variable out of method and add to class level, note that I removed static from method names
public class BankMain {
private ArrayList<Integer> cardNum = new ArrayList<Integer>();
// rest of code as it is
..
..
BankMain main = new BankMain();
//change
main.menu();
//no need foe static
public void cardNumbers(){
//no need here now
//ArrayList<Integer> cardNum = new ArrayList<Integer>();
Scanner cards = new Scanner(System.in);
Scanner input = new Scanner(System.in);
..
..
//public static void menu(){
public void menu(){
//send the list
//I see there are confusion at times regarding calling of static method.
//please note objectname.staticMethod() or classname.staticMethod() is one
//and same thing. Just that classname.staticMethod() is more clear
BankMainPart2.loginCard(cardNum);
}
and
public class BankMainPart2 {
public static void loginCard(ArrayList<Integer> cardNum){
if (cardNum.contains(name)) {
}
}
}
Your method, BankMainPart2.loginCard has not context of "cardNum", it doesn't know what it is (type or value).
In order for the method to be able to act on the array list, you must pass a reference to it, something like...
public class BankMainPart2 {
public static void loginCard(ArrayList<Integer> cardNum){
if (cardNum.contains(name)) {
}
}
}
make the cardnum arraylist as an instance variable in BankMain class and extend BankMain in BankMainClass2 and using reference of BankMain you would be able to access cardNum like this
Class BankMain {
public ArrayList<String> cardNum = new ArrayList<String>();
}
Class BankMain2 extends BankMain {
public void method() {
BankMain2 main = new BankMain2();
sysout(main.cardNum.size());
}
}
but the above scenario would only work when cardNum ArrayList in BankMain class is either marked public,protected or default(Nomodifier). it wouldnt work if its marked as private and other non access modifier such as static and final
You can try any one of these
1.Declare the Arraylist as public then import the first class and use the cardNum in the second class
2.Make the cardNum a static var and use it directly in second class as BankMain.cardNum
3.Pass the Arraylist as argument to the second class.
The key problem is in the the way you are trying to create your classes. Your current problem can be solved by answer given by #MadProgrammer. But you should definitly have a look into the Object Oriented Programming Concepts. This section on How to identify and design a Class? should give you some clear pointers.
So i first declare this object of a class:
static enterprise[] en = new enterprise[10];
Then, inside main:
for(int i=0;i<=9;i++){
System.out.println("Insert name of the " + (i+1) + "ª enterprise");
en[i] = new enterprise(i);
Scanner scanner = new Scanner(System.in);
en[i].setName(scanner.next());
System.out.println(en[i].Name);
}
And then, in another method of the same class:
for(int i = 0; i<=9;i++){
System.out.println(en[i].index + "- " + en[i].Name);
}
So if at first I inserted on the first enterprise A, second B, C,D,E,F,G,H,I,J.. I should get as an output 1 A 2 B etc, but I get 9 J ten times. why does this happen?
Edit: here is the enterprise class: http://pastebin.com/gUCWRRgK
It's because your fields are declared static.
public class enterprise {
static String Name;
static int index;
When a field is static it means that variable is associated with the class. Static variables cannot have different values for each instance.
It should be this:
public class enterprise {
String Name;
int index;
That's because you made your variables static. Remove the static keywords and it'll work. static does not work in Java like it does in C.