成员变量:类中方法外;
局部变量:方法定义中或者方法声明上;
(2)在内存中的位置不同
成员变量:在堆中
局部变量:在栈中
(3)生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
(4)初始化值不同
成员变量:有默认值
局部变量:没有默认值,必须定义,赋值,然后才能使用
5、对象的创建和声明周期
对象的创建需要消耗一些资源,尤其是内存资源。
当我们不再需要一个对象时,就要及时清理它,这样占用的资源才能被释放并重复使用。
如果要最大化运行时效率,可以通过栈区(局部变量)来保存对象,或者将对象保存在静态区里,这样在编写程序时就可以明确的知道对象的内存分配和生命周期,这种做法会优先考虑分配和释放内存的速度。但是代价就是牺牲了灵活性,因为你必须在编写代码时就明确对象的数量、生命周期以及类型,但是这种写法的限制性很大。
还有一种方案是在内存池中动态创建对象,这个内存池也就堆。如果使用这个方案,直到运行时你才能知道需要多少对象,以及它们的生命周期和确切的类型是什么。如果需要创建一个新对象,可以直接通过堆来创建。因为堆是在运行时动态管理内存的,所以堆分配内存所花费的时间通常会比栈多一些。栈通常利用汇编指令向下或向上移动栈指针来管理内存,而堆何时分配内存则取决于内存机制的实现方式。
Java只允许动态分配内存,每当要创建一个对象时,都需要使用new来创建一个对象的动态实例。
如果在栈中创建对象,编译器会判断对象存在时间以及负责自动销毁该对象。
如果在堆中创建对象,编译器就无法得知对象的生命周期。
Java支持垃圾回收机制,它会自动找到没用的对象将其销毁。
6、final 和 static
都可以修饰类、方法、成员变量
static可以修饰类的代码块,final不可以
static不可以修饰方法内局部变量,final可以
static修饰表示静态或全局
static修饰的代码块表示静态代码块,当JVM加载类时,只会被创建一次
static修饰的变量可以重新赋值
static方法中不能用this和super关键字
因为this代表的是调用这个函数的对象的引用,而静态方法是属于类的,不属于对象,静态方法成功加载后, 对象还不一定存在。 this代表对本类对象的引用,指向本类已创建的对象。 super代表对父类对象的引用,指向父类对象。 静态优先于对象存在,方法被static修饰之后,方法先存在,所需的父类引用对象晚于该方法的出 现,也就是super所指向的对象还没出现,当然就会报错。
static方法必须被实现,而不能是抽象的abstract
static方法只能被static方法覆盖
final修饰表示常量、一旦创建不可被修改
final标记的成员变量必须在声明的同时赋值,或在该类的构造方法中赋值,不可重新赋值
final方法不能被子类重写
final类不能被继承,没有子类,final类中的方法默认是final的
final不能用于修饰构造方法
private类型的方法默认是final类型的
7、final、finally、finalize
final可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
finally用于抛异常,finally代码块内语句无论是否发生异常,都会在执行finally,常用于一些流的关闭。
finalize方法用于垃圾回收。
一般情况下不需要我们实现finalize,当对象被回收的时候需要释放一些资源,比如socket链接,在对象初始化时创建,整个生命周期内有效,那么需要实现finalize方法,关闭这个链接。
但是当调用finalize方法后,并不意味着gc会立即回收该对象,所以有可能真正调用的时候,对象又不需要回收了,然后到了真正要回收的时候,因为之前调用过一次,这次又不会调用了,产生问题。所以,不推荐使用finalize方法。
8、Java运算符
-
算术运算符
-
关系运算符
-
位运算符
-
逻辑运算符
-
赋值运算符
-
其他运算符
9、循环结构
-
for
-
while
-
do…while
10、条件表达式
-
if…else…
-
switch case
11、super与this
-
super关键字可以在子类的构造方法中显示地调用父类的构造方法,super()必须为子类构造函数中的第一行。
-
super可以用来访问父类的成员方法或变量,当子类成员变量或方法与父类有相同的名字时也会覆盖父类的成员变量或方法,这个时候要想访问父类的成员变量或方法只能通过super关键字来访问,子类方法中的super.方法名()不需要位于第一行。
-
this关键字指向的是当前对象的引用,用来区分成员变量和局部变量(重名问题)
-
this() 不能使用在普通方法中 只能写在构造方法中。
-
必须是构造方法中的第一条语句。
12、方法的重写
父类的功能无法满足子类的需求时,则需要用到重写;
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写的注意事项:
-
参数列表必须完全与被重写方法的相同;
-
返回类型必须完全与被重写方法的返回类型相同;
-
访问权限不能比父类中被重写的方法的访问权限更低;
-
声明为final的方法不能被重写;
-
声明为static的方法不能被重写,但是能够被再次声明;
-
构造方法不能被重写;
-
子类和父类在同一个包中,那么子类可以重写父类所有除了声明为private和final 的方法;
-
如果不能继承一个方法,则不能重写这个方;
-
子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和 protected的非final方法;
-
重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是, 重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性 异常,反之则可以。
13、在 Java 中,什么时候用重载,什么时候用重写?
(1)重载是多态的集中体现,在类中,要以统一的方式处理不同类型数据的时候,可以用重载。
(2)重写的使用是建立在继承关系上的,子类在继承父类的基础上,增加新的功能,可以用重写。
(3)简单总结:
-
重载是多样性,重写是增强剂;
-
目的是提高程序的多样性和健壮性,以适配不同场景使用时,使用重载进行扩展;
-
目的是在不修改原方法及源代码的基础上对方法进行扩展或增强时,使用重写;
14、抽象类和接口
接口和抽象类都遵循”面向接口而不是实现编码”设计原则,它可以增加代码的灵活性,可以适应不断变化的需求。下面有几个点可以帮助你回答这个问题:在 Java 中,你只能继承一个类,但可以实现多个接口。所以一旦你继承了一个类,你就失去了继承其他类的机会了。
接口通常被用来表示附属描述或行为如: Runnable 、 Clonable 、 Serializable 等等,因此当你使用抽象类来表示行为时,你的类就不能同时是 Runnable 和 Clonable( 注:这里的意思是指如果把 Runnable 等实现为抽象类的情况 ) ,因为在 Java 中你不能继承两个类,但当你使用接口时,你的类就可以同时拥有多个不同的行为。
在一些对时间要求比较高的应用中,倾向于使用抽象类,它会比接口稍快一点。如果希望把一系列行为都规范在类继承层次内,并且可以更好地在同一个地方进行编码,那么抽象类是一个更好的选择。有时,接口和抽象类可以一起使用,接口中定义函数,而在抽象类中定义默认的实现。
15、克隆
(1)什么要使用克隆?
想对一个对象进行复制,又想保留原有的对象进行接下来的操作,这个时候就需要克隆了。
(2)如何实现对象克隆?
实现Cloneable接口,重写clone方法;
实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。
BeanUtils,apache和Spring都提供了bean工具,只是这都是浅克隆。
(3)深拷贝和浅拷贝区别是什么?
浅拷贝:仅仅克隆基本类型变量,不克隆引用类型变量;
深克隆:既克隆基本类型变量,又克隆引用类型变量;
16、javac
(1)javac是什么
-
javac是一种编译器,能够将一种语言规范转化成另外一种语言规范
-
javac的任务就是将Java源代码转化成JVM能够识别的一种语言(Java字节码),这种字节码不是针对某种机器、某种平台的
(2)javac编译器编译程序的步骤
① 词法分析
首先是读取源代码,找出这些字节中哪些是我们定义的语法关键词,如Java中的if、else、for等关键词。
语法分析的结果:从源代码中找出一些规范化的token流。
注:token是一种认证机制
② 语法分析
检查关键词组合在一起是不是Java语言规范,如if后面是不是紧跟着一个布尔表达式。
语法分析的结果:形成一个符合Java语言规范的抽象语法树
③ 语义分析
把一些难懂的、复杂的语法转化为更加简单的语法。
语义分析的结果:完成复杂语法到简单语法的简化,如将foreach语句转化成for循环结果,还有注解等。最后形成一个注解过后的抽象语法树,这颗语法树更接近目标语言的语法规则。
④ 生成字节码
通过字节码生成器生成字节码,根据经过注解的抽象语法树生成字节码,也就是将一个数据结构转化成另一个数据结构。
代码生成器的结果:生成符合Java虚拟机规范的字节码。
注:抽象语法树
在计算机科学中,抽象语法树是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
(3)javac编译器的基本结构
按照上述编译步骤来看,可以将javac编译器分为4个模块:词法分析器、语法分析器、语义分析器和代码生成器。
九、Java Character 类
【Java集合 4】Java.lang.Character类详解
十、String
【Java基础知识 7】toString()、String.valueOf、(String)强转、String.valueOf、(String)强转")
【Java基础知识 8】String、StringBuilder、StringBuffer详解
十一、数组
1、概念
同一种数据类型的集合,数组是一个容器。
数组能够对存储的元素进行自动排号,编号从0开始,方便操作。
2、格式
int[] arr = new int[10];
3、初始化
//方式1
int[] arr = { 1, 2, 3, 4, 5 };
//方式2
int[] arr3=new int[3];
arr3[0]=1;
arr3[1]=2;
arr3[2]=3;
4、遍历
public class Test{
public static void main(String[] args) {
String[] arr = new String[3];
arr[0] = “CSDN”;
arr[1] = “哪吒”;
arr[2] = “博客专家”;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
for (String str:arr) {
System.out.println(str);
}
}
}
5、常见异常
-
NullPointerException 空指针异常
-
ArrayIndexOutOfBoundsException 索引值越界
十二、数据保存在哪里
1、寄存器
寄存器是速度最快的数据存储方式,数据直接保存在中央处理器,然而寄存器的数量是有限的,所以只能按需分配。
JVM中有4种常见的寄存器:
-
pc程序寄存器
-
optop操作数栈顶指针
-
frame当前执行环境指针
-
vars指向当前执行环境中第一个局部变量的指针
所有寄存器都为32位。
pc用于记录程序的执行,optop,frame和vars用于记录指向Java栈区的指针。
2、堆与栈
(1)堆内存用于存放new创建的对象
在堆中分配的内存,由JVM自动垃圾回收器管理。
在堆中产生一个对象后,会在栈中定义一个特殊变量,这个变量的取值等于数组或对象在堆内存中的首地址,在栈中的这个特殊的变量就编程了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的对象。
对象在没有引用变量指向它的时候,才会编程垃圾,不能再被使用,但是仍然占着内存,在随后一个不确定的时间点被垃圾回收器释放掉。这也是Java程序比较占内存的主要原因,实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针。
(2)在函数中定义的一些基本类型的变量和对象的引用变量都是在栈内存中分配的。
当一段代码定义一个变量时,java就在栈中分配一个内存,当超过变量的作用域后,java会自动释放掉该变量分配的内存空间。
简而言之,堆是用来存放对象的,栈是运行程序的。
堆:为成员分配和释放,由程序员自己申请、自己释放。否则发生内存泄露。典型为使用 new 申请的堆内容。
栈为编译器自动分配和释放,如函数参数、局部变量、临时变量等等。
如果想迅速进行垃圾回收,可以将对象置为null。
3、常量存储
常量通常会直接写在程序代码中,不可变。
4、非RAM存储
不保存在应用程序里的数据,最典型的例子就是序列化对象,它指的是转换为字节流并可以发送到其它机器的对象。另一个例子则是持久化对象,它指的是保存在磁盘上的对象。也支持使用数据库存储对象信息。
大多数微处理芯片有额外的缓存内存,只不过缓存内容使用的是传统的内存管理方式,而非寄存器。
一个例子是字符串常量池,所有字符串和字符串常量都会被自动放置到这个特殊的存储空间中。
特殊情况 -> 原始类型
原始类型是直接创建一个“自动变量”,不是引用,该变量直接在栈上保存它的值,运行效率更高。
十三、java异常
十四、序列化与反序列化
十五、Java IO流
十六、泛型
在Java5之前,JAVA语言的集合所支持的通用类型是Object。因为单根结构决定了所有对象都属于Object类型,所以一个持有Object的集合就可以持有任何对象,这就使得集合十分易于复用。
其实并不能保存原始数据类型,不过自动装箱机制在一定程度上解决了这个问题。
当集合中持有Object类型时,要添加一个对象到集合中,该对象会向上转型为Object,从而失去了原本的类型。当你需要将其取出时,会获得一个Object类型的对象引用,这就不是当初的类型了,需要进行向下转型。但除非明确知道对象的具体类型,否则向下转型是不安全的,转型失败会抛出异常。
这个问题的解决方式是“参数化类型”,一个被参数化的类型是一种特殊的类,可以让编译器自动适配特定的类型,参数化类型也叫泛型,通过尖括号中间加上类名来定义泛型,比如List。
十七、枚举
十八、注解
十九、动态代理
二十、反射机制
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/08a3ff73c5dcb6555c2c93a58f27df55.jpeg)
Java面试核心知识点笔记
其中囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。
Java中高级面试高频考点整理
最后分享Java进阶学习及面试必备的视频教学
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
图片转存中…(img-b5w7FXKF-1712071672143)]
[外链图片转存中…(img-B5oIzFE5-1712071672144)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/08a3ff73c5dcb6555c2c93a58f27df55.jpeg)
Java面试核心知识点笔记
其中囊括了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。
[外链图片转存中…(img-hID0Fdcx-1712071672144)]
Java中高级面试高频考点整理
[外链图片转存中…(img-rVFslgls-1712071672144)]
[外链图片转存中…(img-lABLshuL-1712071672144)]
最后分享Java进阶学习及面试必备的视频教学
[外链图片转存中…(img-7c1SnK9M-1712071672145)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!