Java知识点梳理(详细)

本文详细介绍了Java的基本数据类型,包括各种整型、浮点型、字符型和布尔型的特性及内存表示。讨论了字符串在内存中的实现,以及Integer对象的自动装箱和拆箱。深入讲解了Java中的字符串常量池、intern()方法以及字符串拼接的优化。此外,还探讨了关键字final、synchronized和try-catch-finally的用法。文章提到了Java多线程的概念,包括线程状态、同步机制以及线程创建与终止的方法。最后,简单提及了Java的反射和注解机制。
摘要由CSDN通过智能技术生成

1. Java中的数据类型

基本数据类型特征表

类型 位数 最小值 最大值 默认值 其他

byte 8 -128(-2^7) 127(2^7-1) 0 有符号、二进制补码表示

short 16 -32768(-2^15) 32767(2^15-1) 0 有符号、二进制补码表示

int 32 -2^31 2^31-1 0 有符号、二进制补码表示

long 64 -2^63 2^63-1 0L(0l) 有符号、二进制补码表示

float 32 2^(-149) 2^128-1 0.0f 单精度、IEEE754标准

double 64 2^(-1074) 2^1024-1 0.0d 双精度、IEEE754标准

char 16 \u0000(0) \uffff(65535) \u0000(0) 单一的、Unicode字符

字符类型涉及到编码问题。

char类型固定为16位2字节长,因为java内码表示字符按照UTF-16存储。而一旦转化为字节就要根据特定的编码格式来看了,例如UTF-8占用1-4字节。出现乱码问题需要分析编码,在windows系统下默认的编码是GBK,使用gradle命令行可能出现乱码(还没发现啥解决办法)。关于字符的一个问题是char是否能表示所有的汉字,我觉得是不能的,可能可以表示常用的所有汉字,但生僻字16位肯定不够的,不然也不至于需要UTF-8多达4个字节来表示汉字。

String内部是通过char数组实现的,生僻字可能需要两个char来表示。

Unicode是一种编码规范,有Unicode编码表,其具体实现有UTF-8, UTF-16, UTF-32等。除此之外还有GBK,GB2312等。

ASCII编码占8位,一个字节就可以表示英文环境所有字符。

引申到MySQL建表过程中需要指定编码,如果是utf8编码可以留意下,一个字符占据可变字节长度,varchar(10)表示的是10个字符而非字节。

GB2312收录了约7000常用汉字,GBK收录了20000+汉字。相关的文章很多,也不是很容易分辨,这里我只列一下结论:GB2312和GBK都继承自ASCII编码,即英文和符号编码和ASCII一致;对于汉字的编码则一律用2字节,能够表示的范围有所不同。而UTF-8编码是1-4字节,汉字绝大多数用3字节表示。

浮点数内存结构

类型 位数 符号位 指数位 尾数位

float 32 1 8 23

double 64 1 11 52

原始数据类型对应的封装对象

(byte, Byte), (short, Short), (long, Long), (float,Float), (double, Double), (boolean, Boolean)

(int, Integer), (char, Character)

【小题】

Integer i = null;

int j = i.intValue();

【答案】编译通过,但运行时报错NullPointerException。

自动装箱和拆箱

Integer i = 100; //自动装箱,编译器执行Integer.valueOf(100)

int j = i; //自动拆箱,编译器执行i.intValue()

由于自动拆装箱的存在,要小心留意i为null。

【小题】

Integer i1 =200;

Integer i2 =200;

System.out.println("i1==i2: "+(i1==i2));

Integer i3 =100;

Integer i4 =100;

System.out.println("i3==i4: "+(i3==i4));

【答案】运行结果为false,true.

首先,==和equals()的区别:

==比较的是两个对象的引用是否相同,或者是比较原始数据类型是否相等;

equals()比较的是两个对象的内容是否相同,可以通过重写equals添加自己的比较逻辑。

其次,-128~127的Integer值可以从缓存中取得,即Integer类型的常用数字缓存IntegerCache.cache。其他情况要重新创建。

