学习目标
1、介绍变量命名规则、变量在JVM中的体现
2、介绍Java变量的类型(基本数据类型、引用类型)
3、Java基础数据溢出分析
4、深入理解Java引用类型的级别(强引用、软引用、弱引用、虚引用)
5、讨论Number类(java.lang包中)及其子类
6、包装类与基本数据类型的区别
Java版本
JDK8
介绍Java语言的几种变量
Java语言定义的几种变量
1、实例变量(非静态字段)
2、静态变量(类字段)
3、局部变量
4、常量
package com.sample;
public class VariableSample {
private String p1; // 实例变量
private static String p2; // 类变量
private static final String p3 = "p3"; // 常量
public void play(){
int a = 1; // 基本类型 - 局部变量
String b = "b"; // 引用类型 - 局部变量
}
}
变量命名规则
1、变量名称区分大小写。惯例是用字母开头,而不是“$” 或 “_”,虽然他们在技术上是合法的。
2、字母开头,后续字符可能是 数字、字母、下划线 或 美元符号。
3、选择的名称不能是 关键字 或 保留字。
4、如果你选择的名字只包含一个单词,则全部用小写字母拼出来。如果它包含多个单词,请将每个后续单词的首字母大写。
变量在JVM中的体现
堆:可供各个线程共享的运行时内存区域,也是所有类实例和数组对象分配内存的区域;因此 在存放实例变量 和 类变量时,要考虑线程安全问题。
栈:用于保存局部变量的值,包括:1、用于保存基本类型的值 2、保存类的实例,即堆对象的引用。因为每个java虚拟机线程都有自己私有的Java虚拟机栈,因此 局部变量是线程安全的。
运行时常量池:每一个运行时常量池,都在java虚拟机的方法区中分配。
Java变量的类型
1、基本数据类型
2、引用类型(reference type)
Java基本数据类型
基本数据类型 | 二进制位数 | 默认值 | 使用范围 |
---|---|---|---|
byte | 8 | 0 | -128~127 |
short | 16 | 0 | -32768~32767 |
int | 32 | 0 | -2 31~2 31 -1 |
long | 64 | 0 | -2 63~2 63 -1 |
float | 32 | 0.0f | 此类型不用于精确值,例如货币。为此,您需要改为使用 java.math.BigDecimal类 |
double | 64 | 0.0d | 此数据类型不应用于精确值,例如货币。为此,您需要改为使用 java.math.BigDecimal类 |
boolean | 1 | false | 只有两个可能的值:true和false |
char | 16 | '\u0000' | 它的最小值为'\u0000'(或0),最大值为'\uffff'(或65,535) |
Java基础数据溢出分析
以byte为例,byte的数值是-128~127
package com.sample;
public class NumberSample {
public static void main(String[] args){
byte a = (byte)128;
System.out.println(a);
}
}
输出结果:-128
那么计算机是如何计算溢出数据的呢?
1、 byte是8位的二进制,因此将128转换为8位的二进制源码:1 0000000
2、 将原码转换为反码
符号位 | 数值位 | |
---|---|---|
原码 | 1 | 0000000 |
反码 | 1 | 1111111 |
3、 计算补码,反码 + 1
Java虚拟机中有三种引用类型
1、类类型(class type)
2、数组类型(array type)
3、接口类型(interface type)
这些引用类型的值分别指向动态创建的类实例、数组实例 和 实现了某个接口的类实例 或 数组实例。
深入理解java引用类型的级别
当内存空间还足够时,则能保留在内存之中;如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。很多系统的缓存功能都符合这样的应用场景。因此在JDK1.2之后,将引用分为下面四种级别,这四种引用强度由强到弱。
1、 强引用(Final Reference)
2、 软引用(Soft Reference)
3、 弱引用(Weak Reference)
4、 虚引用(Phantom Reference)
强引用(Final Reference)
1、 类似 Object obj = new Object(); 这类的引用
2、 只要强引用还存在(a、判断对象的引用数量 b、可达性分析算法判断对象的引用链是否可达),垃圾收集器永远不会回收掉被引用的对象。
3、 JVM宁愿抛出OOM异常,也不会回收还存在的强引用所指向的对象。
FinalReference.java源码
package java.lang.ref;
/**
* Final references, used to implement finalization
*/
class FinalReference<T> extends Reference<T> {
public FinalReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
强引用只有一个构造函数,根据所给对象和队列构造一个强引用。
软引用(Soft Reference)
1、软引用用来描述一些有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够内存,才会抛出内存溢出异常。
2、这点很好的解决了OOM问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
例子:
package com.sample;
import java.lang.ref.SoftReference;
public class ParamSample {
public static void main(String[] args)
{
SoftReference softReference = new SoftReference(new String("hello world")); // 软引用
System.out.println(softReference.get());
}
}
弱引用(Weak Reference)
弱引用用来描述非必须对象,它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
例子:
package com.sample;
import java.lang.ref.WeakReference;
public class ParamSample {
public static void main(String[] args)
{
WeakReference weakReference = new WeakReference(new String("hello world"));
System.out.println(weakReference.get()); // 垃圾回收之前,获得弱引用的对象
System.gc(); // 垃圾回收
System.out.println(weakReference.get()); // 垃圾回收之后,获得弱引用的对象
}
}
虚引用(Phantom Reference)
1、 虚引用是最弱的一种引用关系。一个对象是否由虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
2、 虚引用必须和引用队列关联使用。
例子:
package com.sample;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class ParamSample {
public static void main(String[] args)
{
ReferenceQueue referenceQueue = new ReferenceQueue();
PhantomReference phantomReference = new PhantomReference(new String("hello world"),referenceQueue);
System.out.println(phantomReference.get());
}
}
讨论Number类(java.lang包中)及其子类
大部分时间在代码中都使用基本数据类型,然而为了代码的灵活性,Java平台为每种基本数据类型提供包装类。
注意:BigDecimal并BigInteger用于高精度计算。AtomicInteger并AtomicLong用于多线程应用程序。
有如下原因要使用Number对象而不是原始数据:
1、通常用于处理数字集合。
2、要使用类定义的常量(如MIN_VALUE和)MAX_VALUE,它们提供数据类型的上限和下限。
3、 使用类方法将值转换为其他基本类型以及从其他基本类型转换值,转换为字符串和从字符串转换,以及在数字系统(十进制,八进制,十六进制,二进制)之间进行转换。
综上所述:当需要对数据做一些处理时,可以使用Number类及其子类提供的一些方法,以免重复造轮子。
自动装箱
自动装箱是Java编译器在基元类型和它们相应的对象包装类之间进行的自动转换。例如,将int转换为Integer,double转换为Double等等。
Java编译器在原始值为以下情况时应用自动装箱:
1、作为参数传递给期望相应包装类的对象的方法。
2、分配给相应包装类的变量。
拆箱
将包装类型(Integer)的对象转换为其相应的基元(int)值称为拆箱
Java编译器应用拆箱:
1、作为参数传递给需要相应基元类型值的方法。
2、分配给相应基元类型的变量。
包装类 与 基本数据类型的区别
1、包装类是对象,拥有方法和字段,对象的调用都是通过引用对象的地址,基本类型不是。
2、包装类型是引用的传递,基本类型是值的传递。
3、声明方式不同,基本数据类型不需要new关键字,而包装类型需要new在堆内存中进行new来分配内存空间 。
4、存储位置不同,基本数据类型直接将值保存在值栈中,而包装类型是把对象放在堆中,然后通过对象的引用来调用他们 。
5、初始值不同,int的初始值为 0 、 boolean的初始值为false 而包装类型的初始值为null。