java基础

jdk,jre,jvm

从概念上讲JDK是JAVA开发工具,用它来开发JAVA程序,里面有很多基础类库和jre。

JRE是JAVA运行环境,开发出来的JAVA程序只要有JRE(jvm)就能运行。

JVM是JAVA虚拟机,是JRE的一部分,对于JAVA类的操作基本上都是在JVM上完成的

八大基本类型

4种整数类型

​ byte 1字节 8位 范围 -28到28

​ short 2字节 16位 范围 -216到216

​ int 4字节 32位 范围 约21亿

​ long 8字节 64位 末尾加L

byte第一位是符号位 总共8位 int short long都是这样第一位是符号位

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zq5Myo9Y-1670078357516)(…/img/image-20220803144125412.png)]

2种浮点类型

​ float 4字节

​ double 8字节

磁盘中保存形式:

int类型组成部分:符号位和数值位

float类型组成部分:符号位、阶位、数值位

double类型组成部分:符号位、阶位、数值位

double的数值位高达52位,碾压int类型

平均精度:float

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5d5QBiLI-1670078357517)(…/img/image-20220802114129503.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oeY7PVIX-1670078357518)(…/img/image-20220913221812575.png)]

有效位数表示精确度 再长会精度丢失

有效位数:二进制从第一个不为0的数开始数 有多少位

1种字符类型

​ “char”

​ 选择的编码决定 unicode编码 一般2字节 16位

​ UTF-8 大多数2字节16位

​ UTF-16 2或者4字节 在Java中,char类型描述了UTF-16编码中的一个代码单元

​ UTF-32 4字节 固定32位

​ charAt 获取第几个字符

1种布尔类型

​ “boolean” 4字节

**理论上消耗1bit就可以存储一个布尔类型 因为只有true和 false***      ***计算机最小的物理存储单元 --8bit--1B**** 

在java布尔类型 底层是int类型实现的 所以在java中占32bit 牺牲空间提升读取速度的做法

在Java中Boolean类型底层用 int 类型表示,所以分配给它的是32个字节—>在CPU高速缓存区里存储单位是缓存行,每一个缓存行存储64字节,因为通过总线读取时需要通过电压传递,缓存行里面的数据的读取是需要排队的,数据越小排队的越多,所以让boolean类型数据变大,运行就会越快

1、 int类型和float类型哪一个精度更好一些,为什么?如果两个都有精度问题,如何解决?

int类型和float类型两者都是4字节,都是32bit 排列组合的数量是一样的 ,int表示的是等长边距 ,表示范围小,而float类型的范围要大, 所以精度低

单精度浮点数虽然由32位组成,但是其中有1位符号位,8位指数,只有23位是数值尾数。也就是说它的精度仅为23位。

而整型int也由32位组成,它只有1位是符号位,剩下的31位都是数值尾数。

int类型比float类型平均精度高(在-1~1的时候float的精度更高),在float类型范围比int类型大

用bigdecimal和biginteger大数据类型解决

int和float的区别

要知道 int类型float类型 都是32比特

int类型是1bit符号位 +31比特数值位

float类型是1bit符号位 + 8bit指数位+23bit

而且每个数组只能存储同一种类型的数据

float x=10/4;—2.0,后面是int类型

2、java为什么是一个强类型语言?

java对数据的变量有着严格的类型要求,它们在内存中都有着固定的大小。比如int------32bit float------32bit ,每个类型在内存中都代表着一种类型 类型转换的时候非常严格

3、i++和++i

i++的通俗的解释即是先赋值再自增,其实这里赋值的值是从操作数栈取的值,也就是说先将i的值压入栈中,

而自增是局部变量表的值自增。

而++i则相反,是先自增后赋值,就是局部变量表的自增,然后把局部变量表的值压入栈中。

4、位运算

1、<<左移

a=a<<3; 二进制左移三位 相当于乘2^3

N进制左移M位 相当于乘N^M

2、>>右移动 相当于除法 和<<相反

需要注意的是 向右移动的时候需要看符号位了 因为补的是符号位

如果右移3三 符号位是1 那么补上三个1

是0补上三个0

3、>>>右移 和上面的区别就是补的不是符号位了 规定补0

5、每一个数都是转换成二进制 二进制都可以用相加的形式表示出来

所以每一个数都可以用位运算

5、==双等于号

基本类型的 == 比较的是值是否相等

