1.Java中有几种基本数据类型?
8种:byte shot int long float double char boolean
https://blog.youkuaiyun.com/Sindyue/article/details/88036054
2.面向对象。
思想 https://blog.youkuaiyun.com/zzy0919sun/article/details/81171006
特征 https://blog.youkuaiyun.com/ruglcc/article/details/7604047
多态 https://blog.youkuaiyun.com/zhouym_/article/details/89421577
封装 https://blog.youkuaiyun.com/qq_37872792/article/details/83448479
相对于面向过程实现功能时,想实现功能的一步一步的过程。面向对象先思考需要那些对象。
这些对象的关系关联,继承,聚合,实现,多态。而分析这些关系就有了4大特性:封装,抽象,多态,继承。
封装:一个类有动态属性-方法,和静态属性-字段。将字段私有化,提供公共方法设置
和访问字段。即将对象封装成一个高度自治和相对封闭的个体。
抽象:抽象是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征。如统计成绩,之抽象学生的班级,学号,姓名,分数属性。而无视其他如体重,年龄…属性。所以在抽象时,抽象的角度取决于分析问题的目的。
多态:同一个方法在不同的对象中体现出来不同的状态。如什么意思?小意思,意思意思。
这个意思在不同语境下的不同表现。在开发中的面向接口编程就是多态化的表现。
继承:继承一个对象的所有属性,并在此基础上添加属性。
3.包装类型
https://blog.youkuaiyun.com/qq_34820803/article/details/87938182
基础类型不具备面向对象的特征,所以有了一一对应的引用对象-包装类型。
包装类型和基础类型的转化是在编译时自动装箱Integer .valueOf和拆箱intValue()。
包装类型是引用对象,需要new在堆中,初始值为null。它们的存放地址也不相同,基础类型存在栈中是值传递,而包装类型存在堆中是引用传递。
4.“==”和equals
比较基础类型时比较的时值,比较引用类型时比较的是引用地址。
equals其实和==相同,但它是顶级父类的方法,常用的引用类型重写了equals方法,就变为比较引用类型里的值。
5. String和StringBuilder StringBuffer的区别?
string是一个不可变的char数组,又叫字符串常量。任何改变都是创建了一个新的字符常量。需要操作大量的字符串时损耗内存性能所以我们用StringBuilder StringBuffer 字符串变量。
StringBuffer:线程安全 StringBuilder:线程不安全
执行速度:StringBuilder > StringBuffer > String
用途:
如果要操作少量的数据用String
单线程操作字符串缓冲区下操作大量数据用StringBuilder
多线程操作字符串缓冲区下操作大量数据用StringBuffer
6.java中的集合。
Java的集合存2种值,value和key-value。对应Collection和Map 2大接口。
Collection:接口包含了list和set,的实现类都同时实现类Iterator接口,可以使用迭代器遍历。
List:通常是一个列表(数组、有序/队列、链表、栈等),元素可重复。一般用ArrayList和LinkedList,另外还有不常用的Vector。另外,LinkedList还是实现了Queue接口,因此也可以作为队列使用。
Set:通常表示一个不可重复有序的集合,通过hashcode和equals可去重。常用实现类有HashSet和TreeSet,HashSet是通过Map中的HashMap实现的,而TreeSet是通过Map中的TreeMap实现的。
TreeSet还实现了SortedSet接口,因此是有序的集合(集合中的元素要实现Comparable接口,并覆写Compartor自定义比较函数来排序才行)。
Map:同样抽象类AbstractMap通过适配器模式实现了Map接口中的大部分函数,主要有hashmap,hashtable,treemap。
HashMap可以存空值null但线程不安全,hashtable线程安全但效率低。一般用CurrentHashMap来实现线程安全,通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
而TreeMap与HashMap的区别与Treeset和Hashset的区别相同,tree是以key排序,hash是以存的先后排序。
7.ArrayList和LinkedList。
https://blog.youkuaiyun.com/eson_15/article/details/51145788
ArrayList、LinkedList、Vector和Stack是List的四个实现类,后面2个因为效率低几乎不用。
ArrayList、LinkedList的主要区别是数据结构的区别,ArrayList基于动态数组,LinkedList基于双向链表。
外在表现是访问速度和插入修改的速度的区别。
ArrayList创建对象时,若未指定集合大小初始化大小为0;若已指定大小,集合大小为指定的大小;
当第一次调用add方法时,集合长度变为10和addAll内容之间的较大值;
之后再调用add方法,先将集合扩大1.5倍,如果仍然不够,新长度为传入集合大小;
如果没触发扩容和复制数组添加效率并不低,但触发扩容和复制数组就会损耗较大的性能。
LinkedList对于查询有优化根据查询的元素><size/0.5决定从左查还是从右查。但还是比不过ArrayList的查询速度。
因为链表不要求内存是连续的,在当前元素中存放下一个或上一个元素的地址。查询时需要从头部开始,一个一个的找。所以查询效率低。插入时不需要移动内存,只需改变引用指向即可。所以插入或者删除的效率高。
所以ArrayList使用在查询比较多,但是插入和删除比较少的情况,而LinkedList使用在查询比较少而插入和删除比较多的情况。
8.HashMap
HashMap的初始化创建容器大小为16,负载因子是0.75。当存值的数量超过负载因子时,就会扩容1.5倍。一般用迭代器遍历,这样可以边遍历边修改,删除等操作。
HashMap的hash碰撞:两个key通过hashcode计算的hash值相同时,put就会产生hash碰撞,这时候会以链表存储key-value,如果超过8次会转为红黑树,如果key-value删除到8个又会转回链表。红黑树是jdk1.8引入的。
8.数据结构
分为逻辑结构和物理结构,分别面向问题和面向计算机。
逻辑结构:
1)集合:元素之间除了同属一个集合没有任何联系。
2)线性:元素之间有一一对应的互补关系。
3)树状:一对多的关系。
4)图形:多对多的关系
物理结构:
① 顺序存储:内存中的一段连续的存储单元依次存入线性表的元素,随机查询较快,插入删除需要移动元素。
② 链接存储:不用连续的存储单位,除结尾外其他元素有下一个元素的指针。空间占用更少,插入灵活,查询较慢。
③ 数据索引:多了一个索引表来标识结点的地址,占用空间多但检索快。
④ 散列存储:又叫hash存储,用函数计算出数据的关键字的hash值作为存储地址,这些hash存在散列表,计算函数叫hash函数。
9.算法
做web开发一般不接触算法,最多的是用递归给前台计算级联数据。
集合的Sort()排序方法,这是一个优化了的快速排序方法,加入了插入排序和堆排序,系统会根据情况自动选择。
还有,冒泡排序,二分查找,hash查找。
10.hash 跟B+tree的区别
1)hash只支持in跟=,不支持范围查询,时间复杂度:O(1)
2)B+tree支持范围查询,时间复杂度:O(log n)
3)B+tree 的优点:
1.磁盘读取代价更低
2.查询更稳定
3.有利于数据库的全文扫描
11.JVM虚拟机
不同平台java有不同版本的的虚拟机,这些JVM屏蔽了平台的不同,提供了统一的运行环境,让Java代码无需考虑平台的差异,运行在不同的环境中。
组成:
①.类加载器子系统
②.运行时数据区
方法区 堆 虚拟机栈 本地方法栈 程序计数器
③.执行引擎
即时编译器 垃圾回收
④.本地方法库
12.类加载的过程
类加载的过程包括了加载,验证,准备,解析和初始化这5个步骤
①.加载:找到字节码文件,读取到内存中.类的加载方式分为隐式加载和显示加载两种。隐式加载指的是程序在使用new关键词创建对象时,会隐式的调用类的加载器把对应的类加载到jvm中。显示加载指的是通过直接调用class.forName()方法来把所需的类加载到jvm中。
②.验证:验证此字节码文件是不是真的是一个字节码文件
③.准备:为类中static修饰的变量分配内存空间并设置其初始值为0或null.可能会有人感觉奇怪,在类中定义一个static修饰的int,并赋值了123,为什么这里还是赋值0.因为这个int的123是在初始化阶段的时候才赋值的,这里只是先把内存分配好.但如果你的static修饰还加上了final,那么就会在准备阶段就会赋值.
④.解析:解析阶段会将java代码中的符号引用替换为直接引用.比如引用的是一个类,我们在代码中只有全限定名来标识它,在这个阶段会找到这个类加载到内存中的地址.
⑤.初始化:如刚才准备阶段所说的,这个阶段就是对变量的赋值的阶段.
13.双亲委派机制
我们的程序本来是要通过应用类加载器来加载,但是它不会优先加载,它会先委托给他的父亲(扩展类加载器),它的父亲再委托给他爷爷(启动类加载器),也就是委托给它的两个亲人。所谓就叫双亲委派。有加载规则,优先使用爷爷加载,如果没有加载到再使用它爹加载,如果他爹也没有加载到,才到自己加载,如果自己也没有加载到才报ClassNotFountException。再这过程中只要上一级加载到了,下一级就不会加载了。
如果是导入的第三方的(maven)jar包,就是从自定义加载器加载。这样可以自己修改覆盖第三方jar包。
优点是:
1)不让我们轻易覆盖系统提供功能
2)也要让我们扩展我们功能。
14.JVM内存模型
程序计数器:
程序计数器是一块非常小的内存空间,但主要用途还是用来确定指令的执行顺序。
Java虚拟机栈:
Java虚拟机栈也是线程私有的,每个方法执行都会创建一个栈帧,局部变量就存放在栈帧中,还有一些其他的动态链接之类的。拟机会为每个线程分配一个虚拟机栈,每个虚拟机栈中都有若干个栈帧,每个栈帧中存储了局部变量表、操作数栈、动态链接、返回地址等。
元空间(JDK取代方法区):
元空间并不在虚拟机中,而是使用本地内存,元空间的大小仅受本地内存限制,但可以通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize来指定元空间的大小。
堆内存:
堆内存主要用于存放对象和数组,它是JVM管理的内存中最大的一块区域,堆内存和元空间都被所有线程共享,在虚拟机启动时创建。
执行引擎:
1.即时编译器
2.GC垃圾回收:
判断对象是否已死,是否为垃圾;
1)引用计数算法:被引用计数,到0就定义为垃圾。如果2个对象不是被堆外的变量引用,而是相互引用就会失效。
2)可达性分析算法:从垃圾回收的起点算起,如果一个引用链没到起点,整个引用链都会被定义为垃圾。
3)元空间回收:上面2个是堆内存的回收,而元空间主要是回收无用的常量和类。常量是用引用计数算法,类通过自己的算法ClassLoader回收。
选择垃圾收集算法;
1)标记算法:先标记可回收的对象后回收,效率不高且会产生不规则的内存碎片。
2)复制算法:把内存分2块,存用其中一块,存满后将存活的转移到另一块内存,原来的内存回收,如此反复。缺点是内存空间只能用一半。
3)标记-整理算法:将存活的对象标记转移到内存空间的一端,回收掉其他内存空间。
4)分代收集算法:分为新生代和老年代,新生代分为伊甸区和2个幸存区。新生代的数据创建和销毁都很快,如果幸存就进给幸存区15次垃圾回收都没死的话,进入老年区。如数据太大幸存区装不下会直接进入老年区。
新生代采用复制算法回收,老年代标记-清除和标记-整理算法来进行回收。
选择垃圾收集的时间;
在安全点和安全区回收
选择适当的垃圾收集器清理垃圾(已死的对象)。
15.JVM优化
JVM调优目标:使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
只是在开发微服务时用IDEA对SpringBoot服务调试过,设置堆栈的大小。
本文深入讲解Java中的基本数据类型、面向对象概念、集合框架、JVM内部机制等核心技术,对比HashMap与B+Tree,探讨算法与数据结构,以及JVM优化技巧。
579

被折叠的 条评论
为什么被折叠?



