26个Java核心技术点分析讲解,如果你都能看懂,大厂离你还远吗
常常一些核心技术等我碰到的时候才发现自己忘得差不多了,甘心安于现状,等自己跟别人有了差距之后才想起来要学习,我太难了。今天给大家整理分享一下这份文档资料,涵盖26个核心技术点,还有几个不是这么核心的,大家可以根据自身情况学习,如果你需要的话,文末有文档领取方式。
包含内容:
26个知识点
- Java基础,集合,并发,多线程,JVM,设计模式
- Java算法,数据结构
- Spring,MyBatis,MVC,netty,tomcat
- 架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡
- SpringBoot,SpringCloud,Dubbo,Docker
适用人群:
个人认为适用于任何阶段的开发朋友
一.JVM(敲黑板面试重点)
JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、 一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接 的交互。
JAVA 集合JAVA 基础 (敲黑板,基础是重点)
- JAVA 异常分类及处理
- JAVA反射
- Java注解
- Java内部类
- Java泛型
- Java序列化
- Java复制
现在很多的面试对Java基础还是很重视的,我们工作久了会发现突然间感觉自己的java基础知识忘记的很厉害,或者说知识掌握的不牢吧。对一些核心的Java基础知识点也不是很了解,还是需要多加的巩固学习。打好基础
微服务
在介绍微服务时,首先得先理解什么是微服务,顾名思义,微服务得从两个方面去理解,什么是\”微\”、什么是\”服务\”,
微,狭义来讲就是体积小、著名的\”2 pizza 团队\”很好的诠释了这一解释(2 pizza 团队最早是亚马逊 CEO Bezos提出来的,意思是说单个服务的设计,所有参与人从设计、开发、测试、运维所有人加起来 只需要2个披萨就够了 )。 而所谓服务,一定要区别于系统,服务一个或者一组相对较小且独立的功能单元,是用户可以感知最小功能集。
- 服务注册发现
- API 网关
- 配置中心
- 事件调度(kafka)
- 服务跟踪(starter-sleuth)
- 服务熔断(Hystrix)
- API 管理
六.Netty 与 RPCJAVA 算法
算法也是比较重要的一个知识点,一般面试中或多或少的都会涉及到算法题,所以算法也是需要重点了解的一个点。
- 二分查找
- 冒泡排序算法
- 插入排序算法
- 快速排序算法
- 希尔排序算法
- 归并排序算法
- 通排序算法
- 基数排序算法
- 剪枝算法
- 回溯算法
- 最短路径算法
- 最大子数组算法
- 最长公共子序算法
- 最小生成树算法
由于篇幅的限制以及文档资料过多,所以小编挑选了几个核心内容,展示给大家,如有需要完整的文章资料的朋友,可以关注+私信(资料)即可领取
Java核心技术梳理-类加载机制与反射
反射机制是一个非常好用的机制,C#和Java中都有反射,反射机制简单来说就是在程序运行状态时,对于任意一个类,能够知道这个类的所有属性和方法,对于任意一个对象,能够调用它的任意属性和方法,其实初听就知道反射是一个比较暴力的机制,它可能会破坏封装性。
通过反射的定义我们可以想到反射的好处:可以灵活的编写代码,代码可以在运行时装配,降低代码的耦合度,动态代理的实现也离不开反射。
为了更好的理解反射,我们先了解下JVM中的类加载机制。
当程序要使用某个类时,如果这个类还未加载到内存,则需要将其加载到内存中,JVM会通过加载、连接、初始化三个步骤来对该类进行初始化。
类的加载由类加载器完成,类加载器通常由JVM提供的,JVM提供的类加载器通常称为系统加载器,开发者可以通过继承ClassLoader基类来创建自己的类加载器。
类加载加载的是一个二进制数据,这些数据的来源有几种:
- 本地文件系统加载class文件。
- 从JAR包中记载class文件。
- 通过网络加载class文件。
- 把一个java文件动态编译,并执行加载
类加载不一定是要等到首次使用时才加载,虚拟机允许系统预先加载某些类
在类被加载后,系统会为之生成一个对应的Class对象,接着进入连接阶段,连接阶段是把类的二进制数据合并到JRE中,类连接分为三个阶段:
- 验证:检验被加载的类是否有正确的内部结构,并和其他的类协调一致。
- 准备:负责为类变量分配内存,并设置默认初始化值。
- 解析:将类的二进制数据中的符号引用替换成直接引用。
虚拟机负责对类进行初始化,主要是对变量进行初始化,对类变量指定初始值有两种方式:
- 声明类变量时指定初始值。
- 使用静态初始化块为类变量指定初始值。
JVM初始化的几个步骤:
- 假如该类还没有被加载和连接,则程序先加载或连接该类。
- 假如该类的直接父类没有初始化,则先初始化这该类的父类。
- 假如类中有初始化语句,则系统依次执行这些初始化语句。
可以看出当程序主动使用某个类时,一定会保证该类及其所有父类都被初始化。那么在什么情况下系统会初始化一个类活着接口呢?
- 创建类的实例,既包括使用new来创建,也包括通过反射来创建和反序列化来创建。
- 调用某个类的静态方法。
- 访问某个类或接口的类变量。
- 使用反射方式来强制创建某个类或接口对应的java.jang.class对象。
- 初始化某个类的子类。
- 使用java.exe命令来运行某个主类。
类加载器是负责将.class文件加载到内存中,并生成对应的java.lang.Class实例,一旦一个类被载入到JVM中,就不会被载入了,这里就存在一个唯一标识的问题,JVM是通过其全限定类名和其加载器来做唯一标识的,即是通过包名,类名,及加载器名。这也意味着不同类加载器加载的同一个类是不同的。
当JVM启动时,会形成三个类加载器组成的初始类加载器层次结构:
- Bootstrap ClassLoader:根类加载器,负责加载Java的核心类,是由JVM自身提供的。
- Extension ClassLoader:扩展类记载器,负责加载JRE的扩展目录(%JAVA_HOME%/jre/lib/ext)中JAR包中的类。
- System ClassLoader:系统类加载器,负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性或CLASSPATH环境变量指定的JAR包和类路径。
JVM的类加载机制主要有三种:
- 全盘负责:就是当一个类加载器负责加载某个Class时,该class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器载入。
- 父类委托:先让父类加载器试图加载该Class,只有当父类加载器无法加载该类时才尝试从自己的类路径中加载该类。
- 缓存机制:所有加载过的Class都会被缓存,这就是为什么修改代码后必须重新启动JVM修改才会生效的原因。
类加载器加载Class大致如下:
- 检测此Class是否载入过(通过缓存查询),跳至第8步。
- 如果父类加载器不存在,则跳至第4步,如果父类加载器存在,则执行第3步。
- 请求使用父类加载器去载入目标类,成功则跳到第8步,否则跳到5步。
- 请求使用根类加载器来载入目标类,成功则调到第8步,否则跳至7步。
- 当前类加载器尝试寻找Class文件,找到执行第6步,找不到则跳入7步。
- 从文件中载入Class,成功跳入第8步。
- 抛出ClassNotFoundException异常。
- 返回对应的java.lang.Class对象。
JVM中除了根类加载器外的所有类加载器都是ClassLoader子类的实例,我们可以扩展ClassLoader的子类,并重写其中的方法来实现自定义加载器。ClassLoader有两个关键方法:
- loadClass(String name, boolean resolve):该方法为ClassLoader的入口点,根据指定名称来加载类
- findClass(String name):根据指定名称来查找类。
通常推荐findClass(String name),重写findClass()方法可以避免覆盖默认类加载器的父类委托和缓存机制两种策略。ClassLoader中还有一个核心方法Class<?> defineClass(String name, byte[] b, int off, int len),该方法负责将指定类的字节码文件读入到数组中,并把它转换成Class对象,不过这个方法是final,不需要我们重写。
前面的通过类加载机制我们知道,每个类被加载后,系统会为该类生成一个对应的Class对象,通过这个对象就可以访问到JVM中的这个类,在程序中获取到Class的方式有三种:
- 使用Class类中的forName(String name)静态方法,传入的参数是某个类的全限定名。
- 调用某个类的class属性来获取该类对应的的Class对象。
- 调用某个对象的getClass()方法。
在第一个和第二个方法中,都是通过类来获取到Class对象,但是很明显第二种更安全也效率更高。
当我们获取到Class对象后我们可以根据Class来获取信息,Class类提供了大量的方法来获取Class对应类的详细信息,类中主要的信息包括:构造函数、方法、属性、注解,另外还有一些基本属性如:类的修饰符、类名、所在包等。
构造函数:
- Constructor<?>[] getConstructors():返回此Class对象对应类的所有public构造函数。
- Constructor<?>[] getDeclaredConstructors():返回此Class对象对应类的所有构造函数,无权限限制
- Constructor<T> getConstructor(Class<?>… parameterTypes):返回此Class对象对应类的、带指定形参的列表的public构造函数。
- Constructor<T> getDeclaredConstructor(Class<?>… parameterTypes):返回此Class对象对应类的、带指定形参的列表的构造函数,无权限限制。
方法中存在Declared表示无权限限制,后面的也与此相同,后面就不列出
方法:
- Method getMethod(String name, Class<?>… parameterTypes):返回此Class对象对应类的、带指定形参的列表的public方法。
- Method[] getMethods():返回此Class对象对应类的所有public方法
成员变量:
- Field[] getFields():返回此Class对象对应类的所有public成员变量。
- Field[] getField(String name):返回此Class对象对应类的、指定名称的public成员变量
注解:
- Annotation[] getAnnotations():返回修饰该Class对象对应类的所有注解
- <A extends Annotation> A getAnnotation(Class<A> annotationClass):获取该Class对象对应类存在的、指定类型的注解,如果不存在,则返回 null。
内部类:
- Class<?>[] getDeclaredClasses():获取该Class对象对应类里包含的全部内部类。
外部类:
- Class<?> getDeclaringClass():获取该Class对象对应类里包含的所在的外部类
接口:
- Class<?>[] getInterfaces():获取该Class对象对应类里所实现的全部接口
基本信息:
- int getModifiers():返回此类或接口的所有修饰符,返回的int类型需要解码。
- Package getPackage():获取此类包名。
- String getName():获取该Class对象对应类的名称。
- String getSimpleName():获取该Class对象对应类的简称。
- boolean isAnnotation():返回Class对象是否表示一个注解类型。
- boolean isArray():Class对象是否是一个数组。
这里将大体能够获取的类信息列出来了:
生成对象的方式有两种,一种是直接调用newInstance()方法,这种方式是用默认构造器来创建对象,还有一种方式是先获得Constructor对象,然后用Constructor调用newInstance()来创建对象。
上面的例子中,我们可以明确的知道返回的是哪个类,所有调用的方法也和之前对象调用方法没有区别,但是一般在用反射机制时,我们是不知道具体类的,这个时候我们可以使用getMethod获取方法,然后使用invoke来进行方法调用:
一般情况下,我们会使用getXXX()方法和setXXX(XXX)方法来设置或者获取成员变量,但是有了反射后,我们可以直接对成员变量进行操作:
从这里可以看出来,反射破坏了封装性。
为帮助开发者们提升面试技能、有机会入职BATJ等大厂公司,特别制作了这个专辑——这一次整体放出。
大致内容包括了: Java 集合、JVM、多线程、并发编程、设计模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大厂面试题等、等技术栈!
欢迎大家关注头条【JAVA后端架构】,回复【666】,获取以上最新Java后端架构VIP学习资料以及视频学习教程,然后一起学习,一文在手,面试我有。
每一个专栏都是大家非常关心,和非常有价值的话题,如果我的文章对你有所帮助,还请帮忙点赞、好评、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!
java 核心技术-12版 卷Ⅰ- 4.7.1 记录 record
有时,记录就只是数据,而面向对象程序设计提供的数据隐藏有些碍事。考虑一个类Point ,这个类描述平面上的一个点,有x和y 坐标。
当然,可以如下创建一个类
这里隐藏了x和y ,然后通过获取方法来获得这些值,不过,这种做法对我们确实有好处吗?
我们将来想改变Point的实现吗? 当然,还有极坐标,不过对于图形API ,你可能不会使用极坐标。在实际中,平面上的一个点就用x 和y 坐标来描述。
为了更简洁地定义这些类,JDK 14 引入了一个预览特性:“记录”(record)。最终版本在JDK 16 中发布。
记录(record)是一种特殊形式的类,其状态不可变,而且公共可读。可以如下将Point 定义为一个记录:
record Point(double x ,double y){}
其结果是有一下实例字段的类
private final double x;
private final double y;
在Java语言规范中,一个记录的实例字段称为组件(component)。
这个类有一个构造器
Point(double x,double y)
和以下访问器方法
public double x()
public double y()
注意,访问器方法名为 x 和 y ,而不是getX 和 getY。(Java中实例字段可以与方法同名,这是合法的。)
var p = new Point(3,4);
System.out.println(p.x() + \” \” + p.y());
注释:Java没有遵循get 的约定,因为那有些麻烦。对于布尔字段,通常使用is 而不是get。而且首字母大写可能有问题。如果一个类既有x字段又有X字段,会发生什么?有些程序员不太满意,因为他们原来的类不能轻松地变为记录。不过实际上,那些遗留类中,很多都是可变的,所以并不适合转为记录。
除了字段访问器方法,每个记录有3个自动定义的方法:toString 、equals 和 hashCode 。下一章会更多地了解这些方法。
警告:对于这些自动提供的方法,也可以定义你自己的版本,只要它们有相同的参数和返回类型。例如,下面的定义就是合法的:
record Point(double x,double y){
public double x() {
return y; // Bad 语法允许,但实际开发中非常不推荐
}
}
可以为一个记录增加你自己的方法:
与所有其他类一样,记录可以有静态字段和方法:
不过,不能为记录增加实力字段:
record Point(double x ,double y){
private double r ;// ERROR
}
警告:记录的实例字段自动为final 手段。不过,它们可能是可变对象的引用。
record PointInTime(double x, double y, Date when){}
这样的实例将是可变的;
var pt = new PointInTime(0 ,0 , new Date());
p.when().setTime(0);
如果希望记录实例是不可变的,那么字段就不能使用可变的类型。
提示: 对于完全由一组变量表示的不可变数据,要使用记录而不是类。如果数据是可变的,或者数据表示可能随时间改变,则使用类。记录更易读、更高效,而且在并发程序中更安全。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。