【Java】java基础知识整合

数据结构及排序

&与&&的区别

&是位运算符,表示按位于运算,&&是逻辑运算符,表示逻辑与

Collection和Collections的区别

Collection是集合类的上级接口,继承于它的接口主要有list和set,而Collections是针对集合类的一个帮助类,提供一系列的集合的搜索,排序,线程安全性等操作。

length方法

数组有没有length()的方法,String有没有length()方法
数组没有length()方法,有length属性,String有length()方法
Overload和Override的区别,Overload能不能改变返回值的类型

重写与重载

方法的重写和重载是Java的多态性的不同表现,重写是父类和子类的多态性的表现,重载是一个类中多态性的表现,重写:父类和子类中定义了相同的方法名和参数,子类在使用这个方法是调用的是子类中的逻辑,父类的定义如同被屏蔽;

重载:同一类中定义了多个同名称的方法,他们或者有不同的参数类型或者有不同的参数个数,并且重载的方法是可以改变方法值的类型的set里的元素是不能重复的,那么用什么方法来区分重复与否,用equels还是用呢,它们有什么区别set元素是不能重复的,是用iterator()来区分重复与否的,使用equels()来判断两个set是否相等,equels()和==方法决定引用值是否指向同一个对象,equels()在类中被覆盖是为了当两个分离的对象的内容和类型相匹配的话,返回真值,
try{}里边有一个return,并且try后面紧跟着一个finally{},那么finally里边的逻辑会不会执行?finally里边的语句会执行,并且在return之前执行

int和Integer的区别

Java提供的两种不同的类型,引用类型和原始类型,int 是Java原始数据类型,Integer是Java为int提供的封装类,Java为每个原始类型都提供了封装类,引用类型和原始类型的行为完全不同并且它们具有不同的语义,引用类型和原始类型具有不同的特征和方法,包括大小和速度问题,引用默认值的不同

面向对象的特性:封装,继承,多态和抽象。

封装:给对象提供了隐藏内部的特性和行为的能力,对象提供一些能被其他对象访问的方法来改变它内部的数据
继承:给对象提供从基类获取字段和方法的能力
抽象:把想法从具体的的实例中分离出来的步骤
多态:编程语言给不同的底层数据类型做相同的接口展示的一种功能,,一个多态类型上的操作可以应用到其他的类型的值上面
同一个接口使用不同的实例而执行不同的操作,父类引用变量通过指向不同的子类对象来调用不同的子类实现方法。

什么是Java虚拟机,为什么Java被称为平台无关的编程语言

Java虚拟机是一个可以执行Java字节码的虚拟机进程,Java源文件被编译成可以供Java虚拟机编译的字节码文件,Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者重新编译,Java虚拟机让这个变成可能,因为它知道底层硬件平台的指令和其他特性
JDE和JRE的区别是什么
JRE :Java运行时环境,是将要执行的Java程序的Java虚拟机,同时也包含applet需要的浏览器插件,
JDK:是完成的Java软件开发包,包含了JRE,编译器和其他工具
自动装箱:是Java编译器在基本数据类型和对应的对象包装类型之间做一层转换,,比如int转Integer。。。反之则是自动拆箱
是什么值传递和引用传递
对象被值传递说明传递的是对象的一个副本,因此就算改变了对象的副本,也不会影响原对象的值
对象被引用传递说明传递的并不是实际的对象,而是对象的引用,因此外部对引用对象所做的改变会反射到所有的对象上
Iterator和ListIterator区别
Iterator只能向后遍历,而ListIterator可以双向遍历并且提供更多的方法,增加元素和替换元素,或者获取前一个或者下一个元素的下标

HashMap和HashTablede 的区别