引用类型的 == 比较的是地址是否相等

Object常用方法

equals()、hashCode()、getClass()、notify()、notifyAll()、wait()、wait(long *,int *)、wait(long *,int *)、toString()

Object 中equals 比较两个对象的物理地址是否相等, 比较两个句柄指向的地址(是否是相同的引用),指向的是否是同一个对象

字符串的equals重写后比较的是字面值是否相等

重写equals也必须重写hashCode方法,为什么?因为hashmap需要equals和hashCode配合使用(先hashcode进行比较找到大概的位置,如果相等了就使用equals进行精确判断,如果不相等就不用再次判断了,减少使用equals开销)

然而重写了equals,s1.equals(s2)返回true,根据hashcode的规则,两个对象相等其哈希值一定相等,所以矛盾就产生了,因此重写equals一定要重写hashcode.

equals和hashCode如何组合使用?

toString 输出类的路径以及对象在内存中的地址

getClass 反射获取类信息

notify唤醒进入等待线程的过程

notifyAll唤醒全部进入等待线程的过程

wait等待线程

精度缺失怎么解决?

无限整数类型和 无限小数类型(BigInteger和BigDecimal)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p3GoS18a-1670078357518)(…/img/image-20220805145651488.png)]

进制问题

1、十进制转换成几进制 就一直对这个数求余

3、N进制转十进制

7进制转换成十进制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3HM1ZL7p-1670078357519)(…/img/image-20220805145205341.png)]

数组

特点:

1、数组是连续的 紧挨在一起的

只有基本类型的一维数组在 物理地址上才是连续的

引用类型 二维数组在物理地址不连续

2、数组的数据存在堆内存中

2、下标从0开始

3、只能存储相同类型的数据

4、不能原地扩展

数组为什么物理地址上连续?

计算机只记录第一个比特点的位置

数组只记录第一点的地址代表整个的地址 所以数组是连续的

数组为什么可以通过下标来获取数据 ?

因为物理地址是连续的 因为数组存储的都是相同的数据类型 内存大小是相同的 我们通过截取的方式 拿int类型来说一次截取32位

为什么从0开始?

拿int类型来说 int类型有32位

通过截取的方式 一次截取32比特

从0开始 0*32=0 然后从0截取32位

然后到1的时候 就从第32位继续截取下一个数

如果从1开始的话 就是1*32=32 然后从32开始截取32位 最前面的32位就丢失了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-viEORrgT-1670078357519)(…/img/image-20220901124842738.png)]

数组为什么不能原地扩展?

因为数组是连续的 如果原地扩展的话 一个数移动所有的数都会跟着移动

消耗的时间太多

String、StringBuffer、StringBulider

1、String 存储的核心是char数组实现的,数组在物理上是连续的。String是final修饰的char[]不可变,是不可以在(char[])内存原地址修改数据。

2、StringBuffer:StringBuffer对象是一个字符序列可变的字符串,它没有重新生成一个对象,而且在原来的对象中可以连接新的字符串。

StringBuffer底层是一个char数组,就是相当于用char数组一次性申请足够大的空间,能进行拼接 和缓冲区一样 一次性申请足够大的空间

​ 初始化容量是16

多线程操作字符串缓冲区下操作大量数据 StringBuffer

3、StringBuilder类也代表可变字符串对象。StringBuilder和StringBuffer基本相似,单线程操作字符串缓冲区下操作大量数据 StringBuilder**

字符串的拼接使用的是append()方法

StringBuilder、StringBuffer(锁)的区别?

StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。

4、如何优化StringBuffer性能?

一开始一个合适的初始化容量

尽量减少底层数组的扩容次数

5、总结1:String字符串具有不可变性,当字符串重新赋值时,不会在原来的内存地址进行修改,而是重新分配新的内存地址进行赋值。

总结2:当字符串进行拼接时,也不会在原来的内存地址进行修改,而是重新分配新的内存地址进行赋值

深拷贝和浅拷贝

深拷贝:1、基本类型的拷贝都是深拷贝,因为基本类型占据的空间只在栈中,int a=1,b=a

​ 2、引用类型的深拷贝,就是会在堆中创建一个新的对象,然后复制这个对象的内容,这时栈中会有两个句柄分别指向这两个对象

​ 比如序列化,我要把一个对象从一台电脑传到另一条电脑,就需要用到深拷贝,复制整个对象,然后传过去

