Java教程

Java基础(7)

本文主要是介绍Java基础(7),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

成员应用细节

JVM主要包括三块内存空间,分别是栈内存、堆内存和方法区

Java虚拟机包含类装载器子系统、执行引擎、运行时数据区、本地方法接口和垃圾收集模块。

  • 类装载器子系统:根据给定的全限定类名(如: java.lang.Object)来装载class文件到运行时数据区域的方法区中。

  • 执行引擎:执行字节码或执行本地方法。

  • 运行时数据区:就是常说的JVM的内存,堆,方法区,虚拟机栈,本地方法栈,程序计数器。

  • 本地方法接口:与本地方法库交互,作用就是为了融合不同编程语言为Java所用,它的初衷是融合C/C++程序

首先通过编译器把Java代码转换成字节码,类加载器再把字节码加载到内存中(运行时数据区的方法区内),而字节码文件只是JVM的一套指令集规范,不能直接交给底层系统去执行,所以需要特定的命令解析器执行引擎将字节码翻译成底层系统指令,再交给CPI去执行,而这个过程需要调用其他语言的本地库接口来实现整个程序的功能。

方法的代码片以及整个类的代码片断被存储到方法区内存中,在类加载的时候这些代码片段会被载入。方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

  • JDK 8完全废弃了永久代的概念,改用在本地内存中实现的元空间来代替,JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。异常情况:方法区无法满足新的内存分配需求时,将抛出OOM异常
  • 运行时常量池是方法区的一部分。并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

方法执行使用的是栈,该方法需要的内存空间在栈内存中分配,称为压栈。方法执行结束后,该方法所占用的内存空间自动释放,称为弹栈。栈中主要存储的是方法体当中的局部变量。

引用和指针的区别:

引用也叫句柄,类似于指针,但是和指针是不同的。指针是一个存放地址的变量,使程序员可以灵活的访问内存,由于可以对指针进行任意的运算操作,所以给程序带来了安全隐患和意想不到的结果。引用继承了指针节省内存的优点,但是限制了对地址的操作,它是安全的。Java中所有的变量都是一个引用,java中没有指针的概念。

Person p=new Person();--调用的是Person类中的无参构造器
class Person{
	private String name;
    private Job[] jobs;
}

在程序执行过程中使用new运算符创建的java对象,存储在堆内存中。对象内部有实例变量,所以实例变量存储在堆内存当中。

变量分类

  • 局部变量,方法体中声明

  • 成员变量,方法体外类内声明

    • 实例变量,没有static修饰符,各个不同对象相互隔离
    • 静态变量,有static修饰符,这个类的所有对象共享
    • 静态变量存储在方法区内存中
  • 三块主要内存中变化最频繁的是栈内存,最先有数据的是方法区内存,垃圾回收期主要针对的是堆内存

相关问题

问:自动垃圾回收机制GC什么时候会将java对象的内存回收?

答:当堆内存中的对象称为垃圾数据的时候会被GC回收

问:什么时候堆内存对象会变成垃圾?

答:1、引用计数法:为每个对象创建一个引用计数器,有对象引用时计数器+1,引用被释放时计数器-1,当计数器为0时就可以被回收。它有一个缺点就是不能解决循环引用的问题。
2、可达性算法(引用链法)︰从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是可以被回收的。

总结

  • 栈内存存储基本类型的变量和对象的引用变量

  • 堆内存用于存放由new创建的对象和数组。每new一个对象就在堆内存中开辟一个新的存储空间存储此实例对象

  • Person p = new Person()执行new命令时程序执行两步:a:在堆内存中开辟一段空间,存储new出来的对象;b:在栈内存中添加一个变量p,p中存放的是该对象在堆内存中开始存放处的物理地址

  • p = null;执行此步骤的时候程序只是更改栈内存中的p变量所保存的地址,把地址指向null,而并没有操作堆内存(把p所指向的对象实例清空回收)

  • 无论是形参或者实参,执行XXX = null;操作时都是把XXX变量栈中存储的地址改为指向null的地址。不操作堆中的数据。

public void pp(int k) {
	System.out.println(k);
}