HashMap允许null键和null值,而HashTable不允许null键和null值
HashTable是同步的,而HashMap不是,HashMap适合单线程,HashTable适合多线程,
HashMap 实现了Iterator,而HashTable实现了Enumeration,并且Enumeration的速度是Iterator的两倍同事占更少的内存,但是Iterator比Enumeration更安全,因为其他线程不能修改正在被Iterator遍历的集合中的对象,同事允许调用者删除底层集合中的元素而Enumeration则不允许

多线程、反射、JVM,Spring源码交流、Spring MVC深入交流,分布式,负载均衡,高并发 CRUD

数据库优化:

  1. 对查询进行优化,尽量避免全表扫描,首先考虑在where及order by的列加索引
  2. 尽量避免在where子句中进行null值判断,否则将导致搜索引擎放弃使用索引而进行全表扫描,
  3. 尽量避免在where子句中使用!=和<>操作符,否则搜索引擎将放弃使用索引而进行全表扫描
  4. 尽量避免where子句中使用or来连接条件,如果一个字段有索引一个字段没索引,将导致搜索引擎放弃索引而进行全表扫描

ThreadLocal和Synchonized的作用:

ThreadLocal是解决线程安全的一个很好的思路,它通过为每一个线程提供一个独立的变量副本来解决变量并发访问的冲突
Synchonized则是用于线程间的数据共享
ThreadLocal则是用于线程间的数据隔离
Synchonized是利用锁的机制,使变量和代码块在某一时刻只能被一个线程所访问,而ThreadLocal则为每一个线程提供一个变量副本,使得
每一个线程在同一时刻访问到的都不是同一个变量,这样就隔离了多线程之间的数据共享。

线程池:

  1. newFixedThreadPool(int poolSizes); 创建一个固定长度的线程,每当提交一个任务就创建一个线程,达到最大值的时候就不会创建,如果出现未逾期的错误而结束的时候,线程池会补充一个新的线程
  2. newCachedThreadPool(); 创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加线程,线程池的规模不存在任何限制
  3. newSingleThreadExecutor():这是一个单线程的executor,它创建单个线程在执行任务,如果这个线程异常结束,会创建一个新的来替代它,它的特点是能确保依照任务在队列中的顺序来串行执行
  4. newScheduledThreadPool(int poolSizes):创建一个固定长度的线程池,可以延时或者定时的方式来执行任务,类似于timer

高数据并发下的数据安全:

  1. 悲观锁:锁住数据库,但是这种不是很好,在高并发下,会因为请求太多呗阻塞而导致系统瘫痪。
  2. 队列的思想:将请求都放在队列中,先进先出嘛,问题是,高并发时,一瞬间队列空间会被撑爆,或者也可以理解成队列太大,最终处理时间还是会变长,最终导致系统异常
  3. 乐观锁:这个比较合适,当数据来访问的时候,都可以访问,但是得加上version,只有在version最前的时候最终才能执行成功,其他的用户都回滚。
    总结:尽量将请求拦截在系统上游,读多写少的多使用缓存。

String,StringBuffer和StringBuilder

String值是不可变的,每次操作都会产生新的对象。
StringBuilder是线程不安全的,效率高是可变的字符串序列,
StringBuffer是线程安全的但是效率低,是可变的字符串序列,有一定的缓冲区,当字符串大小没有超过容量时,不会产生新的对象

总结: String适用于少量的字符串操作的情况

StringBuilder适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer适用于多线程下载字符缓冲区进行大量操作的情况

线程的生命周期:

新建:从新建一个线程对象到程序start()这个线程之间的状态,都是新建状态
就绪:线程对象调用start()方法后就处于就绪状态,等JVM里的线程调度器的调度
运行:就绪状态下的线程在获取到CPU资源后就可以执行run(),此时的线程便处于运行状态,运行状态的线程可变成(就绪,阻塞和死亡)
等待/阻塞/睡眠:在一个线程执行了sleep(睡眠),suspend(挂起)等方法后就会失去所占用的资源,从而进去阻塞状态,在睡眠结束后重新进入就绪状态
终止:run()方法完成后或发生其他终止条件时就会切换到终止状态

