This question already has answers here:
Java - static variable and parameter with same name
(2 answers)
Closed 6 years ago.
I'm trying to change a private static variable with via a static method and BlueJ says that I can't because the variable I'm trying to change (which is declared as static) is non-static:
public class Playerinfo {
private static String name = ""; //Stores the name of the 'player'
public static void setname(String name) {
this.name = name;
}
}
The variable is called name and the method is called setname. I know that I can do this:
Playerinfo.name = (insert variable here)
I don't like the above because I wish to have the name variable in Playerinfo declared as private as not to be meddled with by other classes that easily.
There is no this inside a static method.
Your best bet is to rename the parameter of the method:
public class Playerinfo {
private static String name = ""; //Stores the name of the 'player'
public static void setname(String newName) {
name = newName;
}
}
this refers to a class instance, which is illegal in a static method. Either rename your parameter and do name = param;, or refer to it by class: Playerinfo.name = name;. Either way, it won't affect visibility to other classes.
As far as I understand name doesn't need to be static.Each PlayerInfo object must have its own name so remove static from both name and setname
public class Playerinfo{
private String name = ""; //Stores the name of the 'player'
public void setname(String newName){
this.name = newName;
}
Related
This question already has an answer here:
Why Cannot refer to instance fields while explicitly invoking a constructor java
(1 answer)
Closed 3 years ago.
I created my main use constructor with three parameter passed. the parameter above a default parameter. the goal is to set the first field which is name to be default assume user doesnt input a name. the problem come as for creditLimit and email i get the error below. why is this and what is it i do not understand? and what are the fixes.
- Cannot refer to an instance field creditLimit while explicitly invoking a
constructor
- Cannot refer to an instance field email while explicitly invoking a
public class VipCustomer {
private String name;
private int creditLimit;
private String email;
public VipCustomer()
{
this("Default",creditLimit,email);
}
public VipCustomer(String name, int creditLimit, String email) {
// TODO Auto-generated constructor stub
this.name = name;
this.creditLimit = creditLimit;
this.email = email;
}
public String getName()
{
return this.name;
}
public int getCreditLimit()
{
return creditLimit;
}
The Problem
There seems to be an issue with your first constructor which calls with second constructor with the following parameters at runtime:
this ("Default", 0, null);
This is because the values of creditLimit and email are not set.
creditLimit defaults to 0 as that is the default for ints.
email defaults to null because it is an empty object reference.
The Solution
To fix this issue, I recommend having some final fields at the top of your class that define default behavior.
public class VipCostumer {
// Change these values to what you would like.
public static final String DEFAULT_NAME = "Default";
public static final int DEFAULT_CREDIT = 100;
public static final String DEFAULT_EMAIL = "example#abc.com";
public VipCostumer() {
this(DEFAULT_NAME, DEFAULT_CREDIT, DEFAULT_EMAIL);
}
// rest of your code
}
Trade Off
While this may resolve your issue, I would recommend you consider whether or not you want to have defaults for something as specific as a costumer. Depending on your usage, you may want all costumer data to be differentiable, and creating a lot of a default costumers will take that ability away.
There is a problem with your first constructor, because it will call the second constructor (the one with the parameters), but you just try to set undefined variables to themselves.
If your goal is to set the first field which is name to be default assume user doesnt input a name, use this constructor
public VipCustomer()
{
this.name = "Default";
}
if creditLimit and email is a required value while name is not
public VipCustomer(int creditLimit, String email) {
this.name = "Default";
this.creditLimit = creditLimit;
this.email = email;
}
I created a new class "Lecturer" which extends another class "Person", i wanted to make 2 constructors for Lecturer and one would accept a name and a stipend (just a constant to say how much pay is), the other just accepts the name and uses the default stipend set in the code. i included appropriate getters and setters. I then wrote a writeOutput method to print an output similar to this
Name: (name) which gets the name and prints it
Stipend: (stipend) same process ^
heres what i have so far
Lecturer.java
public class Lecturer extends Person{
private static String name;
static double stipend;
public Lecturer(String name) {
super(name);
}
public Lecturer(String name, double stipend) {
super(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getStipend() {
return stipend;
}
public void setStipend(double stipend) {
this.stipend = stipend;
}
public static void writeOutput() {
System.out.println("Name: " + name);
System.out.println("Stipend: " + stipend);
}
}
Person.java
public class Person {
/** Every Person has a name */
private String name;
/** Person requires a name */
public Person(String n) {
this.name = n;
}
/** return this Person's name */
public String getName() {
return this.name;
}
/** Change this Person's name */
public void setName(String nn) {
this.name = nn;
}
Main file (Inheritance.java)
Lines 41-53
Lecturer l1 = new Lecturer("Zachary");
Lecturer l2 = new Lecturer("Wilhelmina", 11017.00);
l1.writeOutput();
l2.writeOutput();
pause();
l1.setName("Zack");
l1.setStipend(10800.00);
l1.writeOutput();
pause();
System.out.printf("%s's stipend is $%,4.2f.\n",
l1.getName(), l1.getStipend());
System.out.printf("%s's stipend is $%,4.2f.\n",
l2.getName(), l2.getStipend());
This is the output
Name: null
Stipend: 0.0
Name: null
Stipend: 0.0
press enter...
Name: Zack
Stipend: 10800.0
The 2nd part works as it should but the first one isnt and i tried to change the code but nothing is working properly.
In Lecturer you are declaring another name variable. This variable is separate from the name variable declared in Person. The call to the superclass constructor is setting the name variable in Person, not in Lecturer. But you don't need the second variable; remove it. You can access the name in Person via the getName method you've already declared. This means that you also don't need to re-declare getName and setName in Lecturer, so the Lecturer class can inherit them.
Also, in Lecturer, the two variables you've declared shouldn't be static. Per the above reasoning, name shouldn't even be there, but even if it should be there, it shouldn't be static. The variable stipend should be there, but it shouldn't be static. When you declare a member variable static, then there is only one variable for the entire class, no matter how many instances you create, which doesn't sound like what you want.
Your constructors should initialize stipend.
You have a static variable inside Lecturer which has the same name as the inherited one from Person and your getter is referring to that static one - are you sure you want these static variables? For completeness if you really want to keep the static one and the inherited one with the same name then change your getter to read return this.name; which will return the inherited name instance variable.... But that method can be inherited from Person class...
There are two name fields in your program , one is private static String name; in Lecturer.java and another is private String name; in person.java .
The thing is that you are just calling Lecturer javs's name field but not setting it.
Fixed the project based on rgettman answer.
Lecturer class should look like this:
public class Lecturer extends Person {
double stipend = 9144;
public Lecturer(String n) {
super(n);
}
public Lecturer(String n, double stipend) {
super(n);
this.stipend = stipend;
}
public double getStipend() {
return stipend;
}
public void setStipend(double stipend) {
this.stipend = stipend;
}
public void writeOutput() {
System.out.println("Name: " + this.getName());
System.out.println("Stipend: " + getStipend());
}
}
public class Wrapper {
public Wrapper(final String name, final String email) {
_name= name;
_email = email;
}
private static final Card testCard = new Card(_email, _name);
private final static String _name;
private final static String _email;
}
I would like the instantiate this class providing a name and an email.
I am getting "Cannot reference a variable before it is defined for (_email, _name) variables on line :
private static final Card testCard = new Card(_email, _name);
I can make it work by moving the declarations to the top but is there any other way?
Thanks
Based on your description, I don't think you want to use static.
I would like the instantiate this class providing a name and an email.
That means that you provide a name and an e-mail when creating an instance of the class. But using static means that there is only one name and one e-mail, that all instances of the class share! Unless every person in your universe has the same name and the same e-mail address, that is not what you want. So get rid of static on _name, _email, and testCard.
Also, initializing testCard outside the constructor won't work, because the program will try to do new Card(_email, _name) before _email and _name have been initialized. So change that to
private final Card testCard;
and in the constructor:
testCard = new Card(_email, _name);
after _email and _name have been set.
If you do this, you should be able to put the declarations anywhere you want. The "Cannot reference a variable before it is defined" or "Illegal forward reference" problems only come up when you have global (static) variables, according to this question.
You cann't initialize static field because variables _email and _name are not initialized yet. You should initialize testCard after _email and _name will be initialized.
For example, you can do it in constructor
public Wrapper(final String name, final String email)
{
_name= name;
_email = email;
testCard = new Card(_email, _name);
}
private static Card testCard;
or separate method for it
public static void initialize(String name, String email)
{
_name= name;
_email = email;
testCard = new Card(_email, _name);
}
Also you should remove final modifiers if you want to initialize static in contructor.
I'm going back to OOP in java. Here I got problem with simple example:
class CreateString {
private String name;
public CreateString(String name) {
this.name = name;
}
String string = new String(name);//AAA
}
public class Main {
public static void main(String[] args) {
CreateString myName = new CreateString("tomjas");
}
}
I got NullPointerException from line denoted as "AAA". When I change the second line into
private String name="";
it's ok. What is wrong with that code? I thought that field is initialised as one could conclude from constructor. Any hints and pointers to documentation?
Your string variable is a class attribute. Therefore it will be initialized when your class instance is created. But at that time name is still null, as you only assign a value to name in the constructor. So you end up with a NullPointerException.
To fix it, move string = new String(name); into the constructor:
class CreateString {
private String name = null;
private String string = null;
public CreateString(String name) {
this.name = name;
string = new String(name);
}
}
As the constructor is only executed after all the attributes have been initialized, it doesn't matter where you put the line private String string;. You could also place it after the constructor (as you did), and it would still be fine.
All the fields are initialised before the constructor, as such when the line initialising string runs name is still null
class CreateString {
private String name; //<--runs first
public CreateString(String name) { //<--runs third
this.name = name;
}
String string = new String(name);//AAA <---runs second
}
You could move the string initialisation within the constructor to solve this
class CreateString {
private String name;
String String string;
public CreateString(String name) {
this.name = name;
string;= new String(name);//AAA
}
}
String string = new String(name);//AAA
That line is in initializer block.So the default value is null, Since you are using it before assigning some value. Move that line to constructor.
Since you dont have any base class defined for your class, the order of execution would be :
initialize member fields of this class.
run the constructor of this class.
Since while executing this
String string = new String(name);//AAA since it executes first.
the variable name is still null. That's why it throws NullPointerException
Is there a solution to use a final variable in a Java constructor?
The problem is that if I initialize a final field like:
private final String name = "a name";
then I cannot use it in the constructor. Java first runs the constructor and then the fields. Is there a solution that allows me to access the final field in the constructor?
I do not really understand your question. That
public class Test3 {
private final String test = "test123";
public Test3() {
System.out.println("Test = "+test);
}
public static void main(String[] args) {
Test3 t = new Test3();
}
}
executes as follows:
$ javac Test3.java && java Test3
Test = test123
Do the initialization in the constructor, e.g.,
private final String name;
private YourObj() {
name = "a name";
}
Of course, if you actually know the value at variable declaration time, it makes more sense to make it a constant, e.g.,
private static final String NAME = "a name";
We're getting away from the question.
Yes, you can use a private final variable. For example:
public class Account {
private final String accountNumber;
private final String routingNumber;
public Account(String accountNumber, String routingNumber) {
this.accountNumber = accountNumber;
this.routingNumber = routingNumber;
}
}
What this means is that the Account class has a dependency on the two Strings, account and routing numbers. The values of these class attributes MUST be set when the Account class is constructed, and these number cannot be changed without creating a new class.
The 'final' modifier here makes the attributes immutable.
Marking it static, will allow you to use it in the constructor, but since you made it final, it can not be changed.
private static final String name = "a_name";
is is possible to use a static init block as well.
private static final String name;
static { name = "a_name"; }
If you are trying to modify the value in the constructor, then you can't assign a default value or you have to make it not final.
private String name = "a_name";
Foo( String name )
{
this.name = name;
}
or
private final String name;
Foo( String name )
{
if( s == null )
this.name = "a_name";
else
this.name = name;
}
In this case, you can mark the field as 'static' also.
Another possiblity is to initialize the field in an instance initializer blocK:
public class Foo {
final String bar;
{
System.out.println("initializing bar");
bar = "created at " + System.currentTimeMillis();
}
public Foo() {
System.out.println("in constructor. bar=" + bar);
}
public static void main(String[] args) {
new Foo();
}
}
In that case, you might as well make it static, too. And Java convention is to name such constants in ALL_CAPS.
private static final String name = getName();
where getName() is a static function that gets you the name.
I cannot use it in the constructor, while java first runs the constructor an then the fields...
This is not correct, fields are evaluated first, otherwise you couldn't access any default values of members in your constructors, since they would not be initialized. This does work:
public class A {
protected int member = 1;
public A() {
System.out.println(member);
}
}
The keyword final merely marks the member constant, it is treated as any other member otherwise.
EDIT: Are you trying to set the value in the constructor? That wouldn't work, since the member is immutable if defined as final.