浅拷贝, 就是复制一个对象的内存地址,指向的还是堆中的同一个对象

引用传递和值传递

传递的是前面句柄的地址 是引用传递

传递的是后面的值的地址 是值传递

java中只有按值传递

引用传递

如果使用句柄访问的话,Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYHPXBhY-1670078357520)(…/img/image-20220804231757544.png)]

值传递

如果使用直接指针访问的话,Java堆中对象的内存布局就必须考虑如何放置访问类型数据的相关 信息,reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问的开销。。。使用直接指针来访问最大的好处就是速度更快,它节省了一次指针定位的时间开销,由于对象访问在Java中非常频繁,因此这类开销积少成多也是一项极为可观的执行成本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F64sS6UQ-1670078357520)(…/img/image-20220804231817672.png)]

Final、finally

Final

final修饰的类(无法被继承)

final修饰的方法(无法被覆盖,重写),但是可以被重载

final修饰的局部变量(只能赋一次值)

final修饰的引用一旦指向某个对象,则不能再指向其他对象,但是该引用指向的对象的内部数据是可以修改的

final防止指令重排序,保障多线程下的数据安全;

不能同时用abstract和final修饰类(abstract修饰的类是抽象类,抽象类是用于被子类继承的,和final起相反的作用);Final修饰的方法不能被重写,但是子类可以用父类中final修饰的方法

Finally:

finally 不管try catch执不执行,它一定会执行

进行IO操作一定要记住关闭连接

io操作:(内存从磁盘,内存从网络传输大量数据,都是以毫秒为单位的,磁盘转一圈5毫秒,内存到网络传输一般是一毫秒到几十毫秒)

