面向对象(一):基础分析

一、Java中的内存分配

Java 程序在运行时,需要在内存中分配空间。为提高运算效率,对内存空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式与内存管理方式。

1、Class Loader 类加载器

类加载器的作用是加载类文件到内存,编程字节码。比如编写一个HelloWord.java程序,然后通过javac编译成class文件, Class Loader承担加载到内存的责任。

2、STACK 栈:存放局部变量。

  • 数据用完就释放,一定是脱离了它的作用域。
  • Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现java.lang.StackOverflowError异常。常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。

3、HEAP 堆:存储new()出来的东西。

  • 每一个new出来的东西都有引用值。
  • 每一个变量都有默认值
    • byte、shot、int、long 0
    • float、double、0.0
    • char  ‘\u0000‘ 代表空字符
    • boolean false
    • 引用类型 null
  • 使用完毕就变成了垃圾,但是并没有立即回收。会在垃圾回收器空闲的时候回收。
  • 堆内存分为三部分:
    • Permanent Space 永久存储区 。

      • 永久存储区是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用的内存。
    • Young Generation Space 新生区 。
      • 新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。
      • 新生区又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace)。
        • 所有的类都是在伊甸区被new出来的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。
        • 当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1区也满了呢?再移动到养老区。
    • Tenure generation space养老区 。养老区用于保存从新生区筛选出来的JAVA对象,一般池对象都在这个区域活跃。

4、Method Area 方法区

  • 方法区是被所有线程共享,该区域保存所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。
  • static 变量存放于这边,用于共享。
  • String 字符串常量池也在这边。

5、本地方法区(和系统相关)

6、寄存器(给CPU使用)

二、一个对象的内存分配

1、类加载器加载class文件变为字节码存入【方法区】,运行main方法进【栈】。

2、new一个对象,成员变量入【堆】,方法仍存放在【方法区】。

3、方法的调用,从【方法区】加载方法入【栈】,然后调用。执行完毕,从【栈】中被删除。

4、再new同一个对象,会在【堆】张开辟另一块位置,成员变量入【堆】,方法不动。

5、执行完毕,最后main方法,从【栈】中被删除。

6、内存中类的class文件只有一份,即字节码是唯一的。

7、static性质的也只有一份,所以多线程锁要同步static ,可以锁定字节码。

图1,1个对象

图2,2个对象

图3,对象赋值

三、一个对象的内存大小

1、基本数据的类型的大小是固定的,这里就不多说了。

2、对于非基本类型的Java对象,其大小就值得商榷。 在Java中,一个空Object对象的大小是8byte,这个大小只是保存堆中一个没有任何属性的对象的大小。如

<span style="font-family:Arial;font-size:18px;">Object ob = new Object();</span>

3、这样在程序中完成了一个Java对象的生命,但是它所占的空间为:4byte+8byte。4byte是Java栈中保存引用的所需要的空间。而8byte则是Java堆中对象的信息。因为所有的Java非基本类型的对象都需要默认继承Object对象,因此不论什么样的Java对象,其大小都必须是大于8byte。

4、有了Object对象的大小,我们就可以计算其他对象的大小了。

<span style="font-family:Arial;font-size:18px;">Class NewObject {
    int count;
    boolean flag;
    Object ob;
}</span>

其大小为:空对象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小 (4byte)=17byte。但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte的最接近8的整数倍的是24,因此此对象的大小为24byte。

5、这里需要注意一下基本类型的包装类型的大小。因为这种包装类型已经成为对象了,因此需要把他们作为对象来看待。包装类型的大小至少是12byte(声明一个空Object至少需要的空间),而且12byte没有包含任何有效信息,同时,因为Java对象大小是8的整数倍,因此一个基本类型包装类的大小至少是16byte。这个内存占用是很恐怖的,它是使用基本类型的N倍(N>2),有些类型的内存占用更是夸张(随便想下就知道了)。因此,可能的话应尽量少使用包装类。在JDK5.0以后,因为加入了自动类型装换,因此,Java虚拟机会在存储方面进行相应的优化。

四、Java中参数传递问题

(一)论点:Java中只有值传递。

1、基本类型,传的是值,所以不会变。String的效果与基本类型一致。

2、引用类型,传的是地址值,所以会变化。

(二)分析:

1、Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。

  • 基本类型的变量保存原始值,即:他代表的值就是数值本身;

    • 基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress
  • 引用类型的变量保存引用值(地址值)。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址位置。
    • 引用类型包括:类类型,接口类型和数组。

2、【栈】是运行时的单位,而【堆】是存储的单位。

  • 【栈】解决程序的运行问题,即程序如何执行,或者说如何处理数据,调用方法;
  • 【堆】解决的是数据存储的问题,即数据怎么放、放在哪儿。

3、程序运行永远都是在【栈】中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身。

