Is there a difference between the following variable declarations?
Class A {
private int a;
A(){
a= 2;
}
}
VS
Class A {
private int a = 2;
A(){
}
}
Will garbage collection work any differently?
No there is no difference because the java compiler initialize "private int a = 2" inside the constructor internally. You can use java decompiler to confirm my above statement. So for both GC will work same.
There is no difference in the behaviour of your two initialisations. In the first example the a = 2 will happen just before the constructor code is called. If you made a final:
private final int a; //first example
private final int a = 2; //second example
Then you would see a difference between what you could do in the constructor:
A(){ //The blank final field a may not have been initialized for first example
}
A(){
a = 2; //The final field Apple.a cannot be assigned for second example
}
In both cases you are declaring int a as a member variable of the class. Whenever the class is instantiated, space will be set aside on the heap for that integer. However, the garbage collector only cares about whether or not there are any references to the containing object that has been instantiated. Regardless of what you do with the member variables, the object will stay in memory if there is a reference to it, after which point it's eligible for garbage collection.
However, perhaps you believe there should be a difference? Why is that?
Related
I have noticed that when you execute a statement like sum=a+b;
we need the three fields initialized prior to using them in this operation
ie
int a=1
int b=1;
int sum=0;
sum=a+b;
.
My understanding is, this is because javac works like an interpreter and reads line by line.
But when it comes to methods where we call and pass values to fields inside a class we can define the fields after method declaration.
public class Dog extends Animal{
public Dog(String name, int weight, int teeth, String coat) {
super(name, true, true, weight);
this.tail=true;
this.eyes=2;
this.teeth=teeth;
this.coat=coat;
}
private int eyes;
private boolean tail;
private int teeth;
private String coat;}
The parameters eyes, tail, teeth, and coat have been defined after they were used to pass values to the constructor.
How does javac understand that there is a variable after the method.
Is this allowed because we can only define fields and not do any operations on them in a class definition?
Javac is Java Compiler Compiles your Java code into Bytecode
JVM is Java Virtual Machine Runs/ Interprets/ translates Bytecode into Native Machine Code
This error occurs only with local variables because the compiler does not set the default value for the local variables. In the case of instance variables, the compiler sets default values, for example, 0 for integer, null for string, etc.
In the above case if you don't set values in the constructor still your instance variables will be initialized by default values.
private int eyes = 0;
private boolean tail = false;
private int teeth = 0;
private String coat = null;
But same is not true for local variables a, b or sum.
sum can be uninitialized because you are assigning the values to the sum before using it. That is the statement sum = a+b will assign value and before you use it somewhere else may be like sum2 = sum, its assured that sum has a value.
A local variable declaration (and eventual initialization) is executed together with the block it is in, and being accessed from;
an instance field declaration (and initialization) is executed when the instance is created, before the methods are executed 1.
On the other side this is not allowed:
public class Dog extends Animal {
private int total = eyes + teeth; // ERROR!
private int eyes = 2;
private int teeth = 24;
}
above code does not compile - that is intentional!
while this is valid:
public class Dog extends Animal {
private int eyes = 2;
private int teeth = 24;
private int total = eyes + teeth; // OK
}
Why ...? Short answer: it is specified that way, see Java Language Specification (JLS) - Scope of a Declaration:
The scope of a declaration of a member m declared in ... a class or interface C (§8.2, §9.2) is the entire body of C, ...
The scope of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block,...
One reasons for that is to avoid cyclic references as mentioned in the JLS, see examples on link below 1. Also explained in this answer by Hoopje.
1 - exception are references to fields in initializers, see Restrictions on Field References in Initializers
This has nothing to do with the difference between an interpreter and a compiler. It is just a rule added to language to prevent two fields to refer to each other in their initialization code. For example, what would be the initial values of the fields in the following class?
class A {
int a = b * b;
int b = a + 1;
}
Of course, the Java designers could have decided to allow forward references, and only generate an error when such cycles are detected. But they decided otherwise, and I think that that was the right decision.
There is no reason to forbid forward references to fields from within a method, because when the method is executed, the class is initialized already. Even constructors run after the fields' initializers have been evaluated.
I'm studying computer engineering, my 2nd semester just began. I've been making Android applications for a few while.
My programming lecturer (teaches C++ (Object Oriented)) said we can't initialize variables in a class unless we use a constructor since there's no memory dedicated to those data members before making an object of that class.
He said this is incorrect:
class example
{
int a = 0;
};
But my experience says something else:
I've made a class in my Android project that keeps my Constants. I don't make any objects of that class. I've initialized variables and never used a constructor. But it works fine:
public class Constants {
public static final int a = 1;
}
I want to know how am I initializing variables when there's no memory dedicated to that variable and how it works.
What part of my story is wrong? I want to know how my code works when there's no memory dedicated to my variables (Constants)?
The Truth
class A {
int a = 0;
};
In-class initializers became legal in C++11; so the only conclusion to draw from what you have said is that your teacher is living in the past.
However, if he is teaching C++03 and not a later revision of the language, he's correct about it being ill-formed.
It is important to note that what he said regarding (non-static) data-members and their lack of storage until an object of such class has actually been created still applies.
An in-class initializer will initialize the data-member during construction, as long as the data-member isn't initialized in the used constructor's mem-initializer (then the latter takes precedence).
struct A {
A () = default;
A (int x) : m (x) { }
int m = 0; // ^ mem-initializer
};
A x; // `x.m` is initialized to `0`
A y (123); // `y.m` is initialized to `123`
Further Reading
cppreference.com - Non-static data members : Member Initialization
He said this is incorrect:
class example
{
int a = 0;
}
Well, yes, it's incorrect, there needs to be a semicolon at the end, after the }.
With that semicolon, this is legal C++11; the = 0 is a non-static data member initializer (NSDMI for short). It's syntatic sugar for performing the equivalent initialization in the constructor.
public class Constants {
public static final int a = 1;
}
static things are per-class, and exists even if no objects of that class is ever created. Non-static things are per-object.
This is more of a hypothetical question but if I have some final called A and another final B that are both ints, I can't do this:
private final int A = B/2, B = (some kind of other derived number);
I am just wondering why. Any help would be awesome. NetBeans popped up an error on this and I just want to know why it is a problem.
PS-The error that popped up said "illegal forward reference".
You are accessing variable B before you declare it. That's the reason for "illegal forward reference".
Define variable B before A
private final int B = (some kind of other derived number), A = B/2;
Pretend you're the compiler:
private final int ok. Mr user wants a "const" int
A the variable is called A
= ...here comes the value
B/2 HUH? WHAT THE HELL IS B? NO ONE TOLD ME ANYTHING ABOUT B. STUFF YOU USER. I'M OUT OF HERE...
The existing answers don't answer the underlying question:
Why can I use methods that are defined later in my source file, but does the same with variables cause a forward reference error message?
The answer is found in the JLS, more specifically JLS $12.4.1
The static initializers and class variable initializers are executed in textual order, and may not refer to class variables declared in the class whose declarations appear textually after the use, even though these class variables are in scope (§8.3.2.3). This restriction is designed to detect, at compile time, most circular or otherwise malformed initializations.
This question was answered here. Basically it means that you are trying to use a variable that is not initiated.
Initialize B first, then use it to initialize A
private final int B = ?, A = B/2;
illegal forward reference in java
Your code isn't failing because A and B are final. It's failing because B isn't declared/initialized yet. If you declare it first, you'll be able to use them just fine.
For example,
private final int C = 5;
private final int B = C/3;
private final int A = B/2;
This is fine because B is declared first :)
"final" just means that you can't change the variable. So something like this won't work
private final static int C = 5;
private final static int B = C/3;
private final static int A = B/2;
public static void main (String[] args) {
A = 5;
}
because now we're trying to modify A which is "final"
I got a class Foo having a method doSomething that uses two class-related variables b and c that are expensive to get/create. My first version looks like this:
public class Foo {
private final A a;
public Foo(A a) {
this.a = a;
}
public void doSomething() {
final B b = a.getB();
final C c = b.getC();
for (int i = 0; i < 1000; i++) {
// do something with b and c
}
}
}
So I get the first object (type B) via a class variable a and the second object (type C) via the first object.
Now, since those variables are related to the class and the method is always called exactly one time (though not necessarily when creating an object of type Foo), I thought about making them class variables as well:
public class Foo {
private final A a;
private final B b;
private final C c;
public Foo(A a) {
this.a = a;
b = a.getB();
c = b.getC();
}
public void doSomething() {
for (int i = 0; i < 1000; i++) {
// do something with b and c
}
}
}
I'm not sure which version to use if any of those two. I somehow don't feel comfortable making those two variables class members since they can be retrieved from the existing class variable a. However, it would increase readability of the methods IMO.
You are absolutely right. If it increases readability, bu all means do it. However, I would ask you this: What is the purpose of Referencing A from within the class? Is it only for getting B and C?
In this case, I would just input B and C in Foo's constructor!
This way you even make it more readable by breaking the dependency on A and Making the dependency on B and C more explicit.
Also, consider whether you are using these variables in other methods in the class. If the answer is yes- it signals that they should be class members, However, if the class contains a lot of methods that do not use these variables, that might signal the opposite.
The general principle you should follow here is the principle of High Cohesion
generally speaking, if you can use a local variable, it is preferable to using a field.
Using a local variable
limits the variable to where it is used.
uses less memory.
is thread safe.
Why not just store instances of B and C in your class Foo? Do you reference A somewhere in your class? Otherwise, Storing both B and C as instance variables is no less memory efficient, since storing one A object contains a B and C object.
From my experience static (or class variable|field|method) usually became evil after some time and needs to be refactorred out except cases when this stuff is static by it's nature (Math.PI or Math.max() are examples or such static things). If those methods are doing some computation based on anything dynamic I would leave them as instance.
In the following example, the variable b is declared final, but not static. That means it's a constant instance variable. However, because it's constant, none of the Passenger objects can change its value. So isn't it better to declare it static and make it a class variable, so that there is only one copy to be used by all instantiated objects?
class Passenger {
int a;
final int b = 0;
void drive() {
System.out.println("I'm driving!");
}
}
The purpose of final but non-static variables is to have an object-wide constant. It should be initialized in the constructor:
class Passenger {
final int b;
Passenger(int b) {
this.b = b;
}
}
If you are always assigning a constant literal value (0) to the final variable, it doesn't make much sense. Using static is preferred so that you are only having a single copy of b:
static final int b = 0;
BTW I don't think having default access modifier was your intention.
It depends on the purpose of b. Usually constants are there for a specific purpose. If you make it static you could accidentally change it in some instance of that class and that will affect all the others.
If you have multiple instances of Passenger class, I would go for making it static. While this has little benefit when talking about an int variable, this could save some memory if you have complex objects. This is because a static variable belongs to a class, not to an instance, thus memory space for it will be reserved only once, and it will be referred by the class object itself, not by the instances. Of course, you should be aware that having b as a static variable means that the changes made on this variable will be reflected on all the classes that access this variable, but since you made it final this won't be the case.
Note also that with the code you've written, classes in the same package as Passenger will be able to read the b value by accessing it via Passenger.b (if static).
In java, the static attribute basically means: associated with the type itself, rather than an instance of the type.
In other words you can reference a static variable without creating instances of that type... Whereas in the case of just using final you'd need to instantiate the class.
So, yes, to answer your question, I'd say that you're right. :)
A final primitive is the same as a static final primitive (except more efficient)
A final reference to an immutable object the same as a static final reference of the same.
A final reference to a mutable object is NOT the same as a static final reference of the same.
final int i = 0;
// same as
static final int = 0;
final String hi = "Hello";
// same as
static final String hi = "Hello";
final List<String> list = new ArrayList<String>();
// is NOT the same as
static final List<String> list = new ArrayList<String>();
The only time the last example is the same is when you have a singleton. It is fairly common for singletons to be written with a confusion of static and non static fields and methods as the difference is not obvious. :|
A final variable is defined when you need a constant, so you can assign a value just once.
Using static, instead, you are defining a variable shared by all the objects of that type (like a global variable) and it is not associated with a certain object itself.