Java面向对象的特征
面向对象的三个基本特征是:封装(隔离,重用)、继承(减少重复)、多态(继承重写)。
请你说说“面向对象六大原则”?
单一职责原则(Single-Resposibility Principle)。
开放封闭原则(Open-Closed principle)。
Liskov替换原则(Liskov-Substituion Principle)。
依赖倒置原则(Dependecy-Inversion Principle)。
接口隔离原则(Interface-Segregation Principle)。
良性依赖原则。
https://blog.csdn.net/cancan8538/article/details/8057095
https://www.jianshu.com/p/f2c2250cc33b
谈谈final、finally、finalize的区别
1.final类
final类不能被继承 ,没有子类 ,final类中的方法默认是final的 / 方法不能被子类的方法覆盖,但可以被继承 /
成员变量表示常量,只能被赋值一次,赋值后值不再改变 / 不能用于修饰构造方法
2.final方法
如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。 使用final方法的原因有二:
- 把方法锁定,防止任何继承类修改它的意义和实现。
- 高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。
3. final变量(常量)
- 用final修饰的成员变量表示常量,值一旦给定就无法改变!
- final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。
- 从下面的例子中可以看出,一旦给final变量初值后,值就不能再改变了。
4.final参数
当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。
5.finally
finally是关键字,在异常处理中,try子句中执行需要运行的内容,catch子句用于捕获异常,finally子句表示不管是否发生异常,都会执行。finally可有可无。但是try…catch必须成对出现。
6.finalize()
finalize() 方法名,Object类的方法,Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象进行调用。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的子类覆盖 finalize() 方法以整理系统资源或者执行其他清理操作。
java 内部类和静态内部类的区别
定义在一个类内部的类叫内部类,包含内部类的类称为外部类 , 外部类按常规的类访问方式使用内部 类,唯一的差别是外部类可以访问内部类的所有方法与属性, 包括私有方法与属性。
- 1.静态内部类可以有静态成员(方法,属性),而非静态内部类则不能有静态成员(方法,属性)。
- 2.静态内部类只能够访问外部类的静态成员,而非静态内部类则可以访问外部类的所有成员(方法,属性)。
- 3.实例化一个非静态的内部类的方法:
- a.先生成一个外部类对象实例 OutClassTest oc1 = new OutClassTest();
- b.通过外部类的对象实例生成内部类对象 OutClassTest.InnerClass nostaticinner = oc1.new InnerClass();
- 4.实例化一个静态内部类的方法:
- a.不依赖于外部类的实例,直接实例化内部类对象 OutClassTest.InnerStaticClass inner = new OutClassTest.InnerStaticClass();
- b.调用内部静态类的方法或静态变量,通过类名直接调用 OutClassTest.InnerStaticClass.static_value OutClassTest.InnerStaticClass.getMessage()
Java 中的 ==, equals 与 hashCode 的区别与联系
概念:
- == : 该操作符生成的是一个boolean结果,它计算的是操作数的值之间的关系
- equals : Object 的 实例方法,比较两个对象的content是否相同
- hashCode : Object 的 native方法 , 获取对象的哈希值,用于确定该对象在哈希表中的索引位置,它实际上是一个int型整数
java中重载与重写的区别
重载:方法名相同,参数不同,返回值也可以不同
重写:父类与子类之间的多态性,对父类函数进行重定义
int与Integer的区别
int:基本数据类型 ,值引用,默认值为0
integer:包装类,地址引用,默认值null
Java线程基础
进程:.exe,运行的应用程序
线程:进程中执行的一个流程
实现线程的方法:继承Thread类,实现runable接口,实现Callable接口
线程状态
public static final State RUNNABLE;
public static final State NEW;
public static final State BLOCKED;
public static final State WAITING;
public static final State TIMED_WAITING;
public static final State TERMINATED;
Java 对象的初始化过程
初始化过程:
- 1、 new 用到了Person.class,所以会先找到Person.class文件,并加载到内存中(用到类中的内容类就会被加载)
- 2、执行该对象的static代码块(静态初始块)。(如果有的话,给Person.class类进行初始化)
- 3、在堆内存中开辟空间,分配内存地址
- 4、在堆内存中建立对象特有属性,并进行默认初始化
- 5、对属性进行显示初始化(声明成员属性并赋值)
- 6、执行普通初始块
- 7、执行构造函数
- 8、将内存地址赋值给栈内存中的jack变量
执行顺序:父类静态成员和static块—>子类静态成员和static块—>父类普通成员和非static块—>父类构造函数—>
子类普通成员和非static块—>子类构造函数
java线程池详解
在Java用有一个Executors工具类,可以为我们创建一个线程池,其本质就是new了一个ThreadPoolExecutor对象。
Java中锁的分类
- 公平锁/非公平锁
- 公平锁是指多个线程按照申请锁的顺序来获取锁
- 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序
- 可重入锁
- 可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁
- 独享锁/共享锁
- 独享锁是指该锁一次只能被一个线程所持有。
- 共享锁是指该锁可被多个线程所持有。
- ReadWriteLock,其读锁是共享锁,其写锁是独享锁。
- 互斥锁/读写锁
- 互斥锁在Java中的具体实现就是ReentrantLock
- 读写锁在Java中的具体实现就是ReadWriteLock
- 乐观锁/悲观锁
- 分段锁
- 偏向锁/轻量级锁/重量级锁
- 自旋锁
- 自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
Java中CAS详解
锁机制存在以下问题:
- (1)在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
- (2)一个线程持有锁会导致其它所有需要此锁的线程挂起。
- (3)如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。
compare and swap:aba问题使用version。循环时间长开销大。 只能保证一个共享变量的原子操作 ,多个变量需要用锁,或者把两个变量合并成一个共享变量, AtomicReference <变量>
BlockingQueue解读
首先,最基本的来说, BlockingQueue 是一个先进先出的队列(Queue),为什么说是阻塞(Blocking)的呢?是因为 BlockingQueue支持当获取队列元素但是队列为空时,会阻塞等待队列中有元素再返回;也支持添加元素时,如果队列已满,那么等到队列可以放入新元素时再放入。
CopyOnWriteArrayList实现原理及源码分析
是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器" 。
写入得时候将引用指向新副本,原内容将会被拷贝一分用于读操作读取,试用于读多写少的并发场景,缺点占用内存每次都要拷贝一份,频繁gc,无法保证实时性
Synchronized原理和优化
Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。
一些优化:
- 适应性自旋(Adaptive Spinning)
- 锁粗化(Lock Coarsening) 锁粗化的概念应该比较好理解,就是将多次连接在一起的加锁、解锁操作合并为一次,将多个连续的锁扩展成一个范围更大的锁。 每次调用stringBuffer.append方法都需要加锁和解锁,如果虚拟机检测到有一系列连串的对同一个对象加锁和解锁操作,就会将其合并成一次范围更大的加锁和解锁操作,即在第一次append方法时进行加锁,最后一次append方法结束后进行解锁。
- 锁消除(Lock Elimination)
类的加载机制
1.加载: 内存中生成一个代表这个类的java.lang.Class对象
2.验证: 文件格式验证、元数据验证、字节码验证和符号引用验证。
3.准备: 正式为类变量分配内存并设置类变量的初始值阶段
4.解析: 虚拟机将常量池中的符号引用替换为直接引用的过程
5.初始化:
6.类加载器:
虚拟机设计团队把加载动作放到JVM外部实现,以便让应用程序决定如何获取所需的类,JVM提供了3种类加载器:
- 启动类加载器(Bootstrap ClassLoader):负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。
- 扩展类加载器(Extension ClassLoader):负责加载 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。
- 应用程序类加载器(Application ClassLoader):负责加载用户路径(classpath)上的类库。
JVM 怎么确定对象已经死了?
1.引用计数算法:引用+1 失效-1
2.可达性分析算法 : 通过一系列“GC roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链(refenecre chain) ,当一个对象到GcRoot 没有任何的引用链,则证明此对象不可用。
面试被问烂的 Spring IOC
控制反转
- 两种实现:依赖查找(DL)和依赖注入(DI)。
Spring AOP是什么?你都拿它做什么?
向切面编程(AOP) : 当我们需要为多个不具有继承关系的对象引入一个公共行为,例如日志、权限验证、事务等功能时
1.静态代理:
package test.staticProxy;
// 接口
public interface IUserDao {
void save();
void find();
}
//目标对象
class UserDao implements IUserDao{
@Override
public void save() {
System.out.println("模拟:保存用户!");
}
@Override
public void find() {
System.out.println("模拟:查询用户");
}
}
/**
* 静态代理
* 特点:
* 2. 目标对象必须要实现接口
* 2. 代理对象,要实现与目标对象一样的接口
*/
class UserDaoProxy implements IUserDao{
// 代理对象,需要维护一个目标对象
private IUserDao target = new UserDao();
@Override
public void save() {
System.out.println("代理操作:开启事务...");
target.save(); // 执行目标对象的方法
System.out.println("代理操作:提交事务...");
}
@Override
public void find() {
target.find();
}
}
2.动态代理
动态代理类的源码是在程序运行期间,通过 JVM 反射等机制动态生成。代理类和委托类的关系是运行时才确定的
package test.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 接口
public interface IUserDao {
void save();
void find();
}
//目标对象
class UserDao implements IUserDao{
@Override
public void save() {
System.out.println("模拟:保存用户!");
}
@Override
public void find() {
System.out.println("查询");
}
}
/**
* 动态代理:
* 代理工厂,给多个目标对象生成代理对象!
*
*/
class ProxyFactory {
// 接收一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 返回对目标对象(target)代理后的对象(proxy)
public Object getProxyInstance() {
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标对象使用的类加载器
target.getClass().getInterfaces(), // 目标对象实现的所有接口
new InvocationHandler() { // 执行代理对象方法时候触发
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 获取当前执行的方法的方法名
String methodName = method.getName();
// 方法返回值
Object result = null;
if ("find".equals(methodName)) {
// 直接调用目标对象方法
result = method.invoke(target, args);
} else {
System.out.println("开启事务...");
// 执行目标对象方法
result = method.invoke(target, args);
System.out.println("提交事务...");
}
return result;
}
}
);
return proxy;
}
}
SpringMVC工作原理详解
SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是 DispatcherServlet,它是一个 Servlet,顶层是实现的Servlet接口。
Java 必须掌握的 20+ 种 Spring 常用注解
1、声明bean的注解
@Component 组件,没有明确的角色
@Service 在业务逻辑层使用(service层)
@Repository 在数据访问层使用(dao层)
@Controller 在展现层使用,控制器的声明(C)
2、注入bean的注解
@Autowired:由Spring提供
@Inject:由JSR-330提供
@Resource:由JSR-250提供
都可以注解在set方法和属性上,推荐注解在属性上(一目了然,少写代码)。
3、java配置类相关注解
@Configuration 声明当前类为配置类,相当于xml形式的Spring配置(类上)
@Bean 注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式(方法上)
@Configuration 声明当前类为配置类,其中内部组合了@Component注解,表明这个类是一个bean(类上)
@ComponentScan 用于对Component进行扫描,相当于xml中的(类上)
@WishlyConfiguration 为@Configuration与@ComponentScan的组合注解,可以替代这两个注解
4、切面(AOP)相关注解
Spring支持AspectJ的注解式切面编程。
@Aspect 声明一个切面(类上)
使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。
@After 在方法执行之后执行(方法上)
@Before 在方法执行之前执行(方法上)
@Around 在方法执行之前与之后执行(方法上)
@PointCut 声明切点
在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上)
5、@Bean的属性支持
@Scope 设置Spring容器如何新建Bean实例(方法上,得有@Bean)
其设置类型包括:
Singleton (单例,一个Spring容器中只有一个bean实例,默认模式),
Protetype (每次调用新建一个bean),
Request (web项目中,给每个http request新建一个bean),
Session (web项目中,给每个http session新建一个bean),
GlobalSession(给每一个 global http session新建一个Bean实例)
@StepScope 在Spring Batch中还有涉及
@PostConstruct 由JSR-250提供,在构造函数执行完之后执行,等价于xml配置文件中bean的initMethod
@PreDestory 由JSR-250提供,在Bean销毁之前执行,等价于xml配置文件中bean的destroyMethod
6、@Value注解
@Value 为属性注入值(属性上)
支持如下方式的注入:
》注入普通字符 》注入配置文件 等等
7、环境切换
@Profile 通过设定Environment的ActiveProfiles来设定当前context需要使用的配置环境。(类或方法上)
@Conditional Spring4中可以使用此注解定义条件话的bean,通过实现Condition接口,并重写matches方法,从而决定该bean是否被实例化。(方法上)
8、异步相关
@EnableAsync 配置类中,通过此注解开启对异步任务的支持,叙事性AsyncConfigurer接口(类上)
@Async 在实际执行的bean方法使用该注解来申明其是一个异步任务(方法上或类上所有的方法都将异步,需要@EnableAsync开启异步任务)
9、定时任务相关
@EnableScheduling 在配置类上使用,开启计划任务的支持(类上)
@Scheduled 来申明这是一个任务,包括cron,fixDelay,fixRate等类型(方法上,需先开启计划任务的支持)
10、@Enable*注解说明
这些注解主要用来开启对xxx的支持。
@EnableAspectJAutoProxy 开启对AspectJ自动代理的支持
@EnableAsync 开启异步方法的支持
@EnableScheduling 开启计划任务的支持
@EnableWebMvc 开启Web MVC的配置支持
@EnableConfigurationProperties 开启对@ConfigurationProperties注解配置Bean的支持
@EnableJpaRepositories 开启对SpringData JPA Repository的支持
@EnableTransactionManagement 开启注解式事务的支持
@EnableTransactionManagement 开启注解式事务的支持
@EnableCaching 开启注解式的缓存支持
11、springmvc部分
@EnableWebMvc 在配置类中开启Web MVC的配置支持,如一些ViewResolver或者MessageConverter等,若无此句,重写WebMvcConfigurerAdapter方法(用于对SpringMVC的配置)。
@Controller 声明该类为SpringMVC中的Controller
@RequestMapping 用于映射Web请求,包括访问路径和参数(类或方法上)
@ResponseBody 支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上)
@RequestBody 允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)
@PathVariable 用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
@RestController 该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。
@ControllerAdvice 通过该注解,我们可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,
这对所有注解了 @RequestMapping的控制器内的方法有效。
@ExceptionHandler 用于全局处理控制器里的异常
@InitBinder 用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。
@ModelAttribute 本来的作用是绑定键值对到Model里,在@ControllerAdvice中是让全局的@RequestMapping都能获得在此处设置的键值对。
谈谈你对 Spring AOP 的了解?请加上这些内容,绝对加分!
众所周知,一旦提到AOP,相信大家都是条件反射的想到JDK代理和CGLib代理,没错,这两个代理都是在运行时内存中临时生成代理类,故而又称作运行时增强——动态代理。
其实,除了运行时织入切面的方式外,我们还有一种途径进行切面织入,它可以在类加载期通过字节码转换,进而将目标织入切入点(目标类),这种方式就是LTW,即静态代理(静待代理也被称作编译时增强,后面会有相关代码样例)。 java.lang.instrument
- ClassFileTransformer
spring boot面试问题集锦
https://mp.weixin.qq.com/s?__biz=MzI3MjUxNzkxMw==&mid=2247484003&idx=1&sn=1efd280c5b9044ef511ea03cc913428e&chksm=eb301c15dc4795032285317d653163020dcc7a6b0cd9fdf4952c0394b84196e1bce2d5a0d481&scene=21#wechat_redirect
https://www.javainuse.com/spring/SpringBootInterviewQuestions
Spring Boot 是如何实现自动配置的?
AutoConfigurationImportSelector -》META-INF/spring.factories
Spring Boot 与 MVC 的区别
Spring MVC的功能
1.Spring MVC提供了一种轻度耦合的方式来开发web应用。
Spring MVC是Spring的一个模块,式一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。
2.Spring Boot的功能
Spring Boot实现了自动配置,降低了项目搭建的复杂度。
众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。
Mybatis常见面试题总结及答案
https://mp.weixin.qq.com/s?__biz=MzI3MjUxNzkxMw==&mid=2247484032&idx=1&sn=140af17b61a31623546e29f85ba89421&chksm=eb301cf6dc4795e0e2c0569be6b70afebf70af2c56353c63cff2a9663600584e67c16017ea88&scene=21#wechat_redirect
Mybatis架构与原理
-
SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
-
Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
-
StatementHandler 封装了JDBC Statement操作,负责对JDBCstatement的操作,如设置参数、将Statement结果集转换成List集合。
-
ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所需要的参数
-
ResultSetHandler *负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
-
TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
-
MappedStatement MappedStatement维护了一条
节点的封
-
SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
-
BoundSql 表示动态生成的SQL语句以及相应的参数信息
-
Configuration MyBatis所有的配置信息都维持在Configuration对象之中