My question is regarding the declaration and value assignment rules in Java.
When writing the fields we can declare and assign values together but we cannot do the same separately.
E.G.:
class TestClass1 {
private int a = 1;
private int b ;
b= 1;
private int sum;
public int getA() {
return a;
}
public int getB() {
return b;
}
public int getSum() {
sum = a + b;
return sum;
}
}
public class TestClass {
public static void main(String[] args) {
TestClass1 testClass1 = new TestClass1();
System.out.println("total =" + testClass1.getSum());
}
}
Here in line:
private int a = 1;
We are able to declare a as a private int and assign a value 1 to it. But in case of:
private int b ;
b= 1;
Eclipse does not allow this to happen and throws an error. Kindly explain the logic behind this.
Code inside a class, but outside a function, is purely declarations. It does not get "executed". It simply declares what fields a class contains.
The reason you can do the shorthand private int a = 1; is just syntactic sugar that the Java language allows. In reality, what happens is that the a = 1 part is executed as part of the constructor. It's just easier to read and write when it is next to the variable declaration.
It's something nice that the Java langage creators allowed. Not every language allows that, look at C++ as an example that does not always allow it.
you have to put b=1; inside a method or put this inside a constructor.
you are getting this error since you can't do any thing other than declaration(private int a= 1;
) in class level.
It's just a question of syntax in Java. In the example you show, you try to affect a value to b in the member declaration part of your class. This is not allowed by the syntax of Java. You can only do it when you declare your attribute, in the body of a method or in a static block if your attribute is static e.g. :
private static int b;
static {
b = 1;
}
It is only a syntax problem. You can do it like this :
private int b ;
{ // <- Initialization block
b= 1;
}
See What is an initialization block?
You are unable to write logic directly in the class. You should move it to the constructor.
Java only allow declaration within the class and outside any method. Declarations like int b = 1; will be executed when you initialize a new Object.
Related
Why can we do this:
class A{int a=5;}
but are not allowed to do this:
class A {
int a;
a=5;
}
just put it inside a block then.
class A {
int a;
{a=5;}
}
An initialization block will run every time you make in instance of the class e.g.
new A();
this is of course between two other initializations related to creating a new instance.
first is the field's initializations like when you declare a field with a value.
int a = 25;
then the block initialization
{
a = 5;
}
then the constructor:
A() {
a = 6;
}
What is happening in the compiler when we do forward referencing methods, how does it assign the value of another variable which is not declared? And can we use that inside methods? But why can we not use the variable in static blocks? For example,
public class Forward {
static int i = test();
static int test() {
System.out.println(j);
j = 20;
return j;
}
static {
System.out.println(j);
j = 20;
}
static int j;
}
If we assign the value directly like:
int i = j;
int j = 10;
Why does this code not compile? How is it possible only with methods? How does the compiler compile the forward references internally? Is the declaration happening first for all the variables and initialization happening next for all at a time or one by one? Explain it in detail.
JLS Section 8.3.3 states that 4 criteria must all be met if the forward-usage of a static variable will be considered a compile-time error:
The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
In other words, obviously, it must be a "forward declaration": you use it before you declare it:
// Maybe not OK to use j here.
static int j;
// OK to use j here.
The use is a simple name in either a class variable initializer of C or a static initializer of C;
You can make a forward reference to the variable if you qualify its name:
static {
System.out.println(j); // Error on this line...
System.out.println(Forward.j); // ...but not this line...
System.out.println(org.whatever.Forward.j); // ...or this line...
}
static int j;
This criterion only applies to variable or static initializers. This answers the specific question of why you are not getting a compiler error when referring to the static variable in a method.
However, let's just finish things off...
The use is not on the left hand side of an assignment;
Note in this code:
static {
System.out.println(j); // Error on this line...
j = 20; // ...but not this line.
}
static int j;
You can't do anything except assign the variable, even if you reverse the order of the lines (you can't assign and then print it).
C is the innermost class or interface enclosing the use.
The following code would be fine:
class Forward {
static class Inner {
static {
System.out.println(j);
}
}
static int j;
}
If I have:
class A
{
void foo()
{
int a = count;
}
void bar()
{
int a = c; // here ERROR
int c = 10;
}
private int count = 10;
}
here in foo count is used without problem also if it's declared after the use.
The same is not true in method bar where the variable c must be declared before its
use.
Which are the class scope rules? How they differs from method scope rules?
P.S.
My doubt is because the common scope resolutions rules:
When the compiler find count it should try to find it "back" to its
use but back there is Class A... so maybe private int count is "hoisting" at
beginning of Class A?
Imagine that you were a compiler, and you get to the line:
int a = c;
Won't you get angry and ask yourself "What is c"? The order is important1.
1count doesn't make a problem because it's a class member, it's known in the whole class. You can place class members in the beginning of the class, or at the end.
count is declared in the class while c is declared in the method
While compiling, the class would find count in the class.
class A
{
void foo()
{
int a = count;
}
private int count = 10;
}
is equal to put count anywhere in the class, as it is a class member and can be found in the class everywhere.
while in your case of
class A
{
void bar()
{
int a = c; // here ERROR
int c = 10;
}
}
c is not defined before use, as c is a local variable in a method.
Is it possible to assign a value to a final variable anywhere else in the program? Or is it mandatory that they be assigned a value upon creation?
class TestClass() {
//this won't compile but is it possible to assign str a value anywhere else in the program?
public static final String str;
}
You need to assign a value when it's declared - in the constructor if it's not static, in the static initializer block if it is. Once you set the value, it can't be modified.
Do it like this:
public class FinalTest {
private static final String CONSTANT;
private final String value;
static {
CONSTANT = "Hello";
}
public static void main(String [] args) {
FinalTest ft = ((args.length > 0) ? new FinalTest(args[0]) : new FinalTest(CONSTANT));
System.out.println(ft);
}
public FinalTest(String value) {
this.value = value;
}
public String toString() { return this.value; }
}
Local variables
A final variable needs to be assigned a value exactly once before it is accessed. This means that if it's never assigned a value and never accessed, the compiler won't complain.
void foo() {
final int a; // Never assigned, but never accessed either, so no problem
final int b = 7;
System.out.println("b is " + b);
// System.out.println("a is " + a);
// Uncommenting the above line would cause a compile error
}
Static fields
A similar logic applies to final static fields, except it's assumed that they will be accessed at some point, so they must be initialized either on the definition line or in a static initializer block.
Here's what the Java tutorial has to say about static initialization blocks:
This works well when the initialization value is available and the initialization can be put on one line. However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a for loop to fill a complex array), simple assignment is inadequate. Instance variables can be initialized in constructors, where error handling or other logic can be used. To provide the same capability for class variables, the Java programming language includes static initialization blocks.
Note: It is not necessary to declare fields at the beginning of the class definition, although this is the most common practice. It is only necessary that they be declared and initialized before they are used.
Instance fields
While we're at it, a final instance (non-static) field must be assigned a value exactly once by the time the instance initialization is complete. This means there are three places where you can initialize one (but you must pick one):
1. Definition line:
// For when you know the answer
class Foo {
final int theAnswer = 42;
}
2. Constructor:
// For when you need to have the answer passed in
class Foo {
final int theAnswer;
Foo(int answer) {
theAnswer = answer;
}
}
// Or for when you need to do some computation
class Bar {
static final int ANSWER_COUNT = 10;
final int[] answers;
Foo() {
answers = new int[ANSWER_COUNT];
for (int i = 0; i < ANSWER_COUNT; i++) {
answers[i] = i;
}
}
3. Initializer block:
// For when you need to do some computation and have many constructors
class Bar {
static final int ANSWER_COUNT = 10;
final int[] answers;
{
answers = new int[ANSWER_COUNT];
for (int i = 0; i < ANSWER_COUNT; i++) {
answers[i] = i;
}
}
// I have many constructors and don't want to copy-paste
// the initialization logic above to all of them
Bar() { ... }
Bar(int i) { ... }
Bar(String blah) { ... }
}
From the same page in the tutorial, regarding initializer blocks:
The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.
In the code you posted, the field is static so it could be given a value from within a static initialization block:
static {
str = "my string";
}
For non-static fields, they can either be initialized in the constructor, or in an instance initializer block:
class TestClass {
private final String str;
{
str = "my string";
}
TestClass() {
}
}
I'm just beginning to learn Java and I have been very frustrated about learning Java's scope rules. You see I wish to create a Method without the use of arguments/parameters.
In JavaScript, I can do this with ease using functions:
/** Function to increase 2 vars.
/** **/
function modifyNow(){
a++;
b++;
} // END
var a = 5;
var b = 10;
modifyNow();
// By this part, a and b would be 6 and 11, respectively.
Now this is saving me a lot time and simple since whenever the function is called, var a and b, already exist.
So, is there a way to do this in Java without having arguments like how I do it in JavaScript? Or is there another way around this?
Thank you, appreciate the help... ^^
What is the problem with having a and b as private variables in your class, and increment them in modifyNow()? And by the way everything in Java must be in a class. You can't have global code mangling around...
You can do this for class fields, not for local variables.
class Clazz {
int a = 5;
int b = 10;
public void modifyNow() {
a++;
b++;
}
}
// ...
Clazz c = new Clazz();
c.modifyNow();
Now, after each call to modifyNow, the fields are updated.
Global variables are bad. Without knowing your intent, I would say you need to add the variables as members to your class. They are accessible then from any member function.
You see I wish to create a Method without the use of
arguments/parameters.
The best answer is: don't!
If you nevertheless want this, look for public static variables.
class Foo {
int a = 5;
int b = 10;
public void modifyNow(){
a++;
b++;
}
}
You need to use what are called member variables, they are tied to an instance of your class.
public class MyClass
{
// these are Class variables, they are tied to the Class
// and shared by all instances of the class.
// They are referenced like MyClass.X
// By convention all static variables are all UPPER_CASE
private static int X;
private static int Y
// these are instance variables that are tied to
// instances of the class
private int a;
private int b;
/** this the default no arg constructor */
public MyClass() { this.a = 5; this.b = 10; }
/** this is a Constructor that lets you set the starting values
for each instance */
public MyClass(final int a, final int b) { this.a = a; this.b = b; }
public modifyNow() { this.a++; this.b++; }
/** this is an accessor to retrieve the value of a */
public int getA() { return this.a; }
public int getB() { return this.b; }
}
final MyClass myInstanceA = new MyClass();
myInstance.modifyNow();
// a = 6, b = 11
final MyClass myInstanceB = new MyClass(1, 2);
myInstance.modifyNow();
// a = 2, b = 3
Everytime you do a new MyClass() you will get a new independent instance of MyClass that is different from every other instance.
As you are learning JavaScript is not related to Java in anyway. It is a terrible travesty that they picked that name for marketing reasons.