数据库优化:

数据库集群,分库分表,读写分离,添加索引,适当添加冗余字段,尽量单表操作,少使用*查询

TCP协议的三次握手和四次挥手:

三次握手:
  1. 客户端将标志位SYN置为1,随意产生一个值seq=j,并把该数据包发送给服务端,客户端随之进入SYN_SENT状态,等待服务端确认。

  2. 服务端收到数据包之后,由标志位SYN=1知道客户端想要建立连接,服务端将 SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K
    并将该数据包发送给客户端以确认请求连接,服务店进入SYN_RECV状态

  3. 客户端收到确认后检查数据包中的ack是否为j+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务端,服务端检查数据包中的ack是否为K+1,ACK是否为1,如果正确则连接加入成功,客户端和服务端都进入ESTABLISHED状态,完成三次握手,随后就可以传递数据了

  4. SYN攻击(DDOS攻击)在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:netstat -nap|grep SYN_RECV

    四次挥手:

    1. 客户端发送一个FIN,用来关闭客户端到服务端的数据传输,客户端进入FIN_WAIT_1状态
    2. 服务端收到FIN后,发送一个ACK给Client,确认序列号为收到的序号+1,服务端进入CLOSE_WAIT状态
    3. 服务端发送一个FIN,用来关闭服务端到客户端的数据传输,服务端进入LAST_ACK状态
    4. 客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务端,确认序号为收到序号+1,
      服务端进入CLOSED状态,完成四次挥手

ArrayList和LinkedList的区别:

ArrayList采用数组的方式来实现List接口,数组的特性是可以使用索引的方式来快速定位对象的位置,因此对于快速随机取得对象的需求使用ArrayList的效率比较高
LinkedList采用链表的方式来实现List接口的,它本身有自己特定的方法,对于插入和移除的执行效率上效率明显要快的多,适合用来实现队列和堆栈。

HashMap原理,为什么线程不安全,底层实现

在JDK1.6和1.7中 HashMap采用的是位桶(数组)+链表实现,也就是使用链表来解决冲突,同一个Hash值的链表存储在一个链表里,但是当位于一个桶中的元素过多的时候,即Hash值相等的元素过多的时候,通过key值依次查找的效率较低,查询时间是O(n),在JDK1.8中经过改善,使用位桶+链表+红黑树实现,当链表长度较短的时候,依然使用链表存储,当链表长度超过阈值时(8),将链表转化成红黑树,这样可以大大降低查询时间,查询时间(O(log n))。HashMap底层实现方法不是同步的,HashMap在并发执行put的时候会引起死循环(两个put的key发生碰撞,Hash值相同),那么根据HashMap的实现,这两个key会添加到数组的相同位置,这样最终就会发生其中一个线程put的值被覆盖,导致CPU利用率达到100%,因此多线程会导致HashMap的Node链表形成环形数据结构,一旦形成环形数据结构,Node的next节点永远不会为空,就会在获取Node时产生死循环(发生多个线程同时对于Node数组进行扩容的时候,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也会丢失)

HashMap和HashTable,ConcurrentHashMap和synchronized Map的原理和区别

HashMap不是线程安全的,HashTable是线程安全的,但是效率低,因为HashTable使用的是synchronized,所有线程竞争同一把锁,而ConcurrentHashMap
不仅线程安全并且效率高,因为他包含 一个segment数组,将数据分段存储,给每一段分配一把锁,这就是所谓的锁分段技术
JDK1.8在JDK1.7的基础上针对一个链上数据过多(即拉链过长的情况)导致性能下降,增加了红黑树来进行优化。即当链表超过8时,
链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能,其中会用到红黑树的插入、删除、查找等算法

Java虚拟机:

Java的JVM内存可分为3个区:堆,栈,方法区。
堆区:1. 存储的全是对象本身,每个对象都包含一个与之对应的class的信息
2. JVM只有一个堆区被所有线程所共享,堆中不存放基本数据类型和对象引用,指存放对象本身
栈区:1. 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用,对象本身都存放在堆区
2. 每一个栈中的数据都是私有的,其他栈不能访问。
3. 栈分为三部分:基础类型变量区,执行环境上下文,操作指令区。
方法区:1. 又叫静态区,跟堆一样,被所有线程锁共享,方法区包含所有class和static
2. 方法区中包含的都是在整个程序中永远唯一的元素,如class和static线程共享的是:堆和方法区

非线程共享的:栈,本地方法区,程序计数器
Java对象所占用的内存主要是从堆中进行分配的,堆是线程共享的,因此在堆上分配内存时需要加锁,这导致了创建对象的开销比较大,
当对空间不足的时候,就会触发GC,如果GC后空间仍然不足,则就会出现OOM。

内存回收垃圾处理机制—GC

Java提供一中垃圾回收机制,在后台创建一个守护进程,该进程会在堆内存不足的情况下自动跳出来,把堆空间的垃圾全部进行回收,从而保证程序的正常运行。

垃圾: 不在存活的对象
判断方法:引用计数器 ----引用数为0
可达性分析 ----不可达的

回收: 标记清理,标记整理,复制,分代垃圾回收

内存泄露: 指的是一个不再被程序所使用的对象或变量一直被占据在内存中
内存溢出: 指的是要求分配的内存超出了系统所能给你的,比如数组下标越界

HTTP 请求的 GET 与 POST 方式的区别:

GET方法会把名值对追加在请求的URL后面。因为URL对字符数目有限制,进而限制了用在客户端请求的参数值的数目。并且请求中的
参数值是可见的,因此,敏感信息不能用这种方式传递。
POST方法通过把请求参数值放在请求体中来克服GET方法的限制,因此,可以发送的参数的数目是没有限制的。最后,通过POST请求传递的敏感信息对外部客户端是不可见的。

cookie和 session的区别:会话技术

1.cookie数据存放在客户的浏览器,session数据放在服务器上。
2.cookie不是很安全,别人可以分析存放本地的cookie并行cookie欺骗考虑到安全应当使用session。
3.session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能,应当使用cookie。
4.单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5.个人建议:将登陆信息存放为session 其他信息如果需要保留,可以放在cookie中

Java既然有GC线程,为什么还存在内存泄露

无论哪种语言的内存分配方式,都需要返回分配内存的真实地址,Java中通过new关键字或者反射创建对象,存放在堆中,所有的对象回收,
都是由Java虚拟机通过垃圾回收机制完成的,GC会检测长时间没有使用的对象进行回收,但是像一些静态字段,静态引用类,数据库的链接,
网络连接等,若没有正确处理,还是会造成内存泄露。

内存泄露的根本原因:内存对象已经明明不需要了,但是还仍然保留着这块内存和它的访问方式。

避免内存泄露:
1. 明确引用变量的生命周期,是方法内部的局部变量,还是类实例变量,与类实例变量相同的要声明为实例变量,
与C/C++内存管理思维:声明对象引用之前,明确内存对象的有效作用域。
在一个函数内有效的内存对象,应该声明为local变量,与类实例生命周期相同的要声明为实例变量,并依次类推
在内存对象不需要的时候,记得手动置为空。

什么是微服务?

微服务是一种架构模式,它提倡将单一应用程序划分为一组小的服务,每个服务独立运行在自己的进程中,服务之间相互协调,配合,为用户
最终价值。
一个服务做一件事情,从技术角度来看就是一种小而独立的处理过程,类似于进程概念吧,能够单独启动和销毁,拥有自己独立的数据库

SpringCloud和Dubbo本质区别是通信机制不一样,Dubbo基于RPC远程过程调用,SpringCloud是基于HTTP的RestFul API调用。