pp(1);

具体问题

问:由类创建一个对象,JVM内存中发生了哪些事情?

答:MyClass mc = new MyClass();以这条语句为例, MyClass mc =使虚拟机栈中生成了一个指向MyClass对象的地址;new MyClass()则在堆中分配了对象mc成员变量的空间。

栈和堆的区别

  • 管理方式:栈自动释放,堆需要GC
  • 空间大小:栈比堆小
  • 碎片相关:栈产生的碎片远小于堆
  • 分配方式:栈支持静态和动态分配,而堆仅仅支持动态分配
  • 效率:栈的效率比堆高

方法的问题

方法的分类:

  • 无参无返(没有参数列表,没有返回值)单纯的作为功能代码的聚合使用便于功能复用

  • 无参有返(没有参数列表,有返回值)

  • 有参无返(有参数列表没有返回值)适用于功能需要根据参数来进行计算的情况,但是计算的最终结果又无需返回处理

  • 有参有返(有参数列表,有返回值)适用于功能需要根据参数来进行计算的情况,而且最终的结果需要返回处理

方法的形参和实参:

  • 形参:是定义在方法声明上,用于指定该方法需要传递的参数类型的

  • 实参:是调用方法时,实际传递的参数值

方法参数传递

  • 基本数据类型作为参数传值:传值传的时值的内容,来到另一个方法空间之后,这个值和之前没有任何关系。(如:拷贝分享的网盘内容,不会改变原有的网盘内容)
  • 引用数据类型作为参数传值:传值传的时对象在堆的地址值,所以了两个内容指向了同一空间是相互影响的。(如:登陆网盘后拷贝内容,改变的话会改变我的网盘内容)

基本数据类型的对象缓存

在不可变类Integer类定义中查看源代码可以发现一个定义

private static class Integercache {}
//这实际上就是Integer的cache

Integer num1 = 12;
Integer num2 = 12;
System.out.println(num1 == num2);//这块相等,<=127都是真的

是因为在Integer中包含有一个缓存池,缓存值为-128到127之间。

  • 定义Integer k1=12是先在缓存池中查找12这个对象,如果有则直接使用
  • new Integer(12)一定会引发对象的创建,而不管缓存池中是否包含这个对象
Integer k1 = 12;
Integer k2 = 12;
System.out.println(k1 == k2); //true,k1和k2都是引用类型,所以==比较的是地址

Integer k3=new Integer(12);
System.out.println(k1==k3) ; //false

Integer k4 = 129;
Integer k5 = 129;
System.out.println(k4 == k5); //fa1se,因为缓存只缓存-128到127之间的数据

Integer\Long\Short\Byte中都有缓存池、charactcr中也有缓存池;boolean只有true、falsc两个

字符串缓存池

String中包含一个缓存池,当使用某个字符串对象时会首先在缓存池中进行查找,如果存在则直接返回这个对象的地址;如果不存在则会在缓存池中进行创建,创建完成后返回地址。

String s1="abc " ;
String s2="abc ";
String s3=new String("abc"); //这里会创建2个对象,一个在缓存池中,一个是new导致的新创建对象
System.out.println(s1==s2) ; //true
System.out.println(s1==s3); //false

注意:如果通过字串拼接所得内容和某个字串内容一致,但是地址不同

零散知识点

方法中的可变长个数的参数

语法:数据类型…变量名。必须作为最后一个参数出现
具体处理过程中实际上是按照数组的方式进行处理, 而且数组不会为null

public void aa(int...k) {
	if(k.length>O〕{
		for(int i = 0;i<k.length;i++)
			System .out.print1n(k[i]);
	}
}

void pp(Object… arr)可变长参数可以是Object[ ] 数组
注意: 一个方法的最后一个位置只有一个, 所以方法中的可变个数的参数只能有一个

装箱/拆箱

值类型自动转换成它对应的类类型—autoboxing
类类型自动转成它所对应的值类型—unboxing

  • 装箱。如:Integer a = 9;
  • 将一个对像自动转成基本类型就叫拆箱:int c = new Integer(9);
这篇关于Java基础(7)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!