The knowledge point of object and memory control
The initialization process for 1.java variables, including local variables, member variables (instance variables and class variables).
2. In an inheritance relationship, there is a difference between the properties and methods of accessing an object referencing a variable compile-time type and a run-time type.
3.final modifier attribute.
The Division and initialization process of Java variables
Java program variables can generally be divided into member variables and local variables, member variables can be divided into instance variables (non-static variables) and class variables (static variables), the general we encounter the local variables in the following situations will occur:
(1) Parameter: a local variable defined in the method signature that is assigned by the caller and dies as the method ends.
(2) Local variables within a method: The local variables defined within the method must be initialized (assigned to the initial value) within the method, and die out at the end of the method, beginning with the completion of the variable initialization.
(3) Local variables within the code block: The local variables defined within the code block must be initialized (assigned initial values) that are displayed within the code block, and as the initialization completes, the end of the code block dies.
Package Com.zlc.array;
public class Testfield {
{
String b;
If not initialized, the compiler will report the local variable B might not have been initialized
System.out.println (b);
public static void Main (string[] args) {
int A;
If not initialized, the compiler will report the local variable a might not have been initialized
System.out.println (a);
}
A member variable that is decorated with static is a class variable, belonging to the class itself, a member variable that is not decorated with static is an instance variable, an instance of that class, in which each class can only correspond to one class object, but each class can create multiple Java objects. (That is, a class variable takes only a single memory space, and the class needs to allocate a space for the instance variable each time it creates an instance)
Initialization of instance variables: From a syntactic standpoint, a program can initialize an instance variable in three places:
(1) Specifies the initial value when defining an instance variable.
(2) Specify an initial value for an instance variable in a non-static block.
(3) Specify an initial value for the instance variable in the constructor.
where (1) and (2) both of the initialization times are earlier than (3) in the constructor, (1) and (2) The two initialization sequences are determined by their order in the source code.
Package Com.zlc.array;
public class Testfield {public
testfield (int age) {
System.out.println ("Initialize this.age = +this.age in the constructor");
This.age = age;
}
{
System.out.println (Initialize in non-static block);
age =;
}
Initializes the int age = when defined
;
public static void Main (string[] args) {
testfield field = new Testfield;
System.out.println ("Final age =" +field.age);
}
Run as: Initialize in non-static block
constructor initializes this.age =
Final age =
If you use JAVAP, you can see how the Java class was compiled by Javap-c XXXX (class file). The
specifies the initial value when defining an instance variable. Specifying an initializer statement for an instance variable in the initialization block is equal, and when compiled, they are referred to in the constructor, the int age = 15, which divides the following two steps:
1) int age; When a Java object is created, the system allocates memory for the object based on the statement.
2) Age = 15; This statement is extracted into the constructor of the Java class for execution. Initialization of
class variables: From a syntactic standpoint, a program can initialize a class variable from two places. The
(1) Specifies the initial value when defining a class variable.
(2) a static block that specifies an initial value for a class variable. The
Two order of execution is the same as they were in the source code, and we'll give you a little pervert example:
Package Com.zlc.array;
Class Teststatic {
//class member demo teststatic instance
final static teststatic demo = new Teststatic;
Class member Age
static int =;
Instance variable curage
int curage;
Public teststatic (int years) {
//TODO auto-generated constructor stub
curage = Age-years;
}
}
public class test{public
static void Main (string[] args) {
System.out.println (TestStatic.DEMO.curAge);
Teststatic Staticdemo = new Teststatic ();
System.out.println (staticdemo.curage);
}
The output has two lines of print, one is to print Teststatic class attribute demo instance variable, the second through Java object Staticdemo output teststatic instance properties, according to the example variables and class variables we analyzed above initialization process can be inferred:
1 initialization of the first stage, loading classes for class variables demo, age allocation of memory space, the default values of demo and age are null and 0 respectively.
2 initialization of the second stage, the program sequentially to the demo, the age of the initial value, Teststatic (15) need to call the Teststatic constructor, at this time the age = 0 printing result is 15, and when Staticdemo is initialized, The age has been assigned equal to 20, so the output is 5.
The difference between inheriting a member variable and inheriting member methods in an inheritance relationship
When you create any Java object, the program always calls the parent class's non-static block, the parent class constructor, and finally calls the non-static blocks and constructors of this class. The constructor that invokes the parent class through the constructor of the subclass is generally divided into two situations, one is an implicit invocation, and the other is a constructor that invokes the parent class through super display.
The method of a subclass can call an instance variable of the parent class, this is because the subclass inherits the parent class's member variables and methods, but the parent class's method cannot access the instance variable of the subclass because the parent class does not know which class it will inherit and what member variables it will add to the subclass. Of course, in some extreme cases, you can also implement the parent class to call the subclass variables, such as: The subclass overrides the parent class method, will generally print out the default value, because this time the subclass of the instance variable has not been initialized.
package Com.zlc.array; class father{int age = 50;
Public Father () {//TODO auto-generated constructor stub System.out.println (This.getclass ());
This.sonmethod (), Unable to call info ();
public void info () {System.out.println (age);
} public class Son extends father{int = 24;
Public Son (int age) {//TODO auto-generated constructor stub this.age = age;
@Override public void info () {//TODO auto-generated Method stub System.err.println (age);
public static void Main (string[] args) {new Son (28);
}//Subclass-specific methods public void Sonmethod () {System.out.println ("Son method"); }
}
The
, as we normally infer, calls the constructor of the parent class implicitly through the subclass, the info () method is invoked in the constructor of the parent class (note: I'm not talking about invoking the parent class), which is, by the way, outputting the age instance variable of the parent class, the print result is expected to be 50, but the actual output is 0, Analysis Reason:
1) The memory allocation of a Java object is not done in the constructor, but the constructor completes the initialization assignment process, that is, before invoking the constructor of the parent class, the JVM has sorted the memory space for the son object, which holds two age attributes, One is the age of the subclass and one is the age of the parent class.
2) when calling new Son (28), the current this object represents an object that is a subclass Son, and we can get class by printing the object. GetClass (). The com.zlc.array.Son result, but the current initialization process is done in the constructor of the parent class and cannot be invoked through This.sonmethod () because the compilation type of this is father.
3) When the variable's compile-time type and run-time type are not the same, when you access an instance variable of its referencing object through the variable, the value of the instance variable is determined by the type that declares the variable, but when you call the instance method of the object it references through the variable, the behavior of the method is determined by the object it actually references, So what we call here is the info method of the subclass, so the age of the subclass is printed, and the default value of 0 is printed because the age is not yet urgent to initialize.
colloquially, that is, when the type of the declaration is inconsistent with the type of the true new, the attribute used is a parent class, and the method invoked is a subclass.
by Javap-c We can more directly understand why inheritance properties and methods can be very different, if we take the above example, the subclass son of the info rewrite method, this time will be called the parent class of the info method, is because the parent class's info method is compiled and transferred to the subclass. A member variable of a reputation is left in the parent class without a transfer, and the class and the parent class have an instance variable of the same name, and if the subclass overrides the parent class's method of the same name, The subclass method completely overrides the method of the parent class (as for why Java is so designed, it is not clear to the individual). A variable with the same name can exist without overwriting, and the method subclass of the same name overrides the method of the parent class with the same name.
in general, for a reference variable, when you access an instance variable of an object that it references through this variable, the value of the instance variable depends on the type when the variable is declared, and the method behavior depends on the type of object it is actually referencing when accessing the method of the object it refers to.
finally take a small case review:
package Com.zlc.array; class animal{int age;
Public Animal () {} public Animal (int age) {//TODO auto-generated constructor stub this.age = age;
} void Run () {System.out.println ("animal Run" +age);
Class Dog extends animal{int age;
String name;
Public Dog (int age,string name) {//TODO auto-generated constructor stub this.age = age;
THIS.name = name;
@Override void Run () {System.out.println ("dog Run" +age);
} public class Testextends {public static void main (string[] args) {Animal Animal = new Animal (5);
System.out.println (Animal.age);
Animal.run ();
Dog Dog = new Dog (1, "Xiaobai");
System.out.println (Dog.age);
Dog.run ();
Animal animal2 = new Dog (one, "Wangcai");
System.out.println (Animal2.age);
Animal2.run ();
Animal Animal3;
Animal3 = dog;
System.out.println (Animal3.age);
Animal3.run (); }
}
The method to invoke the parent class can be called by Super, but the Super keyword does not refer to any object, it cannot be used as a true reference variable, and interested friends can study it for themselves.
These are examples of variables and methods, class variables and class methods are much simpler, directly using the class name. The method is very convenient, and will not encounter so much trouble.
Iv. use of the final modifier (especially for macro substitution)
(1) inal can modify the variable, after the final modified variable is assigned the initial value, can not be assigned to the value of him.
(2) Inal can modify the method, the final modified method can not be overridden.
(3) Inal can modify classes, the final decorated classes cannot derive subclasses.
The final modified variable must display the specified initial value:
For final-decorated instance variables, the initial values can only be assigned at the following three specified locations.
(1) Specifies the initial value when defining the final instance variable.
(2) Specify the initial value for the final instance variable in a non-static block.
(3) Specify the initial value for the final instance variable in the constructor.
will eventually be referred to as initialization in the constructor.
For the class variable that is specified with final: The initial value can only be assigned in the two places specified.
(1) Specify the initial value when defining the final class variable.
(2) Specify the initial value for the final class variable in the static block.
Also through the compiler, unlike instance variables, class variables refer to static blocks for assignment of initial values, while instance variables refer to constructors for completion.
The final modified class variable also has an attribute, is "macro substitution", when the modified class variable satisfies the specified initial value when the variable is defined, and the initial value is determined at compile time (for example: 18, "AAAA", 16.78 etc. some direct quantity), Then the final-modified class variable is not a variable, the system is treated as a "macro variable" (the constant we often say), and if the initial value can be determined at compile time, it will not be initialized in the static block, directly in the class definition, instead of the final variable. Let's take that age minus year as an example:
Package Com.zlc.array;
Class Teststatic {
//class member demo teststatic instance
final static teststatic demo = new Teststatic;
Class member age
final static int age =;
Instance variable curage
int curage;
Public teststatic (int years) {
//TODO auto-generated constructor stub
curage = Age-years;
}
}
public class test{public
static void Main (string[] args) {
System.out.println (TestStatic.DEMO.curAge);
Teststatic Static1 = new Teststatic ();
System.out.println (static1.curage);
}
The age of this time is final decorated, so at compile time, all the age in the parent class becomes 20 instead of a variable, so the output can reach our expectations.
Especially when comparing strings, you can show
package com.zlc.array;
public class TestString {static String static_name1 = "Java";
static String static_name2 = "Me";
static String Statci_name3 = Static_name1+static_name2;
Final static String final_static_name1 = "Java";
Final static String final_static_name2 = "Me";
Add final or not all lines the front two can be replaced by a macro. Final static String Final_statci_name3 = Final_static_name1+final_static_name2;
public static void Main (string[] args) {String name1 = "Java";
String name2 = "Me";
String Name3 = name1+name2;
(1) System.out.println (Name3 = = "Javame");
(2) System.out.println (Teststring.statci_name3 = = "Javame");
(3) System.out.println (Teststring.final_statci_name3 = = "Javame"); }
}
There is nothing to say with the final modification of methods and classes, but one cannot be overridden by a quilt (like private), one cannot derive subclasses.
When the local variable is modified with final, the local variables that Java requires to be accessed by the inner class are all decorated with final. There is a reason for this, for a common local variable, its scope stays within the method, and when the method ends, the local variable disappears, but the inner class may produce an implicit "closure" , closures allow local variables to remain in the way that they are.
Sometimes a new thread in a method is called, and then the local variable of the method is invoked, at which point the change amount is declared to be final.
The calculation method of the object occupied memory
using the System.GC () and the Freememory () in the Java.lang.Runtime class, TotalMemory (), maxmemory () measures the size of the Java object. This approach is commonly used when you need to accurately determine the size of an object for many resources. This approach is almost useless for production system caching implementations. The advantage of this approach is that the data type size is irrelevant, and different operating systems can get memory footprint.
It uses the reflection API to traverse the hierarchy of the member variables of an object and to calculate the size of all the original variables. This method does not require so many resources and can be used for caching implementations. The disadvantage is that the original type size is different for different JVM implementations that should have different computational methods.
After JDK5.0, the instrumentation API provides a getobjectsize method to calculate the amount of memory the object occupies.
By default, the size of the referenced object is not computed, and in order to compute the referenced object, you can use reflection to obtain it. The following method is provided in the above article for a calculation containing the size of the referenced object:
public class Sizeofagent {static Instrumentation inst;
/** initializes agent */public static void Premain (String Agentargs, instrumentation instp) {inst = INSTP;
}/** * Returns object size without member sub-objects. * @param o object to get size of * @return Object size */public static long SizeOf (object o) {if Inst = = nul L) {throw new IllegalStateException ("Can not access instrumentation environment.\n" + "please C Heck if jar file containing Sizeofagent class is \ n "+" specified in the Java ' s \-javaagent\ command
Line argument. ");}
return Inst.getobjectsize (o);
}/** * Calculates full size of object iterating over * its hierarchy graph.
* @param obj object to calculate size of * @return Object size */public static long Fullsizeof (object obj) {
Map<object, object> visited = new Identityhashmap<object, object> (); Stack<object> Stack= new Stack<object> ();
Long result = internalsizeof (obj, stack, visited);
while (!stack.isempty ()) {result = Internalsizeof (Stack.pop (), stack, visited);
} visited.clear ();
return result; } private static Boolean skipobject (Object obj, Map<object, object> visited) {if (obj instanceof Str
ing) {//Skip interned string if (obj = = ((string) obj). Intern ()) {return true; } return (obj = = null)//Skip visited Object | |
Visited.containskey (obj); private static long internalsizeof (Object obj, stack<object> Stack, Map<object, Object> visited) {if (Skipobject (obj, visited))
{return 0;
} visited.put (obj, null);
Long result = 0;
Get size of object + primitive variables + member pointers result + = sizeofagent.sizeof (obj);
Process all array elements Class Clazz = Obj.getclass (); if (Clazz.isarray ()) {if (Clazz.getname ()).Length ()!= 2) {//skip primitive type array int length = Array.getlength (obj);
for (int i = 0; i < length; i++) {Stack.add (Array.get (obj, i));
} return result;
//Process All fields of the object while (Clazz!= null) {field[] fields = Clazz.getdeclaredfields (); for (int i = 0; i < fields.length i++) {if (! Modifier.isstatic (Fields[i].getmodifiers ())) {if (Fields[i].gettype (). Isprimitive ()) {continue;//
Skip Primitive Fields} else {fields[i].setaccessible (true);
try {//objects to is estimated are put to stack Object objecttoadd = fields[i].get (obj);
if (Objecttoadd!= null) {Stack.add (objecttoadd);
} catch (Illegalaccessexception ex) {assert false; }}} Clazz = ClazZ.getsuperclass ();
return result;
}
}