admin管理员组

文章数量:1547451

《java工程师 基础 面经 转行为人民服务 供有需要的人学习》

  • 知识点1、简单讲讲java跨平台原理 (java编程语言基础)
    • 第一小问:java中的int数据占几个字节
    • 第二小问:面向对象的特征有哪些?
    • 第三小问:有了基本数据类型,为什么还需要包装类型
    • 第四小问:讲一下String和StringBuilder的区别?StringBuffer和StringBuilder区别?
    • 第五小问:讲一下java中的集合
    • 第六小问:ArrayList和LinkedList区别
    • 第七小问:HashMap和HashTable的区别 (几乎每家公司都问)****
      • 第七小问引发的大问、那你说说hashMap的底层实现原理(*****)
    • 第八小问:==和equals区别是什么
    • 第九小问:final在java中的作用
    • 第十小问:java中的Math.round(-1.5)等于多少
    • 第十一小问:String str="i"和String str = new String("i")一样吗
    • 第十二小问:如何将字符串反转
    • 第十三小问:抽象类必须要有抽象方法吗?
    • 第十四小问:抽象类和普通类的区别
    • 第十五小问:抽象类能用final修饰吗
    • 第十六小问:接口和抽象类有什么区别 (容易问)
    • 第十七小问:float f=3.4;是否正确? ??
    • 第十八小问:NIO、AIO、BIO有什么区别
    • 第十九小问、JDK与JRE有什么区别
    • 第二十小问、a+=b和a =a+b有区别吗?
    • 第二十一小问、如何来重写一个equals方法
    • 第二十二小问、Collection和Collections有什么区别
    • 第二十三小问、如何决定使用HashMap还是TreeMap
    • 第二十四小问、如何实现数组和List之间的转换
    • 第二十五小问:ArrayList和Vector区别
    • 第二十六小问:Array和ArrayList有何区别
    • 第二十七小问:Queue中的poll()和remove区别
    • 第二十八小问:哪些集合是线程安全的
    • 第二十八大问、ConcurrentHashMap底层实现原理?
    • 第二十九小问:迭代器Iterator是什么?怎么使用?
    • 第三十小问:Iterator和ListIterator有什么区别
    • 第三十一小问:集合框架中的泛型有什么优点?
    • 第三十二小问:为何Iterator接口没有具体的实现?
    • 第三十三小问:我们能否使用任何类作为Map的key?
    • 第三十四小问、Map接口提供了哪些不同的集合视图?
    • 第三十五小问、Comparable和Comparator接口有何区别?
    • 第三十六小问、BlockingQueue是什么?
    • 第三十七小问、我们如何对一组对象进行排序?
    • 第三十八小问、当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它?
    • 第三十九小问、我们如何从给定集合那里创建一个synchronized的集合?
    • 第四十小问、大写的O是什么?举几个例子?
    • 第四十一小问、使用Java集合框架有哪些最好的实践? (**)
    • 第四十二小问、数组为null和空有什么区别?
    • 第四十三小问、 字符流和字节流的区别
    • 第四十四小问、存在使i + 1 < i的数吗?
    • 第四十五小问、创建对象有哪几种方式
    • 第四十六小问、是否可以继承String 类?
    • 第四十七小问、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
    • 第四十八小问、char 型变量中能不能存贮一个中文汉字?为什么?
    • 第四十九小问、如何实现对象克隆?有时候为什么需要对象克隆?(6月26日看不会)
    • 第五十小问、深拷贝和浅拷贝区别是什么?
    • 第五十一小问、什么是java的序列化?什么情况下需要序列化?
    • 第五十二小问、throw 和throws区别?
    • 第五十三小问、 final、finally、finalize有什么区别
    • 第五十四小问、try-catch-finally中,哪个部分是可以省略的?
    • 第五十五小问、try-catch-finally中,如果catch中return了,finally还会执行吗?
    • 第五十六小问、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分? (**)
  • 知识点2、那你说说虚拟机的类加载机制 (JVM)(***)
    • 第一小问:谈一谈类加载器的双亲委派模型
    • 第二小问:字节码执行引擎是如何执行字节码的 (6月27日不熟)
    • 第三小问:你说说java的内存模型(***)
  • 知识点3、线程有几种创建方式?(多线程并发方面 )
    • 第一小问、线程池都有哪几种工作队列(*)
    • 第二小问、线程池创建时有哪些关键的参数
      • 第二小问补充的第一小问、线程池的实现原理
      • 第二小问补充的第一小问、线程池中的线程是怎么创建的?是一开始就随着线程池的启动创建好的吗
    • 第三小问、如何合理配置线程池的大小 ?
    • 第四小问、进程和线程的区别是什么?
    • 第五小问、sleep()和wait()有什么区别?
    • 第六小问、sleep()和yield()有什么区别?
    • 第七小问、并发和并行有什么区别?
    • 第七小问、请说出与线程同步有哪些相关的方法(**)
    • 第八小问、你知道什么是守护线程
    • 第九小问、线程有哪些状态
    • 第十小问、notify()和notifyAll()区别
    • 第九小问、线程的run()和start()方法有什么区别?
    • 第十小问、创建线程池有哪些方式?及使用场景。(***)
    • 第十一小问、线程池有哪些状态?
    • 第十二小问、线程池中的submit()和execute()方法有什么区别
    • 第十三小问、多线程锁的升级原理是什么?(***) 尚不理解
      • 第十三小问的变型:JVM 对 Java 的原生锁做了哪些优化?
    • 第十四小问、java中锁有几种表现形式
    • 第十四小问、ThreadLocal是什么?有哪些使用场景
      • 第十四小问补充的第一小问:很多人都说要慎用 ThreadLocal,谈谈你的理解,使用 ThreadLocal 需要注意些什么?
    • 第十五小问、Synchronized底层实现原理?(***)
      • 第十五小问引发的第一小问:你刚才说的对象的锁是什么?如何确定对象的锁?
    • 第十五小问引发的第二小问:为什么说 Synchronized 是可重入锁?
    • 第十五小问引发的第三小问:什么是锁消除和锁粗化?
      • 第十五小问引发的第四小问:乐观锁的实现原理又是什么?什么是 CAS,它有什么特性?
    • 第十六小问、如何防止死锁?
    • 第十七小问、Synchronized和volatile的区别是什么(**)
    • 第十八小问、Synchronized和Lock区别
    • 第十九小问、相比synchronized,ReentrantLock的可重入有什么区别吗?
    • 第二十小问、乐观锁一定就是好的吗?
    • 第二十一小问、死锁与活锁的区别,死锁与饥饿的区别?
    • 第二十三小问、synchronized、ReentrantLock都是可重入的锁,什么是可重入锁?
    • 第二十四小问、为什么wait(), notify(), notifyAll()必须要在synchronized方法/块中
    • 第二十五小问、如何停止一个正在运行的线程?
    • 第二十六小问、java如何实现多线程之间的通讯和协作?
    • 第二十七小问、乐观锁和悲观锁的理解及如何实现,有哪些实现方式?
    • 第二十八小问、volatile有什么用?能否用一句话说明下volatile的应用场景?
    • 第二十九小问、servlet是线程安全吗?
    • 第三十小问、Java中用到的线程调度算法是什么?
    • 第三十一小问、什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者模型?
    • 第三十二小问、什么是FutureTask?
    • 第三十三小问、CycliBarriar和CountdownLatch有什么区别?
    • 第三十四小问、什么是不可变对象?
    • 第三十五小问、为什么使用Executor框架比自己创建和管理线程好?
    • 第三十六小问、请谈谈AQS框架 6月27日不熟 难
    • 第三十七小问、Condition
    • 第三十八小问、CopyOnWriteArrayList可以用于什么应用场景
    • 第三十九小问、Java中Semaphore有了解过吗?
    • 第四十小问、Java中的ReadWriteLock是什么
  • 知识点四、数据库 (不熟)
    • 第一小问、关系数据库三范式 华为一面凉经
    • 第二小问、什么是ORM框架?
    • 第二小问、数据库的事务与隔离级别
    • 第三小问、mysql数据库的默认最大连接数
    • 第四小问、什么是索引?你知道Mysql 有哪些索引?分别介绍一下
    • 第五小问、索引的优缺点?哪些情况适合建索引哪些情况不适合建索引?(略读)
    • 第六小问、数据库事务的实现原理?事务的分类?使用事务应该注意的问题?
    • 第七小问、什么是存储过程?有哪些优缺点?(略读)
    • 第八小问、说一说drop、delete与truncate 英 [trʌŋ'keɪt; 'trʌŋ-] 的区别?
    • 第九小问、SQL 优化的一般步骤(待学习)
    • 第十小问、你知道哪些常用的SQL 的优化(待学习。。。)
    • 第十一小问、什么是视图?以及视图的使用场景有哪些?
    • 第十二小问、超键、候选键、主键、外键分别是什么?
    • 第十三小问、Mysql 的几种连接方式?
    • 第十四小问、你知道Mysql的分页原理吗???(**)
    • 第十五小问、 简单讲一下数据库触发器使用场景(待理解)
    • 第十六小问、什么是索引?mysql数据库中表的索引方式有几种?
    • 第十七小问、什么情况下适合添加索引?
    • 第十八小问、事务开启和结束的标志是什么
    • 第十九小问、一对一、一对多、多对多关系的数据表如何设计?
    • 第二十小问、MYISAM和InnoDB对比?
    • 第二十一小问、常见SQL语句会写吗?
    • 第二十二小问:执行数据库查询时候,如果查询的数据有很多,假设有1000万条,用什么方法可以提高查询效率?在数据库方面或java代码方面有什么优化办法?
    • 第二十三小问、Mysql数据库有哪些优化技术(**)
    • 第二十四小问、为什么创建索引后,速度就会变快?你知道索引的原理吗?(待补充)
    • 第二十五小问、如何进行表的水平分割和垂直分割?
    • 第二十六小问、InnoDB存储引擎的B+树实现原理 (****)
    • 第二十七小问、什么时候索引会失效?
    • 第二十八小问、在进行数据库编程时,数据库连接池有什么作用?
    • 第二十九小问、一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后,删除了第 15,16,17 条记录, 再把 Mysql 重启,再 insert 一条记录,这条记录的 ID 是 18 还是 15 ?
    • 第三十小问、与 Oracle 相比,Mysql 有什么优势?
    • 第三十一小问、Mysql 中有哪几种锁?
    • 第三十二小问、Mysql 表中允许有多少个 TRIGGERS?
  • 知识点5、网络通信
  • 知识点6、数据结构与算法
    • 第一小问、什么是算法复杂度?如何算算法复杂度?
    • 第二小问、从不重复的数组中选取出三角形的三条边有几种选法?
    • 第三小问、给出二叉树的前序遍历和中序遍历的结果,如何重新构建二叉树
    • 第四小问、青蛙跳台阶问题,一次只能跳1或者2步,每次可跳n步 有多少种跳法
  • 知识点7、设计模式
    • 第一小问、你知道Spring中运用了什么设计模式?
  • 面试题4、重点讲讲HashMap、算法复杂度、hash冲突时如何解决?(华为1面凉经)
  • 面试题5、你有用过Kafka是吧?简要介绍一下kafka
  • 面试题7、你会用什么设计模式?补充。。。
  • 面试题8、Web方面知识:说一下对Servlet的理解,以及Servlet生命周期
    • 第一小问、forward ()转发和redirect()重定向的区别
    • 第二小问、JSP和Servlet的区别
    • 第三小问、JSP有哪些内置对象?作用分别是什么
    • 第四小问、Cookie和session区别?
    • 第五小问、简单说一下Session工作原理
    • 第六小问、MVC的各个部分有哪些技术可以实现
    • 第七小问、Spring MVC和Struts的区别是什么?
    • 第八小问、如何避免SQL注入攻击?(待学习)
    • 第九小问、什么是XSS攻击,如何避免?
    • 第十小问、什么是CSRF攻击,如何避免?

