这是我java基础知识的第一篇文章,本来早就写好了直接将markdown文档复制过来发表就好的,结果中途遇到了两个问题:
- 无法使用markdown编辑器,而简书中的文章一旦采用了一种编辑方式之后就不能更改了,可以看markdown编辑器右上角有没有预览按钮来判断是否切换成功.
- 无法将合并了单元格的html代码复制到文章里生成表格(这在typora中是可以的),最后我直接截图复制图片了,效果也可以.
1、8种基本数据类型:
1.1 精度扩展
如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中的两个很有用的类:BigInteger和BigDecimal这两个类可以处理包含任意长度数字序列的数值。BigInteger类实现了任意精度的整数运算,BigDecimal实现了任意精度的浮点数运算。
1.2 char类型的字节长度解释
引用:https://blog.csdn.net/nimasike/article/details/88345414
Java采用Unicode进行编码,char类型在内存中占2个字节-16位,其值的范围在0-65535之间。20 世纪 80 年代开始启动设计 Unicode 编码时,人们认为两个字节(16 位)的代码宽度足以对世界上各种语言的所有字符进行编码,并有足够空间留给未来的扩展。所以在设计 Java 时决定采用 16 位的 Unicode 字符集。目前Unicode编码范围在0-1114111之间,显然一个char类型已经不能够存65535以外的字符了,因此Java采用代理区模式来表示65535以外的字符。
代理区模式:在0-65535之间,保留了一部分数字范围(D800–DBFF)和(DC00–DFFF)。(D800–DBFF)叫高代理区和(DC00–DFFF)叫低代理区,各1024,这两个区组成一个二维的表格,共有1024×1024=210×210=24×216=16×65536,用它们来表示Unicode中65535以后的字符。
1.3 boolean类型的字节长度解释
引用:https://blog.csdn.net/YuanMxy/article/details/74170745
在《Java虚拟机规范》一书中的描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。也就是说JVM规范指出boolean当做int处理,也就是4字节,boolean数组当做byte数组处理,这样我们可以得出boolean类型占了单独使用是4个字节,在数组中是确定的1个字节。
那虚拟机为什么要用int来代替boolean呢?为什么不用byte或short,这样不是更节省内存空间吗。经过查阅资料发现,使用int的原因是,对于当下32位的处理器(CPU)来说,一次处理数据是32位(这里不是指的是32/64位系统,而是指CPU硬件层面),32 位 CPU 使用 4 个字节是最为节省的,哪怕你是 1 个 bit 他也是占用 4 个字节。因为 CPU 寻址系统只能 32 位 32 位地寻址,具有高效存取的特点。
java规范中,没有明确指出boolean的大小。在《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的,取决于java虚拟机。
1.4浮点类型数据的取值范围和精度解释
引用:https://blog.csdn.net/qq_40696431/article/details/89957747
Java语言的浮点类型默认是double类型,如果希望Java把一个浮点类型值当成float类型处理,应该在这个浮点类型值后紧跟f或F。例如,5.12代表一个double类型的值,占64位的内存空间;5.12f或5.12F才表示一个float类型的值,占32位的内存空间。当然,也可以在一个浮点数后添加d或D后缀,强制指定double类型,但通常没必要。
Java还提供了三个特殊的浮点数值:正无穷大、负无穷大和非数,用于表示溢出和出错。例如,使用一个正数除以0将得到正无穷大,使用一个负数除以0将得到负无穷大,0.0除以0.0或对一个负数开方将得到一个非数。正无穷大通过Double或Float类的POSITIVE_INFINITY表示;负无穷大通过Double或Float类的NEGATIVE_INFINITY表示,非数则通过Double或Float类的NaN表示。所有的正无穷大数值都是相等的,所有的负无穷大数值都是相等的;而NaN不与任何数值相等,甚至和NaN都不相等。
只有浮点数除以0才可以得到正无穷大或负无穷大,因为Java语言会自动把和浮点数运算的0(整数)当成0.0(浮点数)处理。如果一个正数除以0,则会抛出一个异常:ArithmeticException:/by zero(除以0异常)。
1.4.1浮点数的组成结构
符号位S,指数位E,尾数位M
例如,一个float类型的数据占用4个字节共32位,其各个组成部分为:
符号位(S):最高位(31位)为符号位,表示整个浮点数的正负,0为正,1为负
指数位(E):23-30位共8位为指数位,这里指数的底数规定为2。并且指数位是以补码的形式来划分的(最高位为指数位的符号位,0为正,1为负)。所以指数位真正范围为:-128~127
尾数位(M):0-22位共23位为尾数位,表示小数部分的尾数,即形式为1.M或0.M,至于什么时候是 1 什么时候是 0,则由指数和尾数共同决定。
1.4.2取值范围
float和double的取值范围是由指数的位数来决定的,其中,负指数决定了浮点数所能表达的绝对值最小的非0数,而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
S:符号位,E:指数位,M:尾数位
float:S1_E8_M23,指数位有8位,指数的取值范围为-27~27-1(即-128~127)
float的取值范围为-2^128 ~ +2^127(1038级别的数)
double:S1_E11_M52,指数位有11位,指取的取值数范围为-210~210-1(即-1024~1023)
double的取值范围为-2^1024 ~ +2^1023(10308级别的数)
1.4.3精度
float和double的精度是由尾数的位数来决定的,float的尾数位有23位,double的尾数位有52位。
float:S1_E8_M23,尾数位有23位,2^23 = 8388608,一共7位,这意味着最多能有7位有效数字,但能保证的为6位,也即float的精度为6~7位有效数字;
double:S1_E11_M52,尾数位有52位,2^52 = 45035 99627 37049 6,一共16位,同理,double的精度为15~16位有效数字。
2、变量类型
类变量:定义在类中且在方法、语句块外面,被final/static关键字修饰的变量。
成员变量(全局变量):定义在类中且在方法、语句块外面的变量就是成员变量。
局部变量:定义在方法、语句块中,需要给局部变量赋初值,否则会出现编译期异常。
变量类型 | 类变量(静态变量) | 成员变量(全局变量、实例变量) | 局部变量 |
---|---|---|---|
销毁时间 | 在第一次被访问时创建,在程序结束时销毁 | 在对象创建的时候创建,在对象被销毁的时候销毁 | 在方法或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁; |
修饰符 | public/private,final static | 访问修饰符(public/private/default/protected) | 访问修饰符不能用于局部变量 |
默认值 | 与实例变量一致 | 数值型变量是0,布尔型变量是false,引用类型变量是null,char类型是空字符('\u0000') | 没有默认值,必须要进行初始化 |
3、修饰符
修饰符分为访问修饰符与非访问修饰符。
3.1访问修饰符(访问权限控制)
public(公有访问修饰符):被声明为public的类、方法、构造方法、接口能被任何其他类访问。
protected(受保护的访问修饰符):protected 可以修饰数据成员(变量),构造方法,方法成员(方法),不能修饰类(内部类除外),且能被同一个包下的类访问。接口及接口的成员变量和成员方法不能声明为 protected。
子类与基类在不同包中,子类实例可以访问从基类继承而来的protected方法,而不能直接访问基类的protected方法。(仅针对protected方法)
default(默认访问修饰符):使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。
private(私有访问修饰符):在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
访问控制修饰符 | 当前类 | 同一包内 | 不同包内(子孙类) | 其他包 |
---|---|---|---|---|
public | Y | Y | Y | Y |
protected | Y | Y | Y/N | N |
default | Y | Y | N | N |
private | Y | N | N | N |
3.2非访问修饰符
- static 修饰符,用来修饰类方法和类变量。
-
静态变量:
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
静态方法:
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
abstract 修饰符,用来创建抽象类和抽象方法。
synchronized 和 volatile 修饰符,主要用于线程的编程。
4、接口、抽象类的注意事项
4.1抽象类
抽象类与抽象方法都由abstract修饰符修饰,抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充,它需要被一个子类继承。
抽象类中含有抽象方法也可以含有非抽象方法(抽象类中也可以不包含抽象方法),但若类中含有抽象方法则该类必须是抽象类。
抽象方法没有方法体public abstract sample();,该方法的具体实现由子类提供(除非子类也是抽象类),且子类必须要实现所有的抽象方法。
4.2接口
接口在 Java 中是一个抽象类型,是抽象方法的集合;接口通过关键字 interface
来定义。
接口是隐式抽象的,所以声明时没有必要使用 abstract
关键字;接口的每个方法都是隐式抽象的,所以同样不需要使用 abstract
关键字;接口中的方法都是隐式 public
的。
抽象类存在的意义:
如果类直接实现该接口的话,就需要对接口中的所有方法进行实现。
如果我们只需要对接口中某一部分方法进行实现的话,就可以使用一个抽象类作为中间件,即适配器(AdapterCoach),用这个抽象类实现接口,并对抽象类中的方法置空(方法体只有一对花括号),这时候新类就可以绕过接口,继承抽象类,我们就可以只对需要的方法进行覆盖,而不是接口中的所有方法。
接口与抽象类的区别与联系:
抽象类可以有非抽象方法,但接口没有。
接口中的成员变量隐式为
static final
,但抽象类不是的。一个类可以实现(implements)多个接口,但只能继承(extends)一个抽象类(可以多重继承)。
接口中的所有方法都必须实现;若子类也是抽象类则抽象方法可以不用全部实现,否则也要全部实现。
接口可以继承接口,抽象类不可以继承接口,但可以实现接口,抽象类可以继承实体类。