`

疯狂java基础功16讲(2)------对象与内存控制

阅读更多
Java内存管理分为两个方面:内存分配和内存回收。
内存分配特指创建Java对象时JVM为该对象在堆内存中所分配的内存空间。
内存回收指的是当该Java对象失去引用,变成垃圾时,JVM的垃圾回收机制自动清理该对象,并回收该对象所占用的内存。

由于JVM垃圾回收机制由一条后台线程完成,本身非常消耗性能的,因此如果肆无忌惮地创建对象,让系统分配内存,这样会有两个坏处:
A:不断分配内存使得系统中可用内存减少,从而降低程序运行性能。
B:大量已分配内存的回收使得垃圾回收的负担加重,降低程序的运行性能。

本课主要介绍
   创建Java对象时的内存分配细节, 即内存管理管理中关于内存分配方面知识。


一、实例变量与类变量
  
   Java程序的变量大体可分为成员变量和局部变量。
   1、局部变量,局部变量可以分为3类。
       A:形参,在方法签名中定义的局部变量,由方法调用者为其赋值,随方法结束消亡
       B:方法内的局部变量,在方法内定义,在方法内对其进行显示初始化,随方法结束消亡。
       C:代码块内的局部变量,在代码块内定主,在代码块内对其进行显示初始化,随代码块结束而消亡。
    局部变量的作用时间很短暂,它们都被存储在方法的栈内存中。 

   2、成员变量,成员变量可以分为非静态变量(实例变量)或静态变量(类变量)
       A:非静态变量,没有使用static修饰符修饰的变量
       B:静态变量,使用了static修饰

public class TwoObject {
	/*1
	//下面代码将提示:非法向前引用
	int num1 = num2 + 2 ;
	int num2 = 3 ;
	*/

	/*2
         //下面代码将提示:非法向前引用
	static int num1 = num2 + 1 ;
	static int num2 = 2 ;
	*/
	
	/*3
	 * num2的初始化时机总是位于num1之前
	 */
	//下面代码完全正常
	int num1 = num2 +1 ;
	static int num2 = 2 ;
	
}


  
   A、实例变量和类变量
      使用static修饰的成员变量为类变量,属于该类本身;
      没有使用static修饰的成员变量为实例变量,属于该类的实例。

   由于同一人JVM内每个类只对应一个Class对象,因此同一个JVM内的一个类变量只需一块内存空间;
   但对于实例变量而言,每创建一次实例,就需要为实例变量分配一块内存空间。

   实例变量属于对象,类变量属于类的特性。
 
public class TwoObject2 {
	public static void main(String[] args) {
		//类变量属于该类本身,只要该类初始化完成,程序即可使用类变量
		Person.eyeNum = 2 ;
		//通过Person类访问eyeNum类变量
		System.out.println("Person 的eyeNum属性:"+Person.eyeNum);
		
		//创建 1个Person对象
		Person p = new Person();
		p.name = "孙悟空";
		p.age = 500;
		//通过p访问Person类的eyeNum类变量
		System.out.println("p.eyeNum="+p.eyeNum);
		p.info();
		//创建第2个Person对象
		Person p2 = new Person();
		p2.name = "唐僧";
		p2.age = 20 ;
		//通过p2修改Person类变量eyeNum
		p2.eyeNum = 3 ;
		System.out.println("p.eyeNum="+p.eyeNum);
		System.out.println("p2.eyeNum="+p2.eyeNum);
		System.out.println("Person.eyeNum"+Person.eyeNum);
		
	}
}

class Person{
	String name ;
	int age ;
	static int eyeNum;
	public void info(){
		System.out.println("name="+name+" age="+age);
	}
}

  

   

   B、实例变量的初始化时机

    对于实例变量而言,它属于Java对象本身,每次程序创建Java对象时都需要为实例变量分配内存空间,并执行初始化。
    程序可以在3个地方为实例变量执行初始化:
       A:定义实例变量时指定初始值;
       B:非静态初始化块中对实例变量指定初始值;
       C:构造器中对实例变量指定初始值;
    A和B两种方式比C种更早执行,A和B的执行顺序与它们在程序中的排列顺序相同。

    定义实例变量指定初始值 、初始化块中指定初始值,地位是平等的,当经过编译器处理后,它们都将被提取到构造器中。并总是位于构造器的所有语句之前;合并后,两种语句的顺序保持它们在源代码中的顺序。

package com.crazyjava;

public class TwoObject3 {
	public static void main(String[] args) {
		Cat cat = new Cat("tom",2);
		System.out.println(cat);
		
	}
}
class Cat{
	String name ;
	int age ;
	public Cat(String name,int age) {
		this.name = name ;
		this.age = age;
	}
	{
		weigth = 2.0 ;
	}
	double weigth = 2.3;
	@Override
	public String toString() {
		return "Cat[name="+name+",age="+age+",weigth="+weigth+"]";
	}
	
}

Output: Cat[name=tom,age=2,weigth=2.3]



   C、类变量初始化时机

       类变量属于Java类本身,只有当程序初始化该Java类时才会为该类分配内存空间,并执行初始化。

       程序可以在2个地方为类变量来执行初始化:
          A:定义类变量时指定初始值
          B:静态初始化块中对类变量指定初始值
       这两种方式的顺序与它们在源程序中排列顺序相同。

package com.crazyjava;

public class TwoObject4 {
	//定义count类变量,定义时指定初始值
	static int count = 2; 
	//通过static块为name指定初始值
	static{
		System.out.println("初始化块");
		name = "Java编程";
	}
	static String name = "疯狂Java讲义";
	
	public static void main(String[] args) {
		System.out.println("count="+count+" name="+name);
	}
}

Output:
初始化块
count=2 name=疯狂Java讲义




二、父类构造器

当创建任何对象时,程序总会先依次调用每个父类非静态初始化块、父类构造器(总是从Object开始)执行初始化,最后才调用本类的非静态初始化块、构造器执行初始化。


三、父子实例的内存控制







四、final修饰符




分享到:
评论

相关推荐

    疯狂Java:突破程序员基本功的16课-高清扫描版带书签

    介绍了Java的对象、数组的内存分配,介绍了常见集合的实现细节、内存回收的细节、表达式、流程控制、面向对象、异常的“陷阱”,常用的数据结构和算法的实现以及其他基础的内容,值得细细阅读。

    java源码包---java 源码 大量 实例

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    疯狂JAVA讲义

    学生提问:构造器是创建Java对象的途径,是不是说构造器完全负责创建Java对象? 141 5.5.2 构造器的重载 142 学生提问:为什么要用this来调用另一个重载的构造器?我把另一个构造器里的代码复制、粘贴到这个构造器...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存...

    java源码包2

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目源代码

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包4

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包3

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    【05-面向对象(下)】

    •Object类提供的equals方法判断两个对象相等的标准与==完全相同。因此开发者通常需要重写equals方法。 类成员 •在java类里只能包含Field,方法,构造器,初始化块,内部类(接口、枚举)等5种成员。 用...

    突破程序员基本功的16课.part2

    第1课 数组与内存控制 1.1 数组初始化 1.1.1 Java数组是静态的 1.1.2 数组一定要初始化吗 1.1.3 基本类型数组的初始化 1.1.4 引用类型数组的初始化 1.2 使用数组 1.2.1 数组元素就是变量 1.2.2 没有多维...

    Java高并发高性能分布式框架从无到有微服务架构设计.doc

    近两年在服务的疯狂增长与云计算技术的进步,让微服务架构受到重点关注 微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互 相协调、互相配合,为用户提供最终价值。每个服务运行在其...

    Java高并发高性能分布式框架从无到有微服务架构设计(1).doc

    近两年在服务的疯狂增长与云计算技术的进步,让微服务架构受到重点关注 微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相 协调、互相配合,为用户提供最终价值.每个服务运行在其独立的...

    grails-microservice-example:用琐碎的Grails 3应用程序替换复杂的Java微服务

    展示了如何使用和在Java中构建微服务。 我为有多少样板感到惊讶。 Gradle项目文件,带有所有Hibernate批注的实体文件以及带有所有疯狂的,自定义的手动路由的Main类。 我可以通过创建一个空的Grails 3项目并添加一...

    写了一首 Java 表白诗,女朋友不愁了!

    一首原创 Java 诗 表白大家了 遇见你的第一天 忍不住内心的躁动 我在心里开辟了一块你的内存区域 和你的每一次美好邂逅 我都封装成记忆 深深将它压入堆栈 舍不得让它逃逸 追求你的队列很长 并发很高 我也加入了竞争 ...

Global site tag (gtag.js) - Google Analytics