知识点1、简单讲讲java跨平台原理 (java编程语言基础)

  java能够实现“一次编译,到处运行”,跨平台原理是通过JVM(java 虚拟机)实现的,JVM不是跨平台的,sun公司针对不同的平台分别设计不同的JVM,不同版本的不同位数的java虚拟机屏蔽不同系统指令集开发的差别而都统一使用字节码程序存储格式。java语言编译后生成字节码.calss文件,JVM拿到这个字节码文件后,涉及到虚拟机的类加载机制,(加载、验证、准备、解析、初始化),然后会通过它的字节码执行引擎执行字节码文件,

第一小问:java中的int数据占几个字节

  java中的基本数据类型有8种,int占4个字节,32位。Boolean占1个位。

第二小问:面向对象的特征有哪些?

  有四大基本特征,封装、抽象、多态、继承。
  封装就是把对象封装成相对封闭的个体,对象的属性由它自己的行为来读取和改变。
  抽象就是找出事务的相似与共同之处然后过程一共类
  继承:在一个已经存在的类基础上,把这个已经存在的类的内容作为自己的内容
  多态是一个引用变量声明的时候是父类或者是接口,但是是指向子类或者具体的实现类,而程序调用的方法是运行时动态绑定,并且执行是具体执行的实例对象方法。