优点:每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或者业务需求
开发简单,开发效率提高,一个服务就专一的干一件事,可以被小团队单独开发
微服务是松耦合的,是有功能意义的服务,无论在开发阶段还是部署阶段都是独立的
可以使用不同的语言开发
可以通过灵活且容易的方式自动部署,使用集成工具
每个微服务都有自己的存储功能,可以有自己的数据库,也可以有统一的数据库
缺点:开发人员处理分布式系统的复杂性
多服务运维难度大,系统部署依赖,服务间的通信成本,数据一致性,系统集成测试,性能监控。。。

ACID: 指的是 A原子性(Atomicity),C一致性(Consistency),I独立性(Isolation),D持久性(Durability)。

CAP理论:C强一致性,A可用性,P分区容错性
Zookeeper,保证的是CP也就是一致性和分区容错性,当向注册中心查询服务列表时,我们可以容忍注册中心查询服务列表的时候返回的是几分钟
以前的注册信息,但不能接受服务直接down掉不能用
服务注册功能对于可用性的要求要大于一致性,

在ZK 中会出现这种情况,当master节点因为故障,与其他节点失去连接,剩下节点会重新选举leader,问题在于选举leader的时间过长30-120S,且选举期间整个ZK集群是不可用的,这就导致在选举期间注册服务瘫痪,在云部署环境下,zk集群失去master节点是较大的概率发生的事

在Eureka保证AP,设计时就优先保证可用性,Eureka各个节点都是平等的,几个节点挂掉不会影响正常工作,剩余的节点依旧可以提供注册和
查询服务,而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性)只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,eureka还有一种自我保护机制,如果在15反正内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
1.Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
2.Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
3.当网络稳定时,当前实例新的注册信息会被同步到其它节点中

因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

Java反射:

  1. 理解Class类:对于每个类,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了某个特定类信息Class对象只能由系统创建一个类在JVM中只能有一个Class实例每个类的实例都会记得自己是由那个Class实例所生成的

  2. Class是一个类,封装了当前对象所对应的类的信息,一个类中有属性,方法,构造器等,Class是用来描述类的类
    对于每个类,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了某个特定类的相关信息Class对象只能由系统创建,并且一个类在JVM中只能有一个Class实例

  3. 如果传过来的只是一个全类名,通过反射可以得到这个类里面的信息

  4. 获取Class对象的三种形式
    1. 通过类名获取----例如Person.class
    2. 通过对象获取----例如 person.getClass()
    3. 通过全类名获取—例如Class.forName(“全类名”)

  5. 方法
    forName() 返回指定类名name的Class对象
    newInstance() 调用缺省构造函数,返回该Class对象的一个实例
    newInstance(Object[] args)
    getName()
    //getSuperClass() 返回父类CLass //没有这个类,搞错了吧
    getSuperclass() 返回超类Class
    getInterfaces() 返回接口
    getClassLoader() 返回类加载器

理解CLassLoader:类加载器是用来把类装进Java虚拟机的,JVM规范定义了两种类型的类装载器:启动类装载器(bootstrap),和用户自定义装载器(User-defined class loader)。反射是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。

指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制.

反射提供的功能:
1. 在运行状态下构造任意一个类的对象
2. 在运行时获取任意一个类的成员变量和方法
3. 在运行时调用任意一个类的成员变量和方法
4. 生成动态代理

Class是一个类,一个描述类的类,封装了,Method(描述方法的),Field(描述字段的),Constructor(描述构造器的)
Method
获取
getMethods()
getDeclareMethods()
getDeclareMethod()
使用
method.invoke(obj,args)
Field
获取
getDeclareFields()
getDeclareField(“name”)
使用
field.get()
field.set(obj,“name”)
field.setAccessible(true) // 设置私有属性可访问
Constructor
获取
getConstructors()
getConstructor(String.class, int.class) // 根据参数列表获取指定构造器
调用构造器的newInstance()方法创建对象
Object obj = constructor.newInstance(args[])

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值