配色: 字号:
part2-对象及其内存管理
2018-06-23 | 阅:  转:  |  分享 
  
对象及其内存管理我们知道对于jvm虚拟机具有自动分配内存空间,和自动对失去引用的对象实例进行垃圾回收的共能。但是我们也不能在编程时随意的创
建对象实例。这是因为:不断的分配内存使得系统中可用的内存不断减小,从而降低程序的运行性能。大量已分配的内存的回收使得垃圾回收负担加
重,降低程序的运行性能。失去了引用的实例,则该实例就是垃圾。变量的基本分类局部变量:形参:随方法的结束而消亡。方法内的局部变量:必
须在方法内对其进行显示的初始化,从初始化完成后开始生效,随方法的调用结束而消亡。代码块内的局部变量:必须在代码块内对其进行显示初始
化,随代码块的结束而消亡。总体来说局部变量的特点:作用时间短,且被存放在栈内存中。(从栈内存角度来说,之所以不将实例放到栈内存中而
放在堆内存中,是因为栈内存存的东西的作用时间短,随着方法的消失而消失。而放在堆中,则是由jvm进行垃圾回收,而垃圾回收机制是达到一
定程度才会进行)成员变量:实例变量(非静态成员变量):之所以称其为实例变量,就是因为非静态成员变量是跟随对象的加载而加载,这种变量
其实就是类的实例,存放在堆内存中。有多少个对象,该实例就在内存中开辟了多少块空间。类变量(静态成员变量):之所以称其为类变量,就是
因为静态成员变量跟随类的加载而加载。因此:上述代码可以正常执行,就是因为在初始化一个对象之前,肯定得先初始化该对象所属的类。即类
先加载然后对象才加载类中变量的内存分配类变量、没有继承关系的类的实例变量一定要注意实例变量在堆内粗中是如何展现的。创建了两次对象,
则程序中的实例变量就被分配了两次。每次每个实例变量都被分配了一块内存。而静态变量全局唯一,上述程序虽然给静态变量赋值了两次,但其值
只有一个,就是最后一次的赋值,体现了全局为一。具有继承关系类中的实例变量的内存分配事实上有没有继承关系其实例变量的内存分配都是一样
的。只不过对于具有继承关系的类来说一个对象的实例变量即包含本类的实例变量又包含父类的实例变量,说白了实例变量增多了,但不管多少。创
建一次子类对象,响应的实例变量就被分配一次内存,且都是连续分配(上图中挨着的)。在者若是所创建的对象为多态形式,那么就会出现上图中
两个箭头指向一个实例的情况。从结果更能够说明上述只有s1和s2两个对象.第一图一眼就知道:分配了两次,每次包含了2个实例变量。
每个实例变量对应了一块内存。第二图一眼就知道:分配了两次,每次包含了3个实例变量。每个实例变量对应了一块内存。同时要知道执行过程
是先进行内存空间的分配,然后再进行赋值操作。给对象进行内存分配事实上就是给对象的所有属性进行分配空间,即使该对象在实际过程中并没
有使用该属性,但只要这个属性是该对象的,那么就会给这个属性分配空间。3类中变量的初始化顺序父类类变量、静态块-----
>子类类变量、静态块------>父类实例变量定义、非静态块----->父类构造方法------>子类实例变量定义、
非静态块------->子类构造方法。4、继承之间的访问原则Super和this1、默认在构造器的第一句话为super()。
这就是所说的隐士调用。2、在显示调用时,this()和super()必须写在构造器体中的第一句话位置上。但this.和sup
er.不用。3、this()和super()不可能同时出现在同一个构造器中。4、this()表示的是调用其所在构造器的重载构
造器。也就是说若写成则是错误的。因为this()表示调用的就是publicsom(){}这属于自己调用自己。而若写成就没问题
了,这是因为this(“”)表示调用的是publicTT(Strings)即this(“”)调用了TT()的重载构造器TT(
Strings)5、由于super的隐士存在,则使得父类的构造方法以及非静态块首先执行,然后再执行子类的非静态块和子类构造器。
访问原则子类对象Sons=newSon();多态对象Fatherfs=newSon(
)父类对象Fatherf=newFather();非多态问题子类对象s能够直接使用(即s.父类成员)父类的成员,而父
类对象f不能使用子类的成员。当子类中的属性与父类中的属性或子类中的方法与父类中的方法名称相同时,对于子类对象s,调用相同名称的该方
法或属性,则它会调用子类的该方法或子类的该属性(就近原则)。父类中的全部东西都可以看成是子类的。多态问题多态对像,只能访问父类的成
员变量。多态对象,可以访问父类中的方法(不包括子类对父类重写的方法)若是子类重写了父类的方法,而多态对象又要调用这个方法,那么它调
用的一定是子类的那个重写的方法。父类的所用成员都可以认为是子类的成员,这个再内存分配上有所体现。即当我们创建子类对象时,jvm会同
时为父类的成员属性开辟空间,且父类属性与子类属性相连,共同视为子类的属性。5、多态对象不能调用子类中没有重写的方法。this关键字
特例多态对象的引用类型为编译时类型,实例类型为运行时类型。Fatherf=newSon();其中编译时类型为Fa
ther运行时类型为Son(2)例上述结果为这里必须明白上面的this关键字代表的是父类还是子类,从表面上开应该代表的是父类
。事实上这个this是一个多态对象:这个this首先位于Base构造器中,因此其编译类型为Base。但由于Base构造器是由Der
ived构造器调用的,也就是说Base构造器是运行在Derived构造器中,因此this对象的实例是Derived。最终该this
相当于Basethis=newDerived();这样this对像就具有了多态对象的性质。具体过程:NewDeri
ved();→publicDerived(){i=222;}→publicBase(){System.out
.println(this.i);this.display}→publicvoiddisplay(){System.ou
t.println(i);System.out.println(“dfasdfsadf”)}输出2是因为多态对象只能调用父类的属性
。输出0,是由于父类的构造器先执行,然后在执行子类的实例变量的定义。这个时候子类还没有进行例的定义,因此为i=0final修饰符(
1)final可以修饰变量,被final修饰的变量被赋值后,不能对它重新赋值。(常量)(2)final可以修饰方法,被final修
饰的方法不能被重写。(3)final可以修饰类,被final修饰的类不能派生子类Final修饰的变量Final可以修饰成员变量也可
以修饰局部变量。Final修饰的变量必须显示的赋值,不然错误。final修饰的类变量有两个地方可以指定初始值:定义类变量处、静态
块中;(除此以外都不行)无论那种方式,本质上对于类变量的赋值最终都是再静态块中执行的。final修饰的实例变量由3个地方可以指定
初始值:定义实例变量处、非静态块、构造器;(除此以外都不行)无论那种方式,本质上对于实例变量的赋值最终都是在构造器中执行的。赋
值位置与变量初始化位置是一样的。宏变量(常量)宏变量:条件final修饰的变量2在定义该final类变量时指定了初始值(这里
要求必须是在定义处进行初始化,而在非静态块或构造函数中赋值都是不行的。)3该初始值可以在编译时就被确定下来。注:(1)final
变量本质上已经不再是变量,而是相当于一个常量。如Java的编译与运行首先必须明确java的编译过程和java的运行过程,这两个过
程可以从eclipse角度说,当我们编写完代码后,进行保存操作,该操作其实就是编译文件并生成.class文件的过程。而点击RUNJ
AVA时,这个过程就是运行过程。从命令行来说,javac是进行编译,java命令是运行过程。编译过程:完成的仅仅是对代码的语法检查
。运行过程:完成的是对代码中类的加载以及各个方法的执行。我们之前说宏变量要求必须是在编译前被确定,因此finalinta=
12+Integer.parseInt(“12”);中a就不是宏变量,这是因为执行parseInt()方法是在运行时进行的。而不是
在编译时进行的,因此在编译时是无法确定变量a的值的。所以a就不是宏变量。换句话说,宏变量都是在编译时就能被确定值的。方法中的fi
nal与private我们说final修饰的方法不能被重写。如上图所示一旦被get方法在子类中被重写,则编译时就会报错。但如果将
父类的get方法的public改为private,则在子类中写get方法,就没问题。注意此时子类中的get方法其实并不是重写了父类中的get方法,而是一个属于子自己的一个全的方法。只不过与父类中的get方法重名了。很明显,多态对象所调用的get方法并不是重写父类的方法。因此报错。这是因为当父类中的get方法被private修饰时,说明这个get方法只能被父类访问,而子类不能访问,因此就谈不上重写这一说。
献花(0)
+1
(本文系实习生101首藏)