第三小问:有了基本数据类型,为什么还需要包装类型

  java是一种面向对象的语言,而基本的数据类型不具备面向对象的特性,包装类封装了许多MAX_VALUE、MIN_VALUE属性,还提供了缓存机制。java中的8中基本类型每一种都意义对应一个包装类型,int----》Integer。基本类型与包装类型之间的转换使用了自动装箱和拆箱的机制,装箱:就是将基本类型转换成包装类,例如Integer i = 1;自动装箱,实际上编译时是调用了Integer.valueOf方法来装箱。
  java在类加载时候会为-128到127区间的每个数创建对象,并且放在cache数组中。当我们自动装箱时,或者手动调用valueOf方法时,会判断该数据是否在这个区间,如果在,则直接获取这个cache数组中包装类对象的引用。
  例如:Integer i = -128; Integer j = -128; i == j; 是的,两者是同一对象。
拆箱:就是将包装类型转换成基本类型,分为自动拆箱和手动拆箱。

第四小问:讲一下String和StringBuilder的区别?StringBuffer和StringBuilder区别?

  String 对象是不可改变的,String 类型变量底层使用一个不可变字符数组(final char[]),并且自身维护了一个字符串常量池在方法区中,如果新建了大量的String变量,方法区中jvm无法垃圾回收,那么造成内存资源的大量浪费。在而StringBuffer、StringBuilder底层使用可变字符数组,进行字符串拼接时更加节省内存。StringBuilder是线程不安全,效率高,而StringBuffer线程安全,效率低。在单线程环境下使用的,因为StringBuilder的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高。

第五小问:讲一下java中的集合

  java中的集合分value、key-value两种,存储value的有List和Set,两者的区别就在于是否有序、是否唯一。 当集合存储对象时,必须重写equals和hashCode方法。在每个覆盖equals方法的类中,也必须覆盖hashCode方法。这是Object类的通用约定,相等的对象必须具有相等的散列码hash code。
  存储key-value结构的集合是Map,Map接口实现类有HashMap、treeMap、vector、HashTable、ConcurrentHashMap、LinkedHashMap。其中线程安全的有vector、ConcurrentHashMap、hashTable
  Set代表集合元素无序、不可重复的集合,Map是由key-value键值对组成的集合,但是Map中的key是不可重复的,key之间没有顺序,如果把所有的key集中起来就组成了一个Set集合。所以Map接口所有的key具有Set集合的特征,Map接口也提供了keySet()方法用于返回所有key组成的Set集合。Map集合本质上是一个双向关联数组,我们如果把key-value对捆绑起来,那么Map集合可以视为Set集合,Map集合可以说是Set集合的扩展。

第六小问:ArrayList和LinkedList区别

  List常用的是ArraryList和LinkedList,两者区别是底层实现的数据结构不同,一个是数组,一个是循环双向链表。访问数组中第 n 个数据的时间花费是 O(1) 但是要在数组中查找一个指定的数据则是 O(N) 。当向数组中插入或者删除数据的时候,最好的情况是在数组的末尾进行操作,时间复杂度是 O(1) ,但是最坏情况是插入或者删除第一个数据,时间复杂度是 O(N) 。在数组的任意位置插入或者删除数据的时候,后面的数据全部需要移动,移动的数据还是和数据个数有关所以总体的时间复杂度仍然是 O(N) 。在链表中查找第 n 个数据以及查找指定的数据的时间复杂度是 O(N) ,但是插入和删除数据的时间复杂度是 O(1) ,因为只需要调整指针就可以

第七小问:HashMap和HashTable的区别 (几乎每家公司都问)****

  • 产生时间:Hashtable比HashMap更早产生,虽然Hashtable是线程安全的,但是效率比较低。而且Hashtable没有遵循驼峰命名法。虽然Hashtable比HashMap出现的早一些,但是现在Hashtable基本上已经被弃用了。而HashMap已经成为应用最为广泛的一种数据类型了。
  • 继承的父类不同:HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。Dictionary字典
  • 对外提供的接口不同:Hashtable比HashMap多提供了elments() 和contains() 两个方法。elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。
  • 对Null key 和Null value的支持不同:Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的注释中有说明。HashMap把null作为了一个特殊的键,因此不会像Hashtable一样抛出异常;可以有一个或多个键所对应的值为null。当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
  • 线程安全性不同:Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步。HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。具体的原因在下一篇文章中会详细进行分析。使用HashMap时就必须要自己增加同步处理,虽然HashMap不是线程安全的,但是它的效率会比Hashtable要好很多。这样设计是合理的。在我们的日常使用当中,大部分时间是单线程操作的。HashMap把这部分操作解放出来了。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定
  • 遍历方式的内部实现上不同:Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。HashMap的Iterator是fail-fast迭代器。当有其它线程改变了HashMap的结构(增加,删除,修改元素),将会抛出ConcurrentModificationException。不过,通过Iterator的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。JDK8之前的版本中,Hashtable是没有fast-fail机制的。在JDK8及以后的版本中 ,HashTable也是使用fast-fail的
  • 初始容量大小和每次扩充容量大小的不同Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。创建时,如果给定了容量初始值,那么Hashtable会直接使用你给定的大小,而HashMap会将其扩充为2的幂次方大小。也就是说Hashtable会尽量使用素数、奇数。而HashMap则总是使用2的幂作为哈希表的大小。之所以会有这样的不同,是因为Hashtable和HashMap设计时的侧重点不同。Hashtable的侧重点是哈希的结果更加均匀,使得哈希冲突减少。当哈希表的大小为素数时,简单的取模哈希的结果会更加均匀。而HashMap则更加关注hash的计算效率问题。在取模计算时,如果模数是2的幂,那么我们可以直接使用位运算来得到结果,效率要大大高于做除法。HashMap为了加快hash的速度,将哈希表的大小固定为了2的幂。当然这引入了哈希分布不均匀的问题,所以HashMap为解决这问题,又对hash算法做了一些改动。这从而导致了Hashtable和HashMap的计算hash值的方法不同
  • 两者确定哈希表主干数组上的下标方式不同,hashtable是把其哈希值取余table.length方式。hashMap为了提高效率,不用除法,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算,哈希值和(数组长度-1)进行按位与操作,得到存储的数组下标。HashMap的初始大小和扩容都是以2的次方来进行的,换句话说length-1换成二进制永远是全部为1,比如容量为16,则length-1为1111,所以相与的数可能是偶数或者奇数,这样hash后的值在table中尽量的分散,前面就有提到hash的目的就是为了使分布更均匀 减少冲突。数组加链表,当key 的hash值冲突时 用链地址法解决冲突,在同一个相同下标的table中用链表的形式连接起来