public static Integer valueOf(int i) {

if (i >= IntegerCache.low && i <= IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

关于基本数据类型的几点补充

short s1=1; s1=s1+1;

这一句编译错误,因为执行s1+1返回的结果是int类型(执行隐式类型转换)。修改的话要强制转换为short型才可以。

short s1=1; s1+=4;

这一句没有任何问题。

switch语句不能作用于浮点数类型中,可以作用于char, byte, short, int, Character, Byte, Short, Integer, String or an enum.

封装类型+String都是final的,不可被扩展,数字类型的公共父类是Number类,都实现了Comparable接口。

【小题】

public static void main(String[] args) throws Throwable {

int j=0;

for(int i=0;i<1000;i++) {

j=j++;

}

System.out.println(j);

}

【答案】运行结果为0。

解释一(未十分确信):Java使用中间缓存变量机制,j=j++语句会执行为:

temp=j;

j=j+1;

j=temp;

解释二(靠谱):使用javap反汇编命令进行反汇编,其中j=j++对应的结果是(j对应的变量编号是1):

11: iload_1 //将局部变量j的值放到栈顶:0

12: iinc 1, 1 //将局部变量j的值加1,j=1

15: istore_1 //将栈顶的值放到局部变量j中,j=0

所以从底层实现看,j=j++这一句中的自增操作只是对局部变量的操作,局部变量变化后没有存储到栈顶,反而被之前栈顶的值覆盖了,所以相当于不起作用。

数组

3种创建方式

int[] arr1 = {1,2,3,4}; //正确

int[] arr2 = new int[4]; //正确

int[] arr3 = new int[]{1,2,3,4}; //正确

int[] arr4 = new int[4]{1,2,3,4};s //错误,编译不通过

数组越界,抛出
ArrayIndexOutOfBoundsException

数组具有length属性

如果不对数组指定初值,默认初始化为相应数据类型的默认值。

多维数组,嵌套中括号即可。

数组是一种特殊的结构,在数组对象的对象头中需要记录数组长度的信息。JVM中的对象包括三部分,即对象头(Mark Word)、实例数据和对齐填充;而对象头(Mark Word)中又分为三部分,包括运行时信息(gc信息,锁标志位等)、类型指针、如果是数组还需要记录长度。

String

不属于基本类型,内部实际值是一个char[]数组

JDK1.6之前,方法区包括运行时常量池在永久代中;

JDK1.7,方法区和运行时常量池在永久代,字符串常量池在堆中;

JDK1.8,永久代被废弃,方法区在元空间,运行时常量池和字符串常量池在堆中。原文

创建

String s1="ss"; //先将"ss"存储在池中,然后返回引用

String s2=new String("ss"); //创建新对象,使用的"ss"已经在池中

String s3="Prog"+"gramming"; //创建3个对象,均存储在池中

字符串常量池和不可变(Immutable)字符串

字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享。原文

查看源码可以发现,String的定义是public final class String implements java.io.Serializable, Comparable<String>, CharSequence,经过final修饰,无法被继承。

扩展点:封装类型Short, Integer均被final修饰,继承自Number类。

扩展点2: 封装类型Short, Integer等也是不可变类型,内部实际值是对应基本类型的名为value的final变量。

【小题】

String str1 ="abc";

String str2 ="abc";

System.out.println(str2==str1);

System.out.println(str2.equals(str1));

String str3 =new String("abc");

String str4 =new String("abc");

System.out.println(str3==str4);

System.out.println(str3.equals(str4));

【答案】结果是true,true, false, true.前两个String对象从String池中获取,后两个对象是新创建的,内容相同但引用不同。

【小题】

String d ="2";

String e ="23";

e = e.substring(0, 1);

System.out.println(e.equals(d));

System.out.println(e==d);

【答案】结果是true,false.因为substring方法的实现会重新创建String对象。

public String substring(int beginIndex, int endIndex) {

if (beginIndex < 0) {

throw new StringIndexOutOfBoundsException(beginIndex);

}

if (endIndex > value.length) {

throw new StringIndexOutOfBoundsException(endIndex);

}

int subLen = endIndex - beginIndex;

if (subLen < 0) {

throw new StringIndexOutOfBoundsException(subLen);

}

return ((beginIndex == 0) && (endIndex == value.length

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值