【Java面试】-- 杂题
杂题
2019-11-03 21:09:37 by冲冲
1、类加载器的双亲委派机制
类加载器:把类通过类加载器加载到JVM中,然后转换成class对象(通过类的全路径来找到这个类)。
双亲委派机制:当有一个类进入虚拟机加载环节后,但是他自己的类加载器不去加载,而是让其父类加载器加载(让上级加载器加载),只有当父类加载器找不到这个类的时候,子类加载器才会去加载.
优点:为了安全,Object是所有类的父类,系统类的加载都是经过Object加载器加载。此时,如果有一个自定义的类,但是类名和系统类中的某个类的类名相同,此时由于双亲委派机制的存在,JVM可以判定,哪一个是真的系统类,哪一个是自定义的的类(也就是通过类加载器判断)。可以避免黑客伪造破坏类。
2、HashSet如何去重?
① 首先调用hashCode()方法判断hashCode是否存在,如果不存在则无重复。
② 如果hashCode存在,则调用equals()方法判断有无对象内容重复,如果没有则不重复。
3、volatile关键字是否能保证线程安全?
不能。volatile关键字用在多线程同步中,可保证读取的可见性。JVM只是保证从主内存加载到线程工作内存的值是最新的读取值,而非cache中。但多个线程对volatile的写操作,无法保证线程安全。
假如,线程1和线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值,在线程1对count进行修改之后,会write到主内存中,主内存中的count变量就会变为6。线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6。
4、Java能不能不通过构造函数创建对象?
能。Java创建对象的4种方式:
(1) 用new语句创建对象,这是最常见的创建对象的方法。
(2) 运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
(3) 调用对象的clone()方法。
(4) 运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
注意:(1)和(2)都会明确的显式的调用构造函数 ;(3)是在内存上对已有对象的影印,所以不会调用构造函数 ;(4)是从文件中还原类的对象,也不会调用构造函数。
原型模式应用clone()
clone()是浅拷贝,可以重写成深拷贝。
浅拷贝:如果目标对象A,拥有一个引用类型的变量B,对A进行clone()得到复制品a,a也拥有引用类型变量b,a和b指向同一个对象(内存地址相同)。
深拷贝:a和b分别指向内存地址不同的两个同类型对象。
(在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存)
5、结论
① 子类新增的方法是不能直接操作被子类隐藏的成员变量的。子类重写的方法可以直接操作被子类隐藏的成员变量的。
② 不允许使用static修饰abstract方法。
③ 内部类的类名只能在定义它的类或程序段中或在表达式内部匿名使用。
④ 内部类可以使用它所在类的静态成员变量和实例成员变量。
⑤ 内部类可以用abstract修饰符定义为抽象类。
⑥ 内部类可作为其他类的成员,而且可访问它所在类的成员。
⑦ abstract方法必须在abstract类中。
⑧ static方法中不能处理非static的数据。
6、MyBatis的一级缓存和二级缓存
(1)一级缓存:①默认开启。②作用范围是一个sqlSession。
(2)二级缓存:①默认不开启。②作用范围是一个mapper(namespace),包括多条sqlSession。
缓存的作用:Mybatis首先前往缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。
底层实现:Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句,value为从查询出来映射生成的java对象。
7、线程的创建方式(7种)
①继承Thread类
②实现Runable接口
③实现Callable接口和FutureTask类(该类实现的是Runable()接口)
④匿名Thread类
⑤Timer类和TimerTask类
⑥线程池Executors
⑦Stream类
(1)继承Thread类,作为线程对象存在
public class CreatThreadDemo1 extends Thread{
/**
* 构造方法: 继承父类方法的Thread(String name);方法
* @param name
*/
public CreatThreadDemo1(String name){
super(name);
} @Override
public void run() {
while (!interrupted()){
System.out.println(getName()+"线程执行了...");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
CreatThreadDemo1 d1 = new CreatThreadDemo1("first");
CreatThreadDemo1 d2 = new CreatThreadDemo1("second"); d1.start();
d2.start(); d1.interrupt(); //中断第一个线程
}
}
① interrupted()方法,用于判断该线程是否被中断。
② interrupt()方法,本意是中断线程,但是用于终止线程。终止线程已经不允许用stop方法,该方法不会释放占用的资源。
③ Thread.sleep(200); //线程休息2ms。静态方法,线程不释放占用的资源(对象锁),线程进入sleep类型的阻塞状态。
④ Object.wait(); //让线程进入等待,直到调用Object的notify()或者notifyAll()时,线程停止休眠。调用者是对象不是线程,该方法使线程释放锁,进入同步队列,当被notify()或notifyAll()才被唤醒进入等待地列。
⑤ Thread.yield(); //线程放弃CPU时间片,进入Runable状态(sleep和wait才会阻塞),将cpu时间片让给其他优先级相等或者更高的线程。但是OS的调度机制也有可能继续把时间片交给该线程(备受青睐没办法)。yield只是暂停执行,不会释放对象锁(同sleep)。
(2)实现Runable()接口,作为线程任务存在
public class CreatThreadDemo2 implements Runnable {
@Override
public void run() {
while (true){
System.out.println("线程执行了...");
}
} public static void main(String[] args) {
//将线程任务传给线程对象
Thread thread = new Thread(new CreatThreadDemo2());
//启动线程
thread.start();
}
}
(3)匿名内部类创建线程对象
public class CreatThreadDemo3 extends Thread{
public static void main(String[] args) {
//创建无参线程对象
new Thread(){
@Override
public void run() {
System.out.println("线程执行了...");
}
}.start();
//创建带线程任务的线程对象
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行了...");
}
}).start();
//创建带线程任务并且重写run方法的线程对象
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runnable run 线程执行了...");
}
}){
@Override
public void run() {
System.out.println("override run 线程执行了...");
}
}.start();
} }
因为Thread类本身也实现Runable()接口,那么到底运行刚实现的Runable()接口的run方法,还是运行Thread类本身的run()方法?
应该是Thread类的run()方法,因为该段代码相当于Thread类实现两个Runable()接口,从上往下依次执行,最终Thread类的run()方法覆盖掉前面实现的Runable()的run()方法。
(4)实现Callable()接口,创建带返回值的线程
public class CreatThreadDemo4 implements Callable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CreatThreadDemo4 demo4 = new CreatThreadDemo4(); FutureTask<Integer> task = new FutureTask<Integer>(demo4); //FutureTask最终实现的是runnable接口 Thread thread = new Thread(task); thread.start(); System.out.println("我可以在这里做点别的业务逻辑...因为FutureTask是提前完成任务");
//拿出线程执行的返回值
Integer result = task.get();
System.out.println("线程中运算的结果为:"+result);
} //重写Callable接口的call方法
@Override
public Object call() throws Exception {
int result = 1;
System.out.println("业务逻辑计算中...");
Thread.sleep(3000);
return result;
}
}
Callable()接口源码
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
返回指定泛型的call方法。然后调用FutureTask对象的get方法可以得到call方法的返回值。
(5)定时器Timer
public class CreatThreadDemo5 { public static void main(String[] args) {
Timer timer = new Timer(); timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("定时器线程执行了...");
}
},0,1000); //延迟0,周期1s }
}
(6)线程池创建线程
public class CreatThreadDemo6 {
public static void main(String[] args) {
//创建一个具有10个线程的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
long threadpoolUseTime = System.currentTimeMillis();
for (int i = 0;i<10;i++){
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程执行了...");
}
});
}
long threadpoolUseTime1 = System.currentTimeMillis();
System.out.println("多线程用时"+(threadpoolUseTime1-threadpoolUseTime));
//销毁线程池
threadPool.shutdown();
threadpoolUseTime = System.currentTimeMillis();
} }
shutdown()方法,要求所有线程都运行完之后再销毁。
shutdownnow()方法,要求所有线程立即停止(即便任务还没做完也要停止)然后销毁。
(7)利用java8新特性Stream实现并发
public class CreatThreadDemo7 {
public static void main(String[] args) {
List<Integer> values = Arrays.asList(10,20,30,40);
//parallel 平行的,并行的
int result = values.parallelStream().mapToInt(p -> p*2).sum();
System.out.println(result);
//怎么证明它是并发处理呢?因为输出结果是无序的,比如200,30,10,40,20
values.parallelStream().forEach(p-> System.out.println(p));
}
}
【Java面试】-- 杂题的更多相关文章
- Java面试题精选(三) JSP/Servlet Java面试逻辑题
-- JSP/Servlet Java面试逻辑题 -- 很显然,Servlet/JSP的WEB前端动态制作的重要性比HTML/CSS/JS的价值高很多,但我们都知道他们都是建立在HT ...
- 分享13道上海尚学堂拿回来的Java面试真题,这些都是Java核心常见问题,想拿OFFER必看!
上海尚学堂Java培训学员参加面试带回来的真题,分享出来与大家,希望大家能认真地看看做一遍.后面有详细题解答案,对照下,看看自己做得怎么样,把这些面试遇到的真题全部掌握,做好面试笔试前的准备. 一.1 ...
- 【Java面试真题】剑指Offer53.2——0~n-1中缺失的数字(异或、二分两种解法)
[Java实现]剑指Offer53.2--0~n-1中缺失的数字:面试真题,两种思路分享 前面有另一道面试题[Java实现]剑指offer53.1--在排序数组中查找数字(LeetCode34:在排序 ...
- 秋招如何抱佛脚?2022最新大厂Java面试真题合集(附答案
2022秋招眼看着就要来了,但是离谱的是,很多同学最近才想起来还有秋招这回事,所以纷纷临时抱佛脚,问我有没有什么快速磨枪的方法, 我的回答是:有! 说起来,临阵磨枪没有比背八股文更靠谱的了,很多人对这 ...
- java面试基础题(三)
程序员面试之九阴真经 谈谈final, finally, finalize的区别: final:::修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此 ...
- java面试95题
1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注 ...
- java面试编程题
[程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? //这是一个菲波拉契数列问 ...
- Java面试经典题:线程池专题
1.什么是线程池 线程池的基本思想是一种对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完成后线程对象归池, ...
- java 面试算法题
/** * 设有n个人依围成一圈,从第1个人开始报数,数到第m个人出列,然后从 * 出列的下一个人开始报数,数到第m个人又出列,…,如此反复到所有的人全部出列为 * 止.设n个人的编号分别为1,2,… ...
- java面试基础题------》Java 中的父子类静态代码块,代码块,构造方法执行顺序
4.指出下面程序的运行结果. class A { static { System.out.print("1"); } public A() { System.out.print(& ...
随机推荐
- sql提示1055 不让你group by
是不是突然写好的sql语句 部署上去就 Expression #2 of SELECT list is not in GROUP BY clause and containsnonaggregated ...
- WPF实现Win10汉堡菜单
WPF开发者QQ群: 340500857 | 微信群 -> 进入公众号主页 加入组织 前言 有小伙伴提出需要实现Win10汉堡菜单效果. 由于在WPF中没有现成的类似UWP的汉堡菜单,所以我们 ...
- Golang通脉之数据类型
标识符与关键字 在了解数据类型之前,先了解一下go的标识符和关键字 标识符 在编程语言中标识符就是定义的具有某种意义的词,比如变量名.常量名.函数名等等. Go语言中标识符允许由字母数字和_(下划线) ...
- django-admin和django-admin.py的区别
问题 django初学者在使用django-admin创建项目时容易出现无法创建的错误,这是因为网上很多教程用的都是django-admin.py创建的项目,不出意外的话,你输入相同的命令会发现项目没 ...
- 你一定不知道的Unsafe用法
Unsafe是什么 首先我们说Unsafe类位于rt.jar里面sun.misc包下面,Unsafe翻译过来是不安全的,这倒不是说这个类是不安全的,而是说开发人员使用Unsafe是不安全的,也就是不推 ...
- JAVA笔记2__类/封闭性/构造方法/方法的重载/匿名对象
public class Main { public static void main(String[] args) { Chicken c1 = new Chicken(); Chicken c2 ...
- Windows内核基础知识-5-调用门(32-Bit Call Gate)
Windows内核基础知识-5-调用门(32-Bit Call Gate) 调用门有一个关键的作用,就是用来提权.调用门其实就是一个段. 调用门: 这是段描述符的结构体,里面的s字段用来标记是代码段还 ...
- 攻防世界Web之fakebook
打开题目,得到一个网页,包含一个表格.两个按钮. 习惯性先查看网页源码,但没发现有效信息. <!doctype html> <html lang="ko"> ...
- 【Go语言学习笔记】Go的defer
关键字 defer ⽤于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行. 注意,defer语句只能出现在函数或方法的内部. defer语句经常被用于处理成对的操作,如打开.关闭.连接.断开连接 ...
- 不破不立,祝贺EDG夺得S11冠军。这一夜,我看到太多Flag成真
在昨晚11月6号夜进行的2021英雄联盟S11总决赛中,中国战队EDG夺冠!全国各地高校的男生宿舍像过年一般庆祝夺冠,高呼:EDG世界冠军! 前三局1:2的劣势下,第四局十分胶着,最终EDG顽 ...