1、hashMap和hashTable都实现了Map的接口,从实现结构上就是hashtable是单纯的链表数据结构对应的就是查询效率低,增删快。而hashmap是一种链表数组,在不考虑哈希冲突的情况下,哈希表的主干就是数组,它的查询操作仅需一次定位即可完成,时间复杂度为O(1)。hashMap的查询性能是优于hashTable
2、hashTable虽然查询性能比不上hashMap,但是它对读写加了同步操作,所以hashTable是线程安全的。
3、HashMap是支持null键和null值的,而HashTable在遇到null时,会抛出NullPointerException异常。这并不是因为HashTable有什么特殊的实现层面的原因导致不能支持null键和null值,这仅仅是因为HashMap在实现时对null做了特殊处理,将null的hashCode值定为了0,从而将其存放在哈希表的第0个bucket中

4、HashMap提供对key的Set进行遍历,因此它是fail-fast的,但HashTable提供对key的Enumeration进行遍历,它不支持fail-fast。
  每次我们尝试获取下一个元素的时候,Iterator fail-fast属性检查当前集合结构里的任何改动。如果发现任何改动,它抛出ConcurrentModificationException。Collection中所有Iterator的实现都是按fail-fast来设计的(ConcurrentHashMap和CopyOnWriteArrayList这类并发集合类除外)。
  Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent(并发工具包)中的集合类都为fail-safe的。fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。

第七小问引发的大问、那你说说hashMap的底层实现原理(*****)

  HashMap底层是由数组和链表两种数据结构组合而成的,HashMap的主干是一个Entry数组,每一个Entry包含一个key-value键值对。HashMap由数组+链表组成的,数组是HashMap的主体**,链表则是主要为了解决哈希冲突而存在的**,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,仅需简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找,时间复杂度就是链表的查询复杂度O(n)。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
  如果要新增或查找某个元素,我们通过把当前元素的关键字 通过哈希函数映射到数组中的某个位置,index = h &(table.length-1);得到的index就是放置数据的位置,也就是经常看到的bucket
  如果插入时,两个键的hashcode相同,如何插入呢?如果说插入时两个键的hashcode相同,通过哈希函数得到的bucket位置也是相同,这时与在这个bucket上的原有的key的equals方法,比较,如果相同,则替换,如果不同,则添加。
  如果插入两个hashcode相同的对象,会有问题吗?如果说插入的这两个对象的键值不同,那么肯定不会有问题,map.put(1,student); map.put(2,student);明显不会有问题。如果插入的键值的hashcode相同,那么还是要通过equlas方法进行比较,相同的话只会存一个。
  如果两个键的hashcode相同,你如何获取值对象?当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,找到bucket位置之后,会调用keys.equals()方法去找到完全相同的key,最终找到要找的值对象。
  如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。

  一些优秀的开发者会指出使用不可变的、声明作final的对象,并且采用合适的equals()和hashCode()方法的话,将会减少碰撞的发生,提高效率。不可变性使得能够缓存不同键的hashcode,这将提高整个获取对象的速度,使用String,Interger这样的类作为键是非常好的选择
  如果用户想自定义类作为key,那么最好是将这个类定义成为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了
  你了解重新调整HashMap大小存在什么问题吗?当多线程的情况下,当重新调整HashMap大小的时候,确实存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。这个时候,你可以质问面试官,为什么这么奇怪,要在多线程的环境下使用HashMap呢?

第八小问:==和equals区别是什么

   == 是一个比较运算符,基本类型比较的是值,引用数据类型比较的是地址,equals是一个方法,只能比较引用数据类型,重写前比较的是地址值,重写后比较的是属性的值。 当然如果你重写了equlas方法,你必须要覆盖hashCode。否则,违背了Object.hashCode的通用约定,相等的对象必须具有相等的散列码hash code。

第九小问:final在java中的作用

   用于装饰类、类属性、类方法,对于final修饰的类属性而言,子类不能给他重写赋值,如果重写赋值会报错。

第十小问:java中的Math.round(-1.5)等于多少

   -1 ,四舍六入五成双,五分负数还是正数情况,注意负数5是舍的,例如:Math.round(1.5)值是2,Math.round(-1.5)值是-1

第十一小问:String str="i"和String str = new String(“i”)一样吗

  不一样,前一个直接存放在常量池中,后一个重新创建了一个String类对象,String类底层使用了一个final char[]来存储,所以String不可变,并且后者更占内存

第十二小问:如何将字符串反转

1、通过递归方法
2、通过charAt返回char进行字符串的拼接
3、将字符串转换成字符数组倒叙拼接
4、通过StringBuffer中的reverse StringBuffer(s).reverse().toString()

第十三小问:抽象类必须要有抽象方法吗?

   抽象类不一定要有抽象方法,单有抽象方法的类必须是抽象类

第十四小问:抽象类和普通类的区别

1、抽象类不能被实例化
2、抽象类可以有构造函数,被继承时子类继承父类的构造方法,抽象方法不能被声明为静态
3、抽象方法只需声明,无需实现
4、包含抽象方法的类必须声明为抽象类
5、抽象的子类必须实现抽象类中的所有抽象方法,否则这个类也是抽象类

第十五小问:抽象类能用final修饰吗

   final关键字不能修饰抽象方法

第十六小问:接口和抽象类有什么区别 (容易问)

