杂题


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面试】-- 杂题的更多相关文章

  1. Java面试题精选(三) JSP/Servlet Java面试逻辑题

    --   JSP/Servlet  Java面试逻辑题   --     很显然,Servlet/JSP的WEB前端动态制作的重要性比HTML/CSS/JS的价值高很多,但我们都知道他们都是建立在HT ...

  2. 分享13道上海尚学堂拿回来的Java面试真题,这些都是Java核心常见问题,想拿OFFER必看!

    上海尚学堂Java培训学员参加面试带回来的真题,分享出来与大家,希望大家能认真地看看做一遍.后面有详细题解答案,对照下,看看自己做得怎么样,把这些面试遇到的真题全部掌握,做好面试笔试前的准备. 一.1 ...

  3. 【Java面试真题】剑指Offer53.2——0~n-1中缺失的数字(异或、二分两种解法)

    [Java实现]剑指Offer53.2--0~n-1中缺失的数字:面试真题,两种思路分享 前面有另一道面试题[Java实现]剑指offer53.1--在排序数组中查找数字(LeetCode34:在排序 ...

  4. 秋招如何抱佛脚?2022最新大厂Java面试真题合集(附答案

    2022秋招眼看着就要来了,但是离谱的是,很多同学最近才想起来还有秋招这回事,所以纷纷临时抱佛脚,问我有没有什么快速磨枪的方法, 我的回答是:有! 说起来,临阵磨枪没有比背八股文更靠谱的了,很多人对这 ...

  5. java面试基础题(三)

    程序员面试之九阴真经 谈谈final, finally, finalize的区别: final:::修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此 ...

  6. java面试95题

    1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注 ...

  7. java面试编程题

      [程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?   //这是一个菲波拉契数列问 ...

  8. Java面试经典题:线程池专题

    1.什么是线程池 线程池的基本思想是一种对象池,在程序启动时就开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完成后线程对象归池, ...

  9. java 面试算法题

    /** * 设有n个人依围成一圈,从第1个人开始报数,数到第m个人出列,然后从 * 出列的下一个人开始报数,数到第m个人又出列,…,如此反复到所有的人全部出列为 * 止.设n个人的编号分别为1,2,… ...

  10. java面试基础题------》Java 中的父子类静态代码块,代码块,构造方法执行顺序

    4.指出下面程序的运行结果. class A { static { System.out.print("1"); } public A() { System.out.print(& ...

随机推荐

  1. JSR303数据校验

    Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理. 导入依赖: <dependency> <groupId>org ...

  2. JavaScript常用的Hook脚本

    JavaScript常用的Hook脚本 本文Hook脚本 来自 包子 页面最早加载代码Hook时机 在source里 用dom事件断点的script断点 然后刷新网页,就会断在第一个js标签,这时候就 ...

  3. NX二次开发 克隆

    NXOpen.UF.UFSession theUfSession = NXOpen.UF.UFSession.GetUFSession(); try { //初始化 NXOpen.UF.UFClone ...

  4. Kubernetes client-go 源码分析 - Reflector

    概述入口 - Reflector.Run()核心 - Reflector.ListAndWatch()Reflector.watchHandler()NewReflector()小结 概述 源码版本: ...

  5. python打印爱心

    print('\n'.join([''.join([('AndyLove'[(x-y)%8]if((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 ...

  6. HTTP请求如何带参

    这两天正好作一份API的接口文档,关于HTTP request如何传递参数不是很清楚,这里转载了他人的文档,让我明白了很多.. http://tomfish88.iteye.com/category/ ...

  7. 矩阵n次幂的计算

    1.归纳法 两大数学归纳法 题目一 2.递推关系 题目一 题目二 3.方阵 题目一 4.矩阵对角化(重点) 题目一 题目二 题目三 题目四 5.矩阵性质(综合) 题目一 题目二 对于副对角线: 题目三

  8. 洛谷 P2680 [NOIP2015 提高组] 运输计划

    链接:P2680 题意: 在树上把一条边边权变为0使得最长给定路径最短 分析: 最大值最小可以想到二分答案,对于每一个mid,寻找所有大于mid的路径,再寻找是否存在一条边使得删去它后大于mid的路径 ...

  9. linux c语言 rename的用法-rename() does not work across different mount points, even if the same file system is mounted on both

    最近在一个项目上执行文件的搬移功能时发现总是失败,临时录像文件存放于emmc的/tmp/目录下,当录像完成时候则调用rename企图将此文件搬到/mnt/sdcard/mmcblk1p1/(这是外置的 ...

  10. 无缓存交换 牛客网 程序员面试金典 C++ Python

    无缓存交换 牛客网 程序员面试金典 C++ Python 题目描述 请编写一个函数,函数内不使用任何临时变量,直接交换两个数的值. 给定一个int数组AB,其第零个元素和第一个元素为待交换的值,请返回 ...