Java基础
- 什么是内部类?内部类的作用是什么?
内部类可以多个实例,每个实例都有自己的状态信息,并且与外部对象的信息相互独立。内部类提供你了一种更好的封装,除了该外部类,其他类都无法访问。
- 静态内部类的设计意图?
静态内部类使用场景一般是当外部类需要使用内部类,而内部类无需外部类资源,并且内部类可以单独创建的时候会考虑采用静态内部类的设计。
- 成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用。
成员内部类是最普通的内部类,它是外围类的一个成员。所以他可以无限制的访问外围类的所有成员属性和方法。但外围类想要方位内部类的成员属性或方法则需要通过内部类的实例访问。
主要有两点需要注意:
- 成员内部类中不能存在任何static的变量和方法。
- 成员内部类是依附于外围类的,只有先创建了外围类才能创建内部类。
静态内部类与成员内部类的一个最大的区别就是:非静态内部类在编译完成之后会隐含的保存着一个引用,该引用是指向创建它的外围类的,但静态内部类没有。则意味着:
- 它的创建不需要依赖外围类。
- 它不能使用任何外围类的非static成员变量和方法。
局部内部类是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。
匿名内部类
- 匿名内部类是没有访问修饰符。
- new 匿名内部类,这个类首先是要存在的。
- 当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。
- 匿名内部类没有明面上的构造方法,编译器会自动生成一个引用外部类的构造方法。
- 抽象类和接口的区别?抽象类和接口的意义?抽象类与接口的应用场景?
- 抽象类是否可以没有方法和属性。
可以。
- Java反射机制的理解。
运行时获取实例化类的对象,调用对象的方法或属性,可以作为创建对象的一种方法。三种方式使用:
- class.forName()方法
- 类名.class
- 实例.getClass()
Java深入面试题
- 哪些情况下的对象会被垃圾回收机制处理掉?
GC Root不可达的对象。什么样的对象可以被看做是GC Roots呢?
- 虚拟机栈(栈桢中的本地变量表)中的引用的对象
- 方法区中的类静态属性引用的对象
- 方法区中的常量引用的对象
- 本地方法栈中JNI(Native方法)的引用的对象
- 常见的编码方式?UTF-8编码中的中文占几个字节,int类型占几个字节?
- 静态代理和动态代理有什么区别?什么场景使用?
- 如何将一个Java对象序列化到文件中?
- 实现Seralizable接口
- 通过ObjectOutputStream的writeObject()方法写入,通过ObjectInputStream的readObject()方法来进行读取
- 谈谈对Java注解的理解?
- 注解是一种对代码本身描述的元数据,一种约定的规范。它可以应用到类,方法,属性,参数,变量等。
- 主机不会影响被注解的代码,只是向第三方系统提供关于自己的信息已进行不同的需求。
- 注解会被编译到Class文件中,而且会在运行时被处理程序提取出来用于业务逻辑。
- 为什么String对象是不可变的?
- 使StringPool的实现成为可能,节省了大量的堆空间。
- String对象的不可变性,提高了应用程序的安全性。例如DB的用户名和密码都是String类型进行传递,如果String类型可变,在网络传输的过程中对String类型进行篡改其引用的值,就会导致安全问题。
- 保证String的多线程安全性,可以在不同线程之间共享一个String实例,避免了线程之间的同步。String是隐式线程安全的。
- 由于String类型的不可变性,因此在它被创建时其散列码就会被缓存,不需要再次计算。这使得它成为HashMap中的理想的键值对象。
- Java内存模型说一下。
堆,方法区,虚拟机栈,本地方法栈,程序计数器
- Error和RuntimeException的区别?
Error和Exception都是继承自Trowable的子类,Error是在程序运行时JVM虚拟机底层出现的错误,程序本身无法解决,出现Error程序即为中止执行,且错误无法恢复。
RuntimeException虽然也是运行时出现的一类异常,但这种异常时程序本身出现的异常,编译时JVM不强制捕获这里异常,当发生时,也有JVM进行处理。
- 引用计数法和GC Root可达性分析法的区别?
引用计数法:给对象中添加一个引用计数器,每当有一个地方引用他时,计数器值就+1,;当引用失效时,计数器值就-1;任何时刻计数器为0的对象就是不可能在被使用。缺点:这种方法实现简单,但如果两个对象存在相互引用,即使两个对象都被设置为null,GC在引用计数法中仍然不会回收他们。因此Java并没有采用这种方式。
GC Root可达性分析法:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。
对象Object5 —Object7之间虽然彼此还有联系,但是它们到 GC Roots 是不可达的,因此它们会被判定为可回收对象。(Java使用GC Root来判断对象是否存活。)
在Java语言中,可作为GC Roots的对象包含以下几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。(可以理解为:引用栈帧中的本地变量表的所有对象),即正常创建的对象。
- 方法区中静态属性引用的对象(可以理解为:引用方法区该静态属性的所有对象),即定义的全局静态对象。
- 方法区中常量引用的对象(可以理解为:引用方法区中常量的所有对象),即定义的final static对象。
- 本地方法栈中(Native方法)引用的对象(可以理解为:引用Native方法的所有对象)
该部分参考自:https://blog.csdn.net/luzhensmart/article/details/81431212
- 双亲委派机制说一下?
首先明确一下类加载器,简单说,类加载器就是根据指定的全限定名称将class文件加载到JVM中,转换为class对象。站在JVM的角度来看包含两种类加载器。
启动类加载器(
Bootstrap ClassLoader
):由C++
语言实现(针对HotSpot
),负责将存放在<JAVA_HOME>\lib
目录或-Xbootclasspath
参数指定的路径中的类库加载到内存中。其他类加载器:由
Java
语言实现,继承自抽象类ClassLoader
。如:
- 扩展类加载器(
Extension ClassLoader
):负责加载<JAVA_HOME>\lib\ext
目录或java.ext.dirs
系统变量指定的路径中的所有类库。- 应用程序类加载器(
Application ClassLoader
)。负责加载用户类路径(classpath
)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。
双亲委派的过程如下:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的范围内找不到指定的类时(即ClassNotFoundException),子加载器才会自己去尝试加载。
为什么需要双亲委派机制?
假设没有双亲委派模型,试想一个场景:
黑客自定义一个
java.lang.String
类,该String
类具有系统的String
类一样的功能,只是在某个函数稍作修改。比如equals
函数,这个函数经常使用,如果在这这个函数中,黑客加入一些“病毒代码”。并且通过自定义类加载器加入到JVM
中。此时,如果没有双亲委派模型,那么JVM
就可能误以为黑客自定义的java.lang.String
类是系统的String
类,导致“病毒代码”被执行。
而有了双亲委派模型,黑客自定义的java.lang.String
类永远都不会被加载进内存。因为首先是最顶端的类加载器加载系统的java.lang.String
类,最终自定义的类加载器无法加载java.lang.String
类。
自定义类加载器的实现,见下面的参考链接部分。
- 说说对Java泛型的理解。
泛型:参数化类型,我们都知道有形参或实参,参数化类型就是讲类型由原来具体的类型参数化,类似于方法中的变量参数,此时类型类型也定义为参数形式(类型形参)。然后在使用或调用时传入具体的类型(类型实参)
- Java的异常体系的理解?
- Throwable基类,异常分为Error和Exception两类,Error为JVM层面的错误,程序无法处理,Exception为程序方面的错误,可以进行处理。
- 异常又分为两类,可检查和不可检查异常,可检查异常java编译器可以捕获,强制使用try-catch进行捕获,不可检查异常java编译器不捕获。
- 在Exception中包含Runtime异常和非Runtime异常,Runtime异常属于不可检查异常,java编译器不强制捕获,需要有程序逻辑层面进行避免。
- 抛出异常的方法有throw和throws两种,捕获异常有try-catch-finally处理方式。
数据结构
- 并发集合了解哪些?
并发编程使用的类:AtomicInteger,AtomicBoolean,AtomicLong,AtomicReference。
并发编程使用的集合:ConcurrentHashMap,BlockingQueue,LinkedBlockingQueue,ArrayBlockingQueue,CopyOnWriteArrayList
- 堆和树的区别是什么?
堆是一种特殊的树结构。它分为最大堆和最小堆,具有自己独有的特点。
树是一个无环无向连通图,它有好多种,例如二叉树,二叉搜索树,平衡二叉树,红黑树,多叉树,B树,B+树等等。
- HashMap源码理解?
- ConcurrentHashMap源码理解?
- HashTable实现原理?
HashTable的实现结构与HashMap相同。只是在一些方面存在不同:
- Hashtable的默认容量为11,默认负载因子为0.75.(HashMap默认容量为16,默认负载因子也是0.75)
- Hashtable的容量可以为任意整数,最小值为1,而HashMap的容量始终为2的n次方。
- 为避免扩容带来的性能问题,建议指定合理容量。
- 跟HashMap一样,Hashtable内部也有一个静态类叫Entry,其实是个键值对对象,保存了键和值的引用。
- HashMap和Hashtable存储的是键值对对象,而不是单独的键或值。
算法相关
- 排序算法比较
- 大顶堆,小顶堆;堆的建堆过程,调整过程。
多线程编程
- 什么导致线程阻塞?
sleep(), wait(), join(), yield()
- 线程如何关闭?
- 两个线程同时要求读或者写,能不能实现?如何防止线程的同步?
- Synchronized的实现原理?
- 谈谈对Synchronized关键字,类锁,方法锁和重入锁的理解。
方法锁:Synchronized修饰方法时。这种情况下,每个类的实例对象对应一把锁。每个synchronized方法都必须获得调用该方法的类实例的锁才能执行。保证了同一时刻对于每个类实例,其所有声明的synchronized成员函数中至多只有一个处于可执行的状态。
对象锁:也是synchronized修饰方法或者静态代码块时。方法锁也是对象锁,每个java对象都会一个互斥锁,这个锁由jvm负责获取和释放。线程进入synchronized方法的时候获取该对象的对象锁,如果已经有线程获取了这个对象的锁,则当前线程进行等待。
类锁:static synchronized 修饰方法| synchronized (XXX.class)。类锁只是一个概念上的,并不是真实存在。Java中有很多对象,但只有一个Class对象,一个类的所有实例之间都共享该Class对象。所谓类锁即是Class对象上的锁。
- static synchronized方法的多线程访问和作用。
即上述的类锁概念。
- 谈谈对NIO的理解。
- ReentrantLock的内部实现。
- 对象锁和类锁是否会相互影响?
- 多线程断点续传原理?断点续传的实现?
CyclicBarrier和CountDownLatch
- 线程池的工作原理?
- 线程安全和非线程安全的集合说一下?底层如何实现HashMap和ConcurrentHashMap?
- 线程安全的集合:Vector,StringBuffer,HashTable
- 非线程安全的集合:ArrayList, LinkedList, HashMap, HashSet, TreeMap, TreeSet, StringBuilder
- Synchronized和Lock的区别,可重入锁和非可重入锁的区别?
- 乐观锁和悲观锁的概念?
- Volatile关键字的作用?
- AtomicInteger的底层实现原理。
CAS机制
- CAS机制会出现哪些问题?
CAS的缺点:
- CPU开销大。在并发量高的情况下,如果许多线程反复尝试更新某个变量,却一直更新不成功,会大幅降低程序性能。
- 不能保证代码块的原子性。CAS针对的是某个变量值的原子性操作,无法保证代码块的原子性。
- ABA问题。如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说它的值没有被其他线程改变过了吗?
如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。
该部分内容参考:https://blog.csdn.net/v123411739/article/details/79561458
- 使用过的并发包的哪些类?
- 分布式事务有了解吗?
- ArrayBlockingQueue的实现。
- 如何控制某个方法允许并发访问线程的个数?
- static Semaphore sSemaphore = new Semaphore(6) 表示该方法最多允许几个线程访问
- sSemaphore.acquire():调用一次,允许进入方法的线程数量减一
- sSemaphore.release():调用一次,允许进入方法的线程数量加1
- 当允许进入方法的线程数量减为0的时候其他线程就等待,直到允许的线程数量大于0
- sSemaphore.availablePermits():可以获取当前允许进入方法的线程数量
网络编程
- TCP(传输控制协议Transmission Control Protocol)和UDP(用户数据报协议User Datagram Protocol)的原理和区别。
- TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的。UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)。
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
- TCP首部开销20字节;UDP的首部开销小,只有8个字节。
常见的TCP协议应用:TELNET, SSH, HTTP, FTP,电子邮件。常见的UDP的应用:DNS, TFTP, RIP, DHCP,流媒体通信。
- HTTP协议。
- TCP和UDP的区别?
- TCP的三次握手?四次挥手?为什么两次握手不行?time_wait状态存在的作用?
- NIO说一下你的理解。
大数据组件相关
- Hadoop MapReduce流程是什么?
MapReduce的八大步骤:
Map阶段:
第一步: 通过FileInputFormat读取文件, 解析文件成为key, value对, 输出到第二步.
第二步: 自定义Map逻辑, 处理key1, value1, 将其转换为key2, value2, 输出到第三步.
Shuffle阶段:
第三步: 对key2, value2进行分区.
第四步: 对不同分区内的数据按照相同的key进行排序.
第五步: 分组后的数据进行规约(combine操作),降低数据的网络拷贝(可选步骤)
第六步: 对排序后的数据, 将相同的key的value数据放入一个集合中, 作为value2.
Reduce阶段:
第七步: 对多个map的任务进行合并, 排序. 自定义reduce逻辑, 处理key2, value2, 将其转换为key3, value3, 进行输出.
第八步: 通过FileOutputFormat输出处理后的数据, 保存到文件.
该部分内容参考自:https://blog.csdn.net/weixin_42582592/article/details/83080900
- Kafka复制机制、分区多副本机制。
Kafka中每个topic可以配置多个分区,当存在多个broker的Kafka集群时,每个broker中会以分区的形式存在每个分区的数据副本。对kafka的操作,只针对于主broker进行,副本会同步到其他各个broker中。
- HDFS读写流程,数据Checkpoint流程。
- HQL怎么转化为MR任务的?
Hive是通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的Driver,结合元数据(MetaStore),将这些指令翻译成MapReduce,提交到Hadoop中执行,最后,将执行返回的结果输出到用户交互接口。
1)用户接口:Client。CLI(hiveshell)、JDBC/ODBC(java访问hive)、WEBUI(浏览器访问hive)
2)元数据:Metastore。元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore
3)Hadoop。使用HDFS进行存储,使用MapReduce进行计算。
4)驱动器:Driver
- 解析器(SQL Parser):将SQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。
- 编译器(Physical Plan):将AST编译生成逻辑执行计划。
- 优化器(Query Optimizer):对逻辑执行计划进行优化。
- 执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于Hive来说,就是MR/Spark。
以上内容参考自:https://blog.csdn.net/qq_26442553/article/details/79616207
- YARN的理解?工作流程、组成架构。
- Zookeeper选举机制,节点类型,zookeeper实现原理。
Zookeeper四种节点类型:
- PERSISTENT:持久化节点
- PERSISTENT_SEQUENTIAL:顺序编号的持久化节点,这种节点会根据当前已存在的节点数自动+1
- EPHEMERAL:临时节点,客户端session超时这类节点就会被自动删除
- EPHEMERAL_SEQUENTIAL:临时自动编号节点
- Kafka如何保证高吞吐量的,Kafka的零拷贝具体怎么做的?
- HDFS的容错机制。
- Zookeeper如何保证原子性,怎么实现分布式锁?
Zookeeper实现分布式锁:Curator
- Kafka的存储模型和网络模型。
- Hadoop集群中需要启动哪些进程?它们分别的作用是什么?
- Hive中内部表和外部表的区别是什么?
内部表就是一般意义上的表,Hive中的内部表将数据以文件的形式存储在HDFS中,其元数据存储在Derby或者MySQL中。而外部表维护的是一个连接,它指向HDFS中已经存在的数据。
当删除内部表时,其HDFS中的表数据和元数据都会删除。而删除外部表时,则只会删除维护的那个连接,实际的表数据和表的元数据都不会被删除。
- Redis性能优化,单机增加CPU核心数是否会提高性能?
- Kafka重启是否会导致数据的丢失?
不会,Kafka中的数据是在磁盘中进行持久化的,可以设置一个超时时间,默认为7天。持久化的数据在7天之后会自动被删除。否在重启Kafka是不会删除数据的。
- Hive的数据倾斜原因,如何解决?
- RabbitMQ消息队列丢失消息,重复消费的问题?
SQL和数据相关
- 数据库隔离级别说一下
数据库并发条件下可能出现的问题:
- 脏读:一个事务读取了另一个事务未提交执行的数据。
- 不可重复读:一个事务多次读取的数据前后不一致。
- 幻读:一个事务修改了数据,另一个事务也修改的数据,第一个事务在进行数据读取时,就会发现数据和他之前修改的不一致。
数据库的隔离级别:
- 读未提交,就是可以读到未提交的内容。这种隔离级别下,查询时不会加锁的,可能出现脏读,不可重复读,幻读的问题。
- 读提交,就是只能读到已提交的内容。这是最常用的隔离级别,是SQL Server和Oracle默认的隔离级别。可以有效避免脏读,但除非显示加锁,普通的查询还是不会加锁。(快照读)不能避免不可重复读和幻读。
- 可重复读,针对不可重复读指定的隔离级别,能够避免不可重复读。是MySQL默认的隔离级别。在一个事务启动时,就不再允许进行修改操作。无法避免幻读,因为幻读是由于插入和删除操作产生的。
- 串行化,数据库的最高隔离级别,在这种级别下,事务串行化顺序执行。脏读,不可重复读和幻读都可以避免,但执行效率太低,基本不使用。
- 数据库三范式。
- 第一范式:属性不可分。
- 第二范式:非主属性完全依赖于主属性。
- 第三范式:非主属性之间没有传递依赖。
- 数据库的左连接,右连接,内连接和全连接?
- 左连接:左边表中的数据都显示,右边表中的数据显示共有的那部分,没有对应的部分补空。
- 右连接:与左连接相反。
- 内连接:两张表中都有的数据才能显示出来。
- 全连接:其实就是笛卡尔积,显示左右两个表的所有数据,但去除两个表中的重复数据。
该部分参考自:https://blog.csdn.net/u014204541/article/details/79739980
- MySQL数据库的索引有几种?
- 普通索引
- 唯一索引
- 主键索引
- 全文索引
- 组合索引
- 数据库引擎认识几种?Innodb和myisam的区别?
ISAM,MyISAM,HEAP,InnoDB
MyISAM与InnoDB的区别。InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
设计模式
- 常用的设计模式熟悉哪些?
- 单例模式
- 工厂模式
- 适配器模式
- 观察者模式
- 装饰器模式
- 代理模式
- 外观模式
- 设计模式的6个设计原则?
- 单一职责原则
- 开闭原则
- 里氏替换原则
- 接口隔离原则
- 合成复用原则
- 依赖倒转原则
- 迪米特法则
非技术问题
参考资料
https://blog.csdn.net/blessed24/article/details/78077134?utm_source=blogxgwz8