首先,从语法上讲,

  • 抽象类中除了抽象方法,还可以有方法的实现,而接口比抽象类更加抽象,只能有抽象方法。
  • 抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的
  • 抽象类中的成员可以是private、默认、protected、public的,而接口中的成员实际上都是常量,全都是public的,如果是常量的话是默认为public static final。接口中由于没有具体方法体,所以无法定义属性的set和get方法,所以它干脆把属性定义为常量,例如接口中interface geneElec{ int power = 220; void generate();} 其中power由于是在接口中,所以默认的修饰符是public static final。

  从java面向对象编程语言角度为什么要设计接口和抽象类两者?抽象类是对概念的归纳,接口是对功能的归纳,两者的侧重点不一样。任何的一个类当要扩展功能时,可以通过实现多个接口,而需要将现有的类的内容归为自己所有,则采用面向对象的四大基本特征之一,继承来实现(认现有的类作儿子)。 一个类可以实现多个接口,但只能继承一个父类。

第十七小问:float f=3.4;是否正确? ??

   答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;

第十八小问:NIO、AIO、BIO有什么区别

BIO和NIO是两种不同的网络通信模型,如今NIO的成熟框架有Jetty,Netty开源框架
BIO适用于连接数目比较小,并且一次发送大量数据的场景,这种方式对服务器资源要求比较高
NIO是同步非阻塞,支持大量的长连接,比如10000个连接,AIO 实际用的比较少

第十九小问、JDK与JRE有什么区别

  jre是java的运行环境,包括了java虚拟机和java类库。JDK是java开发工具包,是程序员用java编写java程序的所用到的开发包。 总结的说就是:jdk和jre,一个用于开发,一个用于运行。

第二十小问、a+=b和a =a+b有区别吗?

  在java语言中,a+=b和a=a+b的主要区别是在运算的精度上。类似的有“-= 、 *= 、/= 、%= ”,大家需要明确的是“+=”是java中的一个运算符,而不是两个,所以在运算时 会进行自动类型转换。所以在编译时没有报错。
使用a = a+b ,很明显,下面出错了,提示类型不匹配:不能从int转换为byte

但是给用a+= b,会自动进行类型转换

第二十一小问、如何来重写一个equals方法

  Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

实现高质量的equals方法的诀窍包括:

  1. 使用==操作符检查"参数是否为这个对象的引用";
  2. 使用instanceof操作符检查"参数是否为正确的类型"
  3. 对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;
  4. 编写完equals方法后,问自己它是否满足对称性、传递性、一致性;必须满足自反性(x.equals(x)必须返回true)、对称性(x.equals(y)返回true时,y.equals(x)也必须返回true)、传递性(x.equals(y)和y.equals(z)都返回true时,x.equals(z)也必须返回true)和一致性(当x和y引用的对象信息没有被修改时,多次调用x.equals(y)应该得到同样的返回值),而且对于任何非null值的引用x,x.equals(null)必须返回false
  5. 重写equals时总是要重写hashCode
  6. 不要将equals方法参数中的Object对象替换为其他的类型,在重写时不要忘掉@Override注解。

第二十二小问、Collection和Collections有什么区别

java.util.collection是一个集合接口,提供了对集合对象进行基本操作的通用接口方法
Collections是集合类的一个工具类,提供了对集合操作的一系列静态方法,可以进行搜索、排序操作

第二十三小问、如何决定使用HashMap还是TreeMap

  对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将Map换为TreeMap进行有序key的遍历。

第二十四小问、如何实现数组和List之间的转换

  List转数组:toArray(arrayList.size)方法
  数组转List: Arrays的asList(a)方法

第二十五小问:ArrayList和Vector区别

  1、Vector方法同步,线程安全,而ArrayList方法不是,由于线程同步必然影响性能,因此,ArrayList性能比Vector好
  2、当Vector或者ArrayList的元素超过它的初始值,Vector会将其容量翻倍,而ArrayList只增加50%大小,ArrayList更加有利于节约内存

第二十六小问:Array和ArrayList有何区别

1、ArrayList是Array的复杂版本
2、ArrayList可以存储异构对象,而Array只能存储相同类型的数据,例如[1,a,true] 和 [ 1,2,3 ]
3、Array的长度实际上是不可变的,二维变长数组实际上长度也是固定的,可变的是其中元素的长度,而ArrayList的长度可以指定也可不指定,是变长的
4、存储和删除的不同

第二十七小问:Queue中的poll()和remove区别

  remove和poll方法都是删除队列的头元素,remove方法在队列为空的时候抛出异常,而poll方法返回Null

第二十八小问:哪些集合是线程安全的

vector 、HashTable、ConcurrentHashMap、Stack

第二十八大问、ConcurrentHashMap底层实现原理?

  ConcurrentHashMap是线程安全的,将整个Hash桶进行了分段Segment,也就是将这个大的数组分成了几个小的Segment,每个Segment上都有锁存在,在插入元素时,需要先找到应该插入到哪个Segment,然后获取这个Segment的锁,最后进行插入。
  HashTable容器在并发竞争情况下效率低是因为所有访问HashTable都必须竞争一把锁,ConcurrentHashMap分段锁的原理就是将锁的粒度缩小,相当于一个容器中有多把锁,这样线程之间就不会存在竞争,从而提高了访问效率。
  ConcurrentHashMap中get操作是没有加锁,除非读到的值是null才会加锁重读,get方法中使用的共享变量都用了volatile来修饰,如统计当前Segment大小的count值,volatile变量可以保证线程之间的可见性。

第二十九小问:迭代器Iterator是什么?怎么使用?

Iterator是为了各自容器提供公共的操作接口,使对容器的遍历操作与具体的底层相隔离,起解耦作用,注意迭代器允许调用者在迭代过程中移除元素
Iterator常用的方法:
1、boolean hasNext()
2、Obeject next()
3、void remove()
Iterator的特点:在使用迭代器的过程中

  • 1、不允许线程对集合进行修改,否则会抛出异常
  • 2、可以通过remove方法来移除集合中的元素
  • 3、Iterator必须依附Collection对象而存在,本身不具有装载数据对象的功能
  • 4、Iterator.remove()方法是删除上一次Iterator.next()返回的对象
  • 5、next()方法通过游标指向方式返回下一个Iterator的下一个元素

第三十小问:Iterator和ListIterator有什么区别

