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
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;
}
Let's say we have an immutable class:
public final class Student
{
final String name;
final int regNo;
public Student(String name, int regNo)
{
this.name = name;
this.regNo = regNo;
}
public String getName()
{
return name;
}
public int getRegNo()
{
return regNo;
}
}
Let's say we have created final variables so that their values cannot be changed after object creation. The values for name and regNo are not yet defined here. But I do have a question. We know that if we dont assign values to them, it will take default values. So, if I dont assign any values, it will be
name = null & regNo = 0
So my question is, if its already get assigned to default values, how can we assign values to them at later point?
Those values will indeed be null and 0 before initialisation:
public static final class Student
{
final String name;
final int regNo;
public Student(String name, int regNo) throws NoSuchFieldException, IllegalAccessException {
System.out.println("BEFORE ASSIGNMENT:");
System.out.println(getName());
System.out.println(getRegNo());
this.name = name;
this.regNo = regNo;
System.out.println("AFTER ASSIGNMENT:");
System.out.println(getName());
System.out.println(getRegNo());
}
public String getName()
{
return name;
}
public int getRegNo()
{
return regNo;
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
new Student("Rahul", 3);
}
}
Prints:
BEFORE ASSIGNMENT:
null
0
AFTER ASSIGNMENT:
Rahul
3
The compiler just won't let you use those values directly before initialisation. Also, it forces you to assign them once (and only once) while the object is constructed, and never re-assign them afterwards.
Since you don't have any default constructor (also, can't have any other constructors without assigning values to final variables - it will throw compilation error if you tried) - you won't be able to instantiate any Student object without giving name and regNo.
And whatever you give while creating new Student will be final.
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.
Hello I'm new to Java. I'm trying to create a object and pass name through it. I don't have a clue what I'm doing wrong?.
public class Employee
{
private String name, number;
private String date;
public Employee()
{
name= "";
number = "";
date = "";
}
public Employee(String name, String number, String date)
{
setName(name);
setNumber(number);
setDate(date);
}
public void setName(String n)
{
name = n;
}
public void setNumber(String n)
{
number = n;
// you can check the format here for correctness
}
public void setDate(String d)
{
date = d;
}
public String getName()
{
return name;
}
public String getNumber()
{
return number;
}
public String getDate()
{
return date;
}
}
import java.util.Scanner;
public class TeamLeadDemo
{
public static void main(String[] args)
{
String name;
// create scanner object
Scanner keyboard = new Scanner(System.in);
// inputting data
System.out.println("Enter Name:");
name = keyboard.nextLine();
// instantiating object, HERE IS THE PROBLEM
Employee thename = new Employee(name);
// outputting data
System.out.println("Employee Name:"+thename.getName());
System.out.println("Employee Details:\n" + thename);
}
}// Function definition
What should i do??
Hey fellow newbie programmer!
Take a look at how you initialize your object:
Employee thename = new Employee(name);
Since you only give it the String name as a parameter, Java cannot initialize your Employee object because it does not have a single argument constructor!
Here are your constructors method signatures:
public Employee()
public Employee(String name, String number, String date)
One takes no arguments, and the other takes 3 arguments.
If you look at the way you initialize it, you only pass 1 argument!
You would need to create a new Constructor that has a single argument in order for your code to work. Or easier yet, you could just pass in "", "" for your number and date string values.
More experienced programmers please do not hesitate to correct my programming semantics if they are wrong. I feel like I'm using words that I do not fully understand.
You need a constructor that receives only the name that you are passing:
public Employee(String name) {
this.name = name;
this.number = "";
this.date = "";
}
Currently you only have one default constructor and one that receives all three properties.
Your Employee class has two constructors: one taking zero arguments and one taking three arguments. Yet you're attempting to construct it with one argument. That wouldn't compile.
There are two possible solutions:
Add another constructor taking one argument.
public Employee(String name) {
this.name = name;
}
Use the constructor taking three arguments and pass null through.
Employee employee = new Employee(name, null, null);
Unrelated to the concrete problem, setting values to empty strings in the default constructor and calling the setters in the second constructors is not a nice practice. In the first, just do nothing, keep them default null. In the second constructor, you should prefer setting the property directly instead of calling the setter.
You need to pass in the number and date to the constructor as well. Try:
Employee thename = new Employee(name, "", "");
Employee thename = new Employee(name);
You have no constructor that takes only one String
If you have some very very strong reasons not to use Employee thename = new Employee(name, "", "");, you may try "varargs"
As :
public class Employee {
String fname="";
String lname="";
public Emp(String... attrs) {
if ( attrs.length > 1 ) {
fname = attrs[0];
lname = attrs[1];
}else if(attrs.length == 1) {
fname = attrs[0];
}
}
public String toString() {
return fname + " " + lname;
}
public static void main(String[] args){
Employee e1 = new Employee ("Test");
Employee e2 = new Employee ("Test" ,"case");
System.out.println(e1);
System.out.println(e2);
}
}
Caution : this is just to answer your question- Think before using in real world situations. Not from design/ best approach perspective. But it is different and caters to your question though ;-)
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.