I have already done research on this question, and also tried to figure it out by myself but no luck. So I decided to ask it.
Basic info:
There are two classes. FBClient, and State. In FBClient, I have a static variable of it's type, fbc, a StateManager instance, which just has some methods to work with State stuff, some constants and two getters. In State, I am trying to initialize a BufferedImage.
public class FBClient
{
//Static
public static FBClient fbc;
//In init method
private StateManager stateManager;
//Constants
private final int INIT_FRAME_WIDTH = 320, INIT_FRAME_HEIGHT = (INIT_FRAME_WIDTH / 4) * 3, SCALE = 3, FRAME_WIDTH = INIT_FRAME_WIDTH * SCALE, FRAME_HEIGHT = INIT_FRAME_HEIGHT * SCALE;
public static void main(String[] args)
{
try
{
//First call in exception chain:
fbc = new FBClient();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
private FBClient()
throws IOException
{
//Second call in exception chain:
init();
}
private void init()
throws IOException
{
stateManager = new StateManager();
//Third call in exception chain:
stateManager.addState(new MainMenu((byte) 0, "Main Menu")); //MainMenu is the subclass of State, and the constructor just calls "super(0, "Main Menu")"
}
public int getFRAME_HEIGHT()
{
return FRAME_HEIGHT;
}
public int getFRAME_WIDTH()
{
return FRAME_WIDTH;
}
}
public abstract class State
{
protected final byte ID;
protected final String NAME;
protected final BufferedImage SCREEN;
protected final Graphics2D GRAPHICS;
public State(byte id, String name)
{
this.ID = id;
this.NAME = name;
//Exception cause:
this.SCREEN = new BufferedImage(FBClient.fbc.getFRAME_WIDTH(), FBClient.fbc.getFRAME_HEIGHT(), BufferedImage.TYPE_INT_RGB);
this.GRAPHICS = SCREEN.createGraphics();
}
}
More info:
If I put literals in BufferedImage initialization it works.
If I initialize two variables in the State class, assigning them literals and putting those variables in initialization, it works.
If instead of assigning literals to those variables I assign them FBClient.fbc.getFRAME_WIDTH() and FBClient.fbc.getFRAME_HEIGHT(), it throws a NullPointerException.
If I make a System.out.println(getFRAME_WIDTH + " : " + getFRAME_HEIGHT) in FBClient class, it prints out properly, but if I do it in State class (and off course adding FBClient.fbc. before it), it throws a NullPointerException.
If I make FRAME_WIDTH and FRAME_HEIGHT constants public, and I try to access them from State
class by doing FBClient.fbc.FRAME_WIDTH and FRAME_HEIGHT, it throws a NullPointerException.
If I try to access the constants from FBClient class directly, instead of getters, it still prints out properly.
Finally
Thank you for taking your time, and if you need more information to work with, ask me in the comments and I'll provide it. Also, I apologise if the question is not constructed well/not explained well. If that's the case, tell me how can I improve it. And also, I apologise if this question was asked and answered once already, I may have missed it, but as I said, I did my research.
Edit #1
A comment suggested I print out a fbc value, to see if it's null.
So I added this line of code to the State constructor:
if(FBClient.fbc != null) System.out.println("Not null"); else System.out.println("Null");
And, as suspected, it printed out null. Why is that? I clearly initialized the variable in the main method...
You are referring to FBClient.fbc before it is assigned (actually in the constructor since fbc get assigned after the constructor finished working). To fix it add static to the final values, make the getter static and acess it with FBClient.getFRAME_HEIGHT(). You don't need non-static final variables.
The reason you are having a problem is because you are trying to reference FBClient.fbc within its constructor call and the object hasn't finished its own construction. It's not immediately obvious you're doing this but if you follow the code within the constructor you are calling init() which ultimately calls to a State constructor, which in turn tries to use FBClient.fbc.getFRAME_WIDTH().
I suggest you don't call init() within the FBClient constructor and change your main method code to:
public static void main(String[] args)
{
try
{
//First call in exception chain:
fbc = new FBClient();
fbc.init();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
Hope this helps.
I think your FBClient.fbc is null.
Related
I have two questions regarding the static block and Constants with below code.
Constant (or even simple Static variable) cannot be directly referrenced from static block. It gives error saying "Cannot reference a field before it is defined". But it is ok when accessing through a static method.
If I assign a value to a constant in static block's catch as mentioned below it gives error saying "The final field NAME may already have been assigned". But if asigning in catch it gives error saying "The blank final field NAME may not have been initialized".
I want to know why is it bahaving like this?
Code :
public class TestStaticblock {
static{
try {
// NAME = dummyStringValue() + NAME_APPENDER; // Cannot reference a field before it is defined
// NAME = dummyStringValue() + getNameAppender(); // This is OK
NAME = dummyStringValue();
} catch (Exception e) {
NAME = null; // The final field NAME may already have been assigned
}
}
private static String dummyStringValue() throws Exception{
return "dummy";
}
private static String getNameAppender() throws Exception{
return NAME_APPENDER;
}
private static final String NAME; // If I comment Catch it says "The blank final field NAME may not have been initialized"
private static String NAME_APPENDER = "appender";
}
You can only assign to NAME once (because it is final). Assign the result to a temporary variable, and then assign to NAME (and don't silently swallow Exceptions). Something like,
static {
String temp = null;
try {
temp = dummyStringValue();
} catch (Exception e) {
e.printStackTrace();
}
NAME = temp;
}
The reason you can't assign NAME the way your are currently is because the compiler performs static program analysis (specifically, the data-flow analysis) and that detects that there is a possible code path where NAME is not assigned. And because NAME is final, that is a compilation error.
You cannot use a static final field in a static block before it has been assigned, yet you can access it just by calling a method.
For example, this code prints null FOO:
public class Main {
static final String FOO;
static {
foo();
FOO = "FOOFOO".substring(0, 3);
foo();
}
static void foo() {
System.out.println(FOO);
}
public static void main(String[] args) {}
}
This is undeniably odd, but I guess it would have made the language considerably more complicated to make things such as this impossible.
As for your second question, this doesn't compile.
static{
try {
NAME = dummyStringValue();
} catch (Exception e) {
NAME = null; // The final field NAME may already have been assigned
}
}
This is also odd. If an exception is thrown it can only have occurred inside the method dummyStringValue(). Since you can't assign values to final fields inside a method, it is completely impossible for the NAME variable to have already been assigned in the catch block. Therefore there is no possible code path where NAME is not assigned. You'd think it ought to work in the same way as
static{
if (someCondition()) {
NAME = dummyStringValue();
} else {
NAME = null;
}
}
which compiles fine.
I guess the reason is again that it would have made the language much more complicated to allow this. There is no great benefit to allowing it as you can just use a method or a temp variable as indicated in the other answers. Exceptions just are more complicated than if statements - they can act almost like a goto. A good point was made by #ElliottFrisch in the comments. What about something like this:
static{
try {
NAME1 = dummyStringValue1();
NAME2 = dummyStringValue2();
} catch (Exception e) {
// Has NAME1 been assigned here?
}
}
Perhaps this would be of assistance to those looking for something similar.
There is a little-known feature of Java (discussed in JavaSpecialists Throwing Exceptions from Fields that if you wish to initialise a final instance variable (i.e. NOT a static) to the result of a method call that throws an exception then you can avoid the obvious error by adding a constructor that throws the exception.
Note that this solution only works for non-statics (not what you are observing).
public class TestStaticblock {
private final String NAME = dummyStringValue();
// Adding this removes the "unreported Exception" above.
public TestStaticblock() throws Exception {
}
private static String dummyStringValue() throws Exception {
return "dummy";
}
}
My strong personal preference is to use methods instead of static initializer blocks which initializer a single variable:
private static final String NAME = getName();
private static String getName() {
try {
return something();
} catch (Exception e) {
return null;
}
}
You don't get issues like the one you have described.
You can only calculate one field value, so you are not tempted to throw lots of things into the same block.
You can re-invoke a method to test it.
I am trying to manipulate an object inside a method like this:
My class Problem:
public class TaxiProblem {
public Problem(final World world, final Agent agent) {
_world = world;
_world.setRandomAgent(_agentPlace);
}
private Place _agentPlace;
// Various other functions
}
and in the function .setRandomAgent() in the class World I am trying to manipulate the Place object in what I want it to be like this:
public void setRandomAgent(Place agentPlace) {
int rand = _random.nextInt(25);
agentPlace = _places.get(rand);
agentPlace.setHasAgent(true);
}
I basically want to grab a random Place from the List _places and have it in the variable agentPlace in .setRandomAgent() which in turn will have it in _agentPlace in the Problem class. I thought this would work since Java passes objects by reference in methods but it didn't and _agentPlace remains null.
By doing this
agentPlace = _places.get(rand);
you are overwriting the reference that was passed to the method and losing access to the object you want to alter.
In your setRandomAgent method, agentPlace is indeed a reference that points to your _agentPlace field, not the field itself. In the line I pasted above, what you do is make that reference point to a different object.
_agentPlace = _world.getRandomAgent();
public Place getRandomAgent() {
int rand = _random.nextInt(25);
Place agentPlace = _places.get(rand);
agentPlace.setHasAgent(true);
return agentPlace();
}
When you pass agentPlace to the method, you are creating a copy of the reference. So if you modify the object, then it would work when you return up the stack. But reassigning the variable makes you lose the object you were working with.
I suspect that your problem lies in the implementations as your understanding of pass by reference I believe is correct. The following code will produce the results you expect - That is, it will first print "Before change", then "I am changed!".
class Program
{
static void Main(string[] args)
{
var problem = new Problem();
}
}
public class Problem
{
public Problem()
{
var toChange = new ClassToChange();
toChange.ChangeMe = "Before change";
Console.WriteLine(toChange.ChangeMe);
var changer = new ClassThatChanges();
changer.ChangeSomething(toChange);
Console.WriteLine(toChange.ChangeMe);
Console.ReadLine();
}
}
public class ClassToChange
{
public string ChangeMe { get; set; }
}
public class ClassThatChanges
{
public void ChangeSomething(ClassToChange classToChange)
{
classToChange.ChangeMe = "I am changed!";
}
}
I came across the Java code below which looks good at first but never compiles :
public class UnwelcomeGuest {
public static final long GUEST_USER_ID = -1;
private static final long USER_ID;
static {
try {
USER_ID = getUserIdFromEnvironment();
} catch (IdUnavailableException e) {
USER_ID = GUEST_USER_ID;
System.out.println("Logging in as guest");
}
}
private static long getUserIdFromEnvironment()
throws IdUnavailableException {
throw new IdUnavailableException(); // Simulate an error
}
public static void main(String[] args) {
System.out.println("User ID: " + USER_ID);
}
}//Class ends here
//User defined Exception
class IdUnavailableException extends Exception {
IdUnavailableException() { }
}//Class ends here
Below is the error message which comes in the IDE :
variable USER_ID might already have been assigned.
Is there any problem with the value assignment to the static final variable ?
Final variables allow at most one assignment in the constructor or the initializer block. The reason this does not compile is that Java code analyzer sees two assignments to USER_ID in branches that do not look mutually exclusive to it.
Working around this problem is simple:
static {
long theId;
try {
theId = getUserIdFromEnvironment();
} catch (IdUnavailableException e) {
theId = GUEST_USER_ID;
System.out.println("Logging in as guest");
}
USER_ID = theId;
}
The fact that you have used the assignment operator to throw the Exception in the following line:
USER_ID = getUserIdFromEnvironment();
means that the compiler thinks that there is a possibility of assignment, especially given the fact that it is declared as final.
Since the compiler gave you an that kind of error indicatesthat the variable has been creaated (and perhaps changed) somewhere else. It is good to change the name of your variable whereever it appears in your code.
I'm having a problem where I receive this error:
Exception in thread "main" java.lang.NullPointerException
at com.noxia.Main.startCombat(Main.java:101)
at com.noxia.Area1.createArea1Enemy(Area1.java:43)
at com.noxia.Main.main(Main.java:30)
I know that I need to initialize the variables because they are null, but I can't seem to figure out what I need to put where. I've minimized the code to show just the relevant parts as there are many other variables and methods left out, but this seems to pertain to the issue. Any help would be greatly appreciated =)
public class Main {
Player p;
Enemy e;
Area1 a1;
public static void main(String[] args) {
Main main = new Main();
main.a1 = new Area1();
main.p = new Player(100);
//the line directly below this is line 30 where the error occurs
main.a1.createArea1Enemy(10);
}
public void startCombat()
{
//the line directly below this is line 101 where the error occurs
while (p.getCurrentLife() > 0 & a1.e.getLife() > 0)
{
p.playerAttack();
if (p.getCurrentLife() > 0 & a1.e.getLife() > 0)
{
e.enemyAttack();
}
}
}
public class Player extends Main {
private int currentLife;
public int getCurrentLife()
{
return currentLife;
}
public void setCurrentLife(int cl)
{
currentLife = cl;
}
public Player(int cl)
{
currentLife = cl;
}
public class Enemy extends Main {
private int life;
public int getLife()
{
return life;
}
public void setLife(int lf)
{
life = lf;
}
public Enemy (inf lf)
{
life = lf;
}
public class Area1 extends Main {
public void createArea1Enemy(int enemyCounter)
{
while (enemyCounter > 0)
{
String[] enemyList = {"Enemy1", "Enemy2"} //code for Enemy2 left out below
int enemyListLength = enemyList.length;
int randomEnemy = (int) (Math.random() * enemyListLength);
if (enemyList[randomEnemy].equals("Enemy1"))
{
Enemy enemy1 = new Enemy("Enemy1", 100);
//the line directly below this is line 43 where the error occurs
startCombat();
}
enemyCounter--;
}
}
}
The simple answer is that you have to set e to an enemy before calling startCombat.
But a better way to do this would be to remove e, and pass the enemy object to startCombat using a method parameter. The e field is conceptually wrong. To understand the wrongness, try to come up with a coherent explanation of what it means in terms of the state of a Main object.
Clearly this is beginner code ... and there are a number of bad things about what you have written:
The fields of a class should be for object state, not for passing parameter values to methods.
You should avoid writing code that accesses the innards of a class ... like your main method does.
Best practice is to make fields private, and defined getter and / or setter methods (as required) for external classes to access / modify them.
You need to learn how to write constructors with parameters.
You need to design your code properly. Everything extending Main means that there is going to be no rational model of what the objects "mean". And there's the problem that each instance of Enemy and Area1 will have their own copies of the p, e, and a1 fields, and a whole bunch of inappropriate methods.
The main problem is that you never initialize Enemy e;. You create an enemy but never assign it to this.e.
Change this line:
Enemy enemy1 = new Enemy("Enemy1", 100);
To this:
this.e = new Enemy("Enemy1", 100);
There are also many other problems with your code.
Learn how to write a constructor properly. This code is wrong.
I see no reason at all why a Play, Area1, and Enemy should extend Main.
Parent class(*ch.qos.logback.core.FileAppender*):
...
protected String fileName = null;
public FileAppender() {
}
public void setFile(String file) {
if (file == null) {
fileName = file;
} else {
// Trim spaces from both ends. The users probably does not want
// trailing spaces in file names.
String val = file.trim();
fileName = val;
}
}
...
Child class:
...
public class FileAppender<E> extends ch.qos.logback.core.FileAppender<E> {
private FileResourceManager frm = new FileResourceManager(fileName, tempDir, false, loggerFacade);
public void writeOut(E event) throws IOException {
Object txId = null;
try {
frm.start();
txId = frm.generatedUniqueTxId();
frm.startTransaction(txId);
outputStream = frm.writeResource(txId, fileName, true);
outputStream.write(event.toString().getBytes());
frm.commitTransaction(txId);
}
catch (Exception e) {
...
}
}
The problem is that fileName is passed as null to frm in this line:
private FileResourceManager frm = new FileResourceManager(fileName, tempDir, false, loggerFacade);
How can i create frm instance,with not-null fileName,e.g. already initialized in parent?
If I understand your question correctly, you can do one of the following:
call setFile(file) in constructor of child class
implement logics placed in setFile() method in child's constructor (BTW, that'll be code duplication)
if parent class provides constructor, which accepts file parameter, call parent's constructor with super(file) in constructor of child class
UPDATE
AFAIU, the problem is in fields initialization order. The moving "frm" field initialization into child class constructor should solve the problem:
public FileAppender(String fileName) {
setFile(fileName);
frm = new FileResourceManager(fileName, tempDir, false, loggerFacade);
...
}
Is setFile an override that you are calling from the parent class constructor? In that case: The parent class constructor runs before the useful part fo the child constructor. So setFile is called from the parent class constructor, and then control is returned to the child class constructor which you have nulling out that variable.
The instance field initialisers and instance initialisers are actually part of constructors, after the possibly implicit call to super (but not if they call this()). I believe C sharp inserts instance initialisers before the call to super (but they can't reference this).
What to do: Avoiding inheritance is always good. In particular avoid protected variables and calling overridable methods from constructors. Keep constructors simple. And don't add = null to instance fields.
Resolved with following code:
private static FileResourceManager frm;
public void writeOut(E event) throws IOException {
...
if (frm == null) {
frm = new FileResourceManager(fileName, tempDir, false, loggerFacade);
}
Object txId = null;
try {
...
}
catch (Exception e) {
...
}
}
fileName is initialized(not null) within writeOut() method.
Not very gracefully,but looks like simplest solution in my case.
You have to call the setFile() method in the parent class.
Assuming that your "parent class" is the SomeClass class, overwrite the default constructor there:
public Someclass(String fileName) {
this.fileName = fileName;
}