(1)我们可以使用Iterater来遍历Set和List集合,而ListIterator只能遍历List。
(2)Iterater只可以向前遍历,而ListIterator可以双向遍历。
(3)ListIterator从Iterater接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

第三十一小问:集合框架中的泛型有什么优点?

  在Java1.5引入了泛型,所有的集合接口和实现都大量地使用它。泛型允许我们为集合指定一个可以容纳的对象类型,因此,如果你不小心添加其它类型的任何元素,它会在编译时报错。这避免了在运行时出现ClassCastException,因为你将会在编译时得到报错信息。泛型也使得代码整洁,我们不需要使用显式转换和instanceOf操作符。它也给运行时带来好处,因为不会产生类型检查的字节码指令。也就是说虽然集合中泛型可以让我们使用任何对象类型,但是只要我们选择了一种类型则在后面代码中就必须使用此类型,否则就会报错。

第三十二小问:为何Iterator接口没有具体的实现?

  Iterator接口定义了遍历集合的方法,但它的实现则是集合实现类的责任。每个能够返回用于遍历的Iterator的集合类都有它自己的Iterator实现内部类。
  这就允许集合类去选择迭代器是fail-fast还是fail-safe的。比如,ArrayList迭代器是fail-fast的,而CopyOnWriteArrayList迭代器是fail-safe的。

第三十三小问:我们能否使用任何类作为Map的key?

  我们可以使用任何类作为Map的key,然而在使用它们之前,需要考虑以下几点:
(1)如果类重写了equals()方法,它也应该重写hashCode()方法。
(2)类的所有实例需要遵循与equals()和hashCode()相关的规则。如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。
(3)如果一个类没有使用equals(),你不应该在hashCode()中使用它。
(4)如果用户想自定义类作为key,那么最好是将这个类定义成为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了
比如,我有一个类MyKey,在HashMap中使用它。

//传递给MyKey的name参数被用于equals()和hashCode()()中
MyKey key = new MyKey('Pankaj'); //assume hashCode=1234
myHashMap.put(key, 'Value');

// 以下的代码会改变key的hashCode()和equals()值

key.setName('Amit'); //assume new hashCode=7890

//下面会返回null,因为HashMap会尝试查找存储同样索引的key,而key已被改变了,匹配失败,返回null

myHashMap.get(new MyKey('Pankaj'))

那就是为何String和Integer被作为HashMap的key大量使用

第三十四小问、Map接口提供了哪些不同的集合视图?