4、Java在方法调用传递参数时,因为没有指针,所以它都是进行传值调用(这点可以参考C的传值调用)。

5、 在【运行栈】中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到【堆】中的对象,这个时候才对应到真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是【堆】中的数据。所以这个修改是可以保持的了。

6、对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。

补充:方法重载

1、特点

1)与返回值类型无关,只看方法名和参数列表。

2)在调用时,虚拟机通过参数列表的不同来区分同名方法。

时间: 2024-10-12 17:12:52

面向对象(一):基础分析的相关文章

python学习 面向对象封装

from collectoins import namedtuplePoint=namedtuple('point',['x','y'])t1=Point(1,2)print(t1.x)print(t1.y)没有方法的类属性不会发生变化    定义简单 不能改变面向对象封装私有属性!!!私有方法!!!用装饰器描述的几个方法@property !!!@classmethod!!@staticmethod! 封装:class Teacher:     def __init__(self,name,p

python—面向对象的封装

封装 私有属性 class Teacher: __identifier = 'Teacher' #私有静态属性 def __init__(self,name,pwd) self.name = name self.__pwd = pwd #私有属性 内部使用,外部不能使用 def pwd(self): print(self.__pwd) alex = Teacher('alex','3714') alex.pwd() class Teacher: __identifier = 'Teacher'

python学习_day26_面向对象之封装

1.私有属性 (1)动态属性 在python中用双下划线开头的方式将属性隐藏起来.类中所有双下划线开头的名称,如__x都会自动变形成:_类名__x的形式.这种自动变形的特点是: a.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果.b.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的.c.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆

python面向对象知识点疏理

面向对象技术简介 类: 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例.class 类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外.类变量通常不作为实例变量使用. 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据. 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖,也称为方法的重写. 实例变量:定义在方法中的变量,只作用于当前实例的类. 继承:即一个派生类(de

php学习笔记 面向对象中[接口]与[多态性]的应用

代码如下: <?php /* 接口技术 * * 接口是一种特殊的抽象类,抽象类又是一种特殊的类 * * 接口和抽象类是一样的作用 * * 因为在PHP是单继承的,如果使用抽象类,子类实现抽象类就不能再去继承其他的类了 * * 如果既想实现一些规范,又想继承其他类.就要使用接口. * * 接口和抽象类的对比 * * 1.作用相同,都不能创建对象,都需要子类去实现 * * 2.接口的声明和抽象类不一样 * * 3.接口被实现方式不一样 * * 4.接口中的所有方法必须是抽象方法,只能声明抽象方法(不

php面向对象

面向对象 什么是面向对象? 面向对象编程(Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构,OOP的一条基本原则是计算机程 序是由单个能够起到子程序作用的单元或对象组合而成,OOP达到了软件工程的三个目标:重用性.灵活性和扩展性.为了实现整体 运算,每个对象都能够接收信息.处理数据和向其它对象发送信息. 什么是面向对象编程呢? 把每个独立的功能模块抽象成类形成 对象,由多个对象组成这个系统,这些对象之间都能够接收信息.处理数据和向其它对象

面向对象注意事项

在面向对象中,有实例变量和类变量,实例变量为类对象的实例成员,而类变量不仅类可以直接调用,而且类的对象也可以调用.类对象可以对实例变量进行添加.修改.删除操作等... 下面就用个示例来做参考: #!/usr/bin/env python # -*- coding:utf-8 -*- class PersonInfo(object): commity_data = 123 def __init__(self,name,age): self.name = name self.age = age de

java面向对象:面向对象的思想和概述

1:面向对象思想 面向对象是基于面向过程的编程思想. 面向过程:强调的是每一个功能的步骤 面向对象:强调的是对象,然后由对象去调用功能 2:面向对象的思想特点 A:是一种更符合我们思想习惯的思想 B:可以将复杂的事情简单化 C:将我们从执行者变成了指挥者 开发,设计,特征 面向对象开发 就是不断的创建对象,使用对象,指挥对象做事情. 面向对象设计 其实就是在管理和维护对象之间的关系. 面向对象特征 封装(encapsulation) 继承(inheritance) 多态(polymorphism

6 面向对象之类和对象

1 面向对象和面向过程的区别 两者都是软件开发思想,先有面向过程,后有面向对象.在大型项目中,针对面向过程的不足推出了面向对象开发思想. 区别: 1)编程思路不同: 面向过程以实现功能的函数开发为主,而面向对象要首先抽象出类.属性及其方法,然后通过实例化类.执行方法来完成功能. 2)封装性:都具有封装性,但是面向过程是封装的是功能,而面向对象封装的是数据和功能. 3)面向对象具有继承性和多态性,而面向过程没有继承性和多态性,所以面向对象优势是明显. 2 类和对象 对象:客观存在的实体(一个具体的