作用:和网络相关,和IO相关的都需要建立连接的,这种连接是会占据存储内存空间的,所以需要关闭连接,finally块一般是用来关闭(释放)物理资源(数据库连接,网络连接,磁盘文件等

当try中有return时执行顺序:return语句并不是函数的最终出口,如果有finally语句,这在return之后还会执行finally(return的值会暂存在栈里面,等待finally执行后再返回)

总结:

try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分为以下三种情况:

情况一:如果finally中有return语句,则会将try中的return语句”覆盖“掉,直接执行finally中的return语句,得到返回值,这样便无法得到try之前保留好的返回值。

情况二:如果finally中没有return语句,也没有改变要返回值,则执行完finally中的语句后,会接着执行try中的return语句,返回之前保留的值。

情况三:如果finally中没有return语句,但是改变了要返回的值,这里有点类似与引用传递和值传递的区别,分以下两种情况:

如果return的数据是基本数据类型,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值。

如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值。

static

1、修饰的变量属于类变量,被所有该类产生的对象共享

2、修饰的方法中不能使用非静态方法但是非静态方法可以调用静态方法

3、修饰静态块 作用:给类进行初始化。随着类的加载而执行,且只执行一次,在main方法之前 ,最开始执行

4、Static 修饰的是静态的 一般可以通过调用类直接访问

但是可以被随便修改 所以常和final一起使用

初始化顺序

父类静态块–子类静态块–父类块–父类构造方法–子类块–子类构造方法

静态初始化块:

静态块和静态变量谁在前面就谁先初始化

作用:给类进行初始化。随着类的加载而执行,且只执行一次,在main方法之前 ,最开始执行

封装

封装(对类信息进行封装) 只对外提供简单的访问入口

​ setter和getter作为操作入口

​ 或者通过构造器访问,实例化对象的时候赋值

面试问题:访问器是如何保证线程安全的?

访问器(set get方法)本身不能保证数据安全 **需要自己写方法(深拷贝)**才能避免被修改 保证安全性 。set get方法只在多线程的情况下进行保护

继承、多态

继承:

一个类可以被多个类继承

继承可以继承父类公共的属性、方法**、除了构造方法、public声明的都可以继承**

提高代码的复用性

多态:

父类的句柄指向子类的对象

向上转型:

父类类型 变量名 = new 子类类型

接口名称 变量名 = new 实现类名称

向下转型:

子类类型 变量名 = (子类类型) 父类对象

实现类名称 对象名称 = (实现类名称) 接口名称

转型前使用instanceof判断

super()

父类对象构造方法中“this()”和“super()”不能同时出现,也就是“this()”和“super()”都只能出现在构造方法的第一行

调用父类被子类重写的方法(super.);当在子类对象中,子类想访问父类的东西,可以使用“super.”的方式访问

调用父类的构造方法;**super()**默认存在构造方法的第一行

this()

This关键字 当前对象

1、this是一个引用,保存内存地址指向自身,就是储存当前对象地址,代表当前对象,所以静态方法不能有this

2、this可以在实例方法和构造方法中出现,那个对象调用这个实例方法,哪个对象就是this

3.this大部分可以省略,不能省略的时候

this.属性名 :一个方法中局部变量和成员变量的名称相同时,就需要用到 this.成员变量 = 局部变量

this.方法名 :让类中的一个方法去调用另一个方法或者实例变量,

this() 只能在构造方法中使用,表示当前构造方法调用本类其他的构造方法,目的是代码复用,但是只能出现在构造方法的第一行,不能和super()同时使用,因为它俩规定都必须在第一行,super是在无参构造器中默认存在一个super()

重载和重写(继承)

重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;

重写发生在子类与父类之间,重写涉及到多态,子类对父类的方法重新定义,子类覆盖父类的方法,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常

抽象类和接口的区别

相同点:

**1、**都是抽象的,不能被实例化

2、当一个非抽象类实现接口或者抽象类的时候,必须将接口和抽象类中所有的抽象方法全部实现

不同点:

1.接口中的方法默认都是抽象的,java8开始有默认方法(default);

抽象类中可以有非抽象方法;

2.接口中的变量都是final类型的

抽象类中不一定

3.一个类可以实现多个接口,但是只能继承一个抽象类

4.一个类要实现接口的所有方法,不一定要实现抽象类中的所有方法

5.抽象类是对象的抽象,是一种模板设计‘;接口是对行为的抽象,是一种行为设计

接口方法的冲突

1、 一个类实现两个接口,两个接口的方法都一样可以吗?可以!

  但是如果两个方法的名称一样,但是两个方法的参数不一样可以吗? 可以,就是方法的重载,再重载一个带参数方法就行了

  但是如果两个方法的名称一样,但是两个方法的返回值类型不一样可以吗? 不可以!

2、如果先在一个接口中将一个方法定义为默认方法, 然后又在超类中定义了同样的方法, 会发生什么情况?

超类优先。如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略。

包装类 128陷阱

为什么有包装类?

因为泛型不支持基本类型 只能是引用类型

**自动装箱和自动拆箱?**基本类型转成包装类叫装箱 ,包装类转成基本类型叫拆箱

面试题128陷阱? Integer在 -128~127之间比较才是true 所以需要比较的时候需要拆箱 intValue()方法拆箱

如果我们的数值在-128-127之间的数值都存储在有一个cache数组当中,该数组相当于一个缓存,当我们在-128-127之间进行自动装箱的时候,我们就直接返回该值在内存当中的地址,所以在-128-127之间的数值用==进行比较是相等的。而不在这个区间的数,需要新开辟一个内存空间,所以不相等。

枚举

正常类有的功能枚举都有

枚举是限定了对象个数的类,无法new对象

一个枚举就是一个对象,会调用对象的构造方法

构造方法是私有(private)类型,防止通过new的方式创建新的对象,因为每次调用对象都会调用构造方法

名而且有相同参数类型的默认方法会被忽略。

包装类 128陷阱

为什么有包装类?

因为泛型不支持基本类型 只能是引用类型

**自动装箱和自动拆箱?**基本类型转成包装类叫装箱 ,包装类转成基本类型叫拆箱

面试题128陷阱? Integer在 -128~127之间比较才是true 所以需要比较的时候需要拆箱 intValue()方法拆箱

如果我们的数值在-128-127之间的数值都存储在有一个cache数组当中,该数组相当于一个缓存,当我们在-128-127之间进行自动装箱的时候,我们就直接返回该值在内存当中的地址,所以在-128-127之间的数值用==进行比较是相等的。而不在这个区间的数,需要新开辟一个内存空间,所以不相等。

枚举

正常类有的功能枚举都有

枚举是限定了对象个数的类,无法new对象

一个枚举就是一个对象,会调用对象的构造方法

构造方法是私有(private)类型,防止通过new的方式创建新的对象,因为每次调用对象都会调用构造方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZvkBHK6u-1670078357521)(…/img/image-20220819221258722.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值