Map接口提供三个集合视图:
(1)Set keyset():返回Map中包含的所有key的一个Set视图。集合是受Map支持的,Map的变化会在集合中反映出来,反之亦然。当一个迭代器正在遍历一个集合时,若Map被修改了(除迭代器自身的移除操作以外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。
(2)Collection values():返回一个Map中包含的所有value的一个Collection视图。这个Collection受Map支持的,Map的变化会在Collection中反映出来,反之亦然。当一个迭代器正在遍历一个Collection时,若Map被修改了(除迭代器自身的移除操作以外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从Map中移除对应的映射。它不支持add和addAll操作。
(3)Set<Map.Entry<K,V>> entrySet():返回一个Map钟包含的所有映射的一个集合视图。这个集合受Map支持的,Map的变化会在Collection中反映出来,反之亦然。当一个迭代器正在遍历一个集合时,若map被修改了(除迭代器自身的移除操作,以及对迭代器返回的entry进行setValue外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。

第三十五小问、Comparable和Comparator接口有何区别?

  Comparable和Comparator接口被用来对对象集合或者数组进行排序。Comparable接口被用来提供对象的自然排序,我们可以使用它来提供基于单个逻辑的排序。Comparator接口被用来提供不同的排序算法,我们可以选择需要使用的Comparator来对给定的对象集合进行排序。Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序

第三十六小问、BlockingQueue是什么?

  Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。

第三十七小问、我们如何对一组对象进行排序?

如果我们需要对一个对象数组进行排序,我们可以使用Arrays.sort()方法。如果我们需要排序一个对象列表,我们可以使用Collections.sort()方法。两个类都有用于自然排序(使用Comparable)或基于标准的排序(使用Comparator)的重载方法sort()。Collections内部使用数组排序方法,所有它们两者都有相同的性能,只是Collections需要花时间将列表转换为数组。

第三十八小问、当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它?

  在作为参数传递之前,我们可以使用Collections.unmodifiableCollection(Collection c)方法创建一个只读集合,这将确保改变集合的任何操作都会抛出UnsupportedOperationException。

第三十九小问、我们如何从给定集合那里创建一个synchronized的集合?

  我们可以使用Collections.synchronizedCollection(Collection c)根据指定集合来获取一个synchronized(线程安全的)集合。

第四十小问、大写的O是什么?举几个例子?

  大写的O描述的是,就数据结构中的一系列元素而言,一个算法的性能,算法复杂度。Collection类就是实际的数据结构,我们通常基于时间、内存和性能,使用大写的O来选择集合实现。比如:例子1:ArrayList的get(index i)是一个常量时间操作,它不依赖list中元素的数量。所以它的性能是O(1)。例子2:一个对于数组或列表的线性搜索的性能是O(n),因为我们需要遍历所有的元素来查找需要的元素

第四十一小问、使用Java集合框架有哪些最好的实践? (**)

(1)根据需要选择正确的集合类型。比如,如果指定了大小,我们会选用Array而非ArrayList。如果我们想根据插入顺序遍历一个Map,我们需要使用TreeMap。如果我们不想重复,我们应该使用Set。
(2)一些集合类允许指定初始容量,所以如果我们能够估计到存储元素的数量,我们可以使用它,就避免了重新哈希或大小调整
(3)基于接口编程,而非基于实现编程,它允许我们后来轻易地改变实现。
(4)总是使用类型安全的泛型,避免在运行时出现ClassCastException。
(5)使用JDK提供的不可变类作为Map的key,可以避免自己实现hashCode()和equals()。
(6)尽可能使用Collections工具类,或者获取只读、同步或空的集合,而非编写自己的实现。它将会提供代码重用性,它有着更好的稳定性和可维护性。

第四十二小问、数组为null和空有什么区别?

  数组为null:是创建了数组的引用,但在堆中并没有数组中的元素。例:int[] array1 = null; array1是数组类型的空引用,栈中名为array1的内存空间没有存放任何地址。数组为空:数组是空其实就是数组的长度为0,数组是真正的对象,只是对象中没有元素,也就是说里面没有内容。int[] array = {};。数组的长度为0,是一个空数组,但是array不是null,它也是一个对象,只不过它的元素个数为0。判断数组为空,使用array.length0可以,但是如果是为null,会抛出异常。

第四十三小问、 字符流和字节流的区别

  字节流与和字符流的使用非常相似,当程序写数据到一个文本中,字符流会先将数据放在缓冲区(一段特殊的内存内存中),再通过缓冲区写入文件中。使用字节流、字符流不关闭执行对文本的写入操作,你会发现打开指定的文本,字符流输出形式是没有看到内容,在关闭字符流时会强制性地将缓冲区中的内容进行输出到文本中。如果想在不关闭时也可以将字符流的内容全部输出,则可以使用Writer类中的flush()方法强制性清空缓冲区,将内容写入到文本中。
  在开发中,字节流使用较为广泛,字符流是字节流的包装。
            

第四十四小问、存在使i + 1 < i的数吗?

答案:存在,解析:如果i为int型,那么当i为int能表示的最大整数时,i+1就溢出变成负数了,此时不就<i了吗。

第四十五小问、创建对象有哪几种方式

(1)用new语句创建对象,这是最常见的创建对象的方法。
(2) 运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
(3) 调用对象的clone()方法。
(4) 运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。

第四十六小问、是否可以继承String 类?

答:String类是final类,不可以被继承。

第四十七小问、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

  无论是基本类型作为参数传递,还是对象作为参数传递,实际上传递的都是值,只是值的的形式不用而已。基本类型作为参数传递时好理解,方法中改变了形参,是不会改变实参的值的。但是当对象作为参数传递时,方法中改变了该对象中的值,原始的对象也会看起来像是也发生了改变。这是因为对象作为参数传递时是传递的是栈中的值,是栈内存中存放的堆内存的地址,真正的对象在堆中。(个人感觉是传引用,但是答案说传值,此值应该是指栈中的值)



第四十八小问、char 型变量中能不能存贮一个中文汉字?为什么?

  char类型可以存储一个中文汉字因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char类型占2个字节(16bit),所以放一个中文是没问题的。
  补充:使用Unicode意味着字符在JVM内部和外部有不同的表现形式,在JVM内部都是Unicode,当这个字符被从JVM内部转移到外部时 (例如存入文件系统中),需要进行编码转换。所以Java中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如 InputStreamReader和OutputStreamReader,这两个类是字节流和字符流之间的适配器类,承担了编码转换的任务

第四十九小问、如何实现对象克隆?有时候为什么需要对象克隆?(6月26日看不会)

  当有时候想对一个对象处理,但又想保留原有的数据进行接下来的操作,此时就需要进行克隆。

答:有两种方式:分深拷贝与浅拷贝
深拷贝有两种方式实现:
1.实现Cloneable接口并重写Object类中的clone()方法;因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。要想对一个对象进行复制,就需要对clone方法覆盖。覆盖clone()方法,访问修饰符设为public。覆盖方法中调用super.clone()方法得到需要的复制对象。
注意:并不是说重写了Object类的clone()方法就能进行拷贝,而是需要看你具体的clone如何实现。例如:若你没有对Address类也进行重写clone方法,所以Address addr只是复制了addr变量的引用,并没有真正的开辟另一块空间。

 Student implements Cloneable{
 private int number;  
 private Address addr;
....
    @Override  
     public Object clone() {  
        Student stu = null;  
         try{  
             stu = (Student)super.clone();  
         }catch(CloneNotSupportedException e) {  
             e.printStackTrace();  
         }  
        return stu;  
    }  
    Address addr = new Address();  
    addr.setAdd("杭州市");  
     Student stu1 = new Student();  
     stu1.setNumber(123);  
    stu1.setAddr(addr);
    addr.setAdd("西湖区");  
      
     Student stu2 = (Student)stu1.clone();  
       
     System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
     System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());   
    System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
    System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
     }

结果:
学生1:123,地址:杭州市
学生2:123,地址:杭州市
学生1:123,地址:西湖区
学生2:123,地址:西湖区
2.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

第五十小问、深拷贝和浅拷贝区别是什么?

  浅拷贝只是赋值了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之发生改变。 深拷贝是将对象及值赋值一个副本,两者没有关联。

第五十一小问、什么是java的序列化?什么情况下需要序列化?

  java的序列化就是将对象的内容转换成字节流,方便存储或者是网络传输。当然,在真实的网络传输中一般不会直接使用java序列化机制,java序列化有无法跨语言、序列化的码流太大、序列化的性能太低缺点。所以在网络传输中,有goole的Protobuf,FaceBook的Thrift、JBoss的Marshalling [ˈmɑːrʃlɪŋ] 吗休零。
  序列化通过实现Serializable接口。

第五十二小问、throw 和throws区别?

1、throw是在代码块内,即在捕获方法内的异常并抛出时用
2、throws是针对方法,即将方法的异常信息抛出
3、可以理解为throw是主动,而throws是被动

第五十三小问、 final、finally、finalize有什么区别

  final:用于修饰类、方法、变量
  finally:作为异常的处理部分,只能在try/catch语句中,表示这段语句最终一定会执行
  finalize:是java.lang.Object的方法,每个对象在被垃圾回收时被调用

第五十四小问、try-catch-finally中,哪个部分是可以省略的?

  try语句后面必须要有一个别的语句跟在后面:例如,try-catch,try-finally,try-catch-finally

第五十五小问、try-catch-finally中,如果catch中return了,finally还会执行吗?

  答:会的,在return前执行

第五十六小问、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分? (**)

  方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。
  就是每个重载的方法都必须有一个独一无二的参数类型列表,什么是独一无二的参数类型,即参数个数不同、参数类型不同、参数顺序不同,编译期可以根据不同的参数类型知道你调用的是哪个方法。但是重载如果根据返回类型来判断,比如在int x =f() 或者float x = f()中,那么的确可以据此却分重载方法。你如果调用的时候根本就不关心返回值的类型,那么编译器就不知道你调用的是哪个。而且如果用返回类型来区分,java中只有8种基本数据类型,那你的重载方法可以重载的的数量就受到了返回类型的限制。

知识点2、那你说说虚拟机的类加载机制 (JVM)(***)

  类加载机制主要包括:加载、验证、准备、解析、初始化五个阶段,加载是类加载的一个阶段:加载阶段通过类的全限定名获取该类的二进制字节流,然后将类的二进制字节流中的静态存储结构(静态方法、类变量)转化成方法区的运行数据结构,在内存中会生成一个代表这个类的java.lang.Class对象,作为方法区中这个类的各种数据访问入口。验证阶段:验证阶段是为了确保Class文件的字节流中的信息是否符合虚拟机的要求,不会危害虚拟机自身的安全。验证会验证文件格式、元数据、字节码、符号引用是否符合要求。准备阶段:会为类成员变量分配内存并且设置类变量初始化,static类变量就是此时进行初始化的。解析阶段:解析阶段是虚拟机将常量池中的符号引用代替成直接引用的过程,解析阶段不一定和其他阶段安装顺序完成,可能会交互混合式进行。初始化阶段是执行类构造器cIinit方法过程,java虚拟机规定了五种情况必须进行初始化,1、遇到new、getstatic、putstatic字节码指令时 2、使用java.lang.reflect包方法进行对类反射的时候 3、当初始化一个类,发现其父类还没进行过初始化,需要先触发其类的初始化 4、当用户指定要执行的主类(即包括main方法的类),虚拟机会先初始化这个主类 5、比较长,记不住了

第一小问:谈一谈类加载器的双亲委派模型

  双亲委派模型是一种设计模式(代理模式),类加载过程按照启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器这种层次关系进行加载叫双亲委派模型。我们把每一层上面的类加载器叫做当前层类加载器的父加载器,当然,它们之间的父子关系并不是通过继承关系来实现的,而是使用组合关系来复用父加载器中的代码。
            
  双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类
站在Java开发人员的角度来看,类加载器可以大致划分为以下三类:

启动类加载器:Bootstrap ClassLoader,跟上面相同。它负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类均被BootstrapClassLoader加载)。启动类加载器是无法被Java程序直接引用的。
扩展类加载器:Extension ClassLoader,该加载器由sun.misc.LauncherKaTeX parse error: Undefined control sequence: \jre at position 28: …er实现,它**负责加载JDK\̲j̲r̲e̲\lib\ext目录中**,或…AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
  应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,我们还可以加入自定义的类加载器。因为JVM自带的ClassLoader只是懂得从本地文件系统加载标准的java class文件,因此如果编写了自己的ClassLoader,便可以做到如下几点:
   1)在执行非置信代码之前,自动验证数字签名。
   2)动态地创建符合用户特定需要的定制化构建类。
   3)从特定的场所取得java class,例如数据库中和网络中。

JVM如何确立每个类在JVM的唯一性
  在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如 果一个名为Pg的包中,有一个名为Cl的类,被类加载器KlassLoader的一个实例kl1加载,Cl的实例,即C1.class在JVM中表示为 (Cl, Pg, kl1)。

为什么使用双亲委派
  比如 java.lang.String 这个类,这个是jdk提供的类, 如果我们自定义个 包名:java.lang 然后在里面创建一个String 类, 当我在用String类的时候,根据前面所说,是由bootstrap级的loader 来进行加载的,这个时候它发现其实已经加载过了jdk的String了,那么就不会去加载自定义的String了,防止了重复加载 也加大了安全性

第二小问:字节码执行引擎是如何执行字节码的 (6月27日不熟)

  字节码执行引擎执行java代码是有解释执行、编译执行两种方式,也有可能是两种结合。解释执行就是通过解释器执行字节码,编译执行,是将字节码通过即时编译器产生本地代码执行。
  在java虚拟机中每个线程中有许多的栈帧,一个栈帧的入栈到出栈过程就对应了第一个方法从调用开始到执行完成。栈帧中存储了方法的局部变量表,操作数栈,动态连接和方法返回地址等信息
  在执行引擎活动线程中,只有虚拟机栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),这个栈帧所关联的方法称为当前方法(Current Method)。执行引用所运行的所有字节码指令都只针对当前栈帧进行操作
  在Java程序编译为Class文件时,该方法需要分配的最大局部变量表的容量。当一个方法刚刚执行的时候,这个方法的操作数栈是空的,在方法执行的过程中,会有各种字节码指向操作数栈中写入和提取值,也就是入栈与出栈操作。在Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载的解析阶段转化为直接引用,这种转化称为静态解析。另外一部分将在每一次的运行期期间转化为直接引用,这部分称为动态连接
      

第三小问:你说说java的内存模型(***)

  首先先介绍一下为什么会出现java内存模型:计算机执行程序时会有CPU和缓存一致性问题,(当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。在多线程场景下就可能存在缓存一致性问题),除了缓存一致性问题,还有在硬件上为了使处理器内部的运算单元能够尽量的被充分利用,处理器可能会对输入代码进行乱序执行处理缓存一致性问题其实就是可见性问题。而处理器优化、指令重排即会导致有序性原子性问题。为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范,提供了一些措施来限制处理器优化和避免内存屏障出现的可见性问题
  Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行
  总之,Java内存模型(Java Memory Model ,JMM)JMM是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题

补充:Java中的volatile关键字提供了一个功能,那就是被其修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次是用之前都从主内存刷新。因此,可以使用volatile来保证多线程操作时变量的可见性。volatile关键字会禁止指令重排。synchronized关键字保证同一时刻只允许一条线程操作,可以使用synchronized和volatile来保证多线程之间操作的有序性。synchronized关键字看似确实是万能的,他可以同时满足以上三种特性,这其实也是很多人滥用synchronized的原因。但是synchronized是比较影响性能的,虽然编译器提供了很多锁优化技术,但是也不建议过度使用。

知识点3、线程有几种创建方式?(多线程并发方面 )

1、通过继承Thread类实现一个线程,并重写该类的run()方法,创建Thread子类的实例,也就是创建了线程对象,然后调用线程对象的start方法
2、定义Runnable接口的实现类,一样要重写run()方法,然后创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,new Thread(Runnable实现类对象)
3、创建Callable接口的实现类,并实现call()方法,然后创建Callable实现类的对象,使用该Callable示例创建FutureTask的对象,以FutureTask对象作为Thread的target创建Thread对象,获得线程对象。调用线程对象的start()方法启动线程,可以调用FutureTask对象的get()方法获得线程运行结果

import java.util

本文标签: 工程师基础Java