社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
pdf下载地址:Java面试宝典
2. 访问权限修饰符public、private、protected, 以及不写(默认)时的区别(2017-11-12) 22
1. Java有没有goto语句?(2017-11-12-wl) 26
2. & 和 && 的区别(2017-11-12-wl) 27
3. 在Java中,如何跳出当前的多重嵌套循环(2017-11-14-wl) 27
4. 两个对象值相同(x.equals(y) == true),但却可有不同的hashCode,这句话对不对?(2017-11-14-wl) 27
5. 是否可以继承String (2017-11-14-wl) 28
6. 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?(2017-11-14-wl) 29
7. 重载(overload)和重写(override)的区别?重载的方法能否根据返回类型进行区分?(2017-11-15-wl) 29
8. 为什么函数不能根据返回类型来区分重载?(2017-11-15-wl) 30
9. char 型变量中能不能存储一个中文汉字,为什么?(2017-11-16-wl) 31
10. 抽象类(abstract class)和接口(interface)有什么异同?(2017-11-16-wl) 31
11. 抽象的(abstract)方法是否可同时是静态的(static), 是否可同时是本地方法(native),是否可同时被synchronized(2017-11-16-wl) 32
12. 阐述静态变量和实例变量的区别?(2017-11-16-wl) 32
13. ==和equals的区别?(2017-11-22-wzz) 33
14. break和continue的区别?(2017-11-23-wzz) 33
15. String s = "Hello";s = s + " world!";这两行代码执行后,原始的String对象中的内容到底变了没有?(2017-12-1-lyq) 33
3. error和exception的区别?(2017-2-23) 36
5. 请写出你最常见的5个RuntimeException(2017-11-22-wzz) 37
6. throw和throws的区别(2017-11-22-wzz) 38
7. final、finally、finalize的区别?(2017-11-23-wzz) 38
1. Math.round(11.5)等于多少?Math.round(- 11.5) 又等于多少?(2017-11-14-wl) 39
2. switch是否能作用在byte上,是否能作用在long上,是否能作用在String上?(2017-11-14-wl) 39
3. 数组有没有length() 方法?String有没有length() 方法?(2017-11-14-wl) 39
4. String 、StringBuilder 、StringBuffer的区别?(2017-11-14-wl) 39
5. 什么情况下用“+”运算符进行字符串连接比调用StringBuffer/StringBuilder 对象的append方法连接字符串性能更好?(2017-11-14-wl) 40
6. 请说出下面程序的输出(2017-11-14-wl) 47
7. Java中的日期和时间(2017-11-19-wl) 48
2. String是基本数据类型吗?(2017-11-12-wl) 71
3. short s1 = 1; s1 = s1 + 1; 有错吗?short s1 = 1; s1 += 1有错吗;(2017-11-12-wl) 71
4. int 和 和 Integer有什么区别?(2017-11-12-wl) 71
5. 下面Integer类型的数值比较输出的结果为?(2017-11-12-wl) 72
6. String类常用方法(2017-11-15-lyq) 74
7. String、StringBuffer、StringBuilder的区别?(2017-11-23-wzz) 74
8. 数据类型之间的转换(2017-11-23-wzz) 75
1. Java中有几种类型的流(2017-11-23-wzz) 75
4. 字节流和字符流的区别(2017-11-23-wzz) 77
5. 如何实现对象克隆?(2017-11-12-wl) 77
6. 什么是java序列化,如何实现java序列化?(2017-12-7-lyq) 80
1. HashMap排序题,上机题。(本人主要靠这道题入职的第一家公司) 81
3. ArrayList内部用什么实现的?(2015-11-24) 83
4. 并发集合和普通集合如何区别?(2015-11-24) 89
6. List和Map、Set的区别(2017-11-22-wzz) 91
7. HashMap 和HashTable有什么区别?(2017-2-23) 92
8. 数组和链表分别比较适合用于什么场景,为什么?(2017-2-23) 93
9. Java中ArrayList和Linkedlist区别?(2017-2-23) 96
10. List a=new ArrayList()和ArrayList a =new ArrayList()的区别?(2017-2-24) 97
11. 要对集合更新操作时,ArrayList和LinkedList哪个更适合?(2017-2-24) 97
12. 请用两个队列模拟堆栈结构(2017-2-24) 101
13. Collection和Map的集成体系(2017-11-14-lyq) 102
14. Map中的key和value可以为null么?(2017-11-21-gxb) 103
(一)多线程基础知识--传统线程机制的回顾(2017-12-11-wl) 104
(二)多线程基础知识--线程并发库(2017-12-11-wl) 118
1. 静态嵌套类(Static Nested Class) 和内部类(Inner Class)的不同?(2017-11-16-wl) 272
2. 下面的代码哪些地方会产生编译错误?(2017-11-16-wl) 272
1. 写一个ArrayList的动态代理类(笔试题) 273
2. 动静态代理的区别,什么场景使用?(2015-11-25) 274
12. heap和stack有什么区别(2017-2-23) 294
13. 解释内存中的栈 (stack) 、堆 (heap) 和方法区 (method area) 的用法(2017-11-12-wl) 301
3. Java类加载体系之ClassLoader双亲委托机制 (2017-2-24) 302
4. 描述一下JVM加载class (2017-11-15-wl) 306
5. 获得一个类对象有哪些方式?(2017-11-23-wzz) 307
1. 既然有GC机制,为什么还会有内存泄露的情况(2017-11-16-wl) 307
1. Java中为什么会有GC机制呢?(2017-11-16-wl) 309
2. 对于Java的GC哪些内存需要回收(2017-11-16-wl) 309
3. Java的GC什么时候回收垃圾(2017-11-16-wl) 309
七、Java8的新特性以及使用(2017-12-02-wl) 311
1. 通过10个示例来初步认识Java8中的lambda表达式(2017-12-02-wl) 311
2. Java8中的lambda表达式要点(2017-12-02-wl) 319
3. Java8中的Optional类的解析(2017-12-02-wl) 321
八、在开发中遇到过内存溢出么?原因有哪些?解决方法有哪些?(2017-11-23-gxb) 328
1. 说下原生jdbc操作数据库流程?(2017-11-25-wzz) 329
2. 什么要使用PreparedStatement?(2017-11-25-wzz) 330
3. 关系数据库中连接池的机制是什么?(2017-12-6-lyq) 330
1. http的长连接和短连接(2017-11-14-lyq) 331
2. HTTP/1.1与HTTP/1.0的区别(2017-11-21-wzy) 332
3. http常见的状态码有哪些?(2017-11-23-wzz) 335
4. GET和POST的区别?(2017-11-23-wzz) 335
5. http中重定向和请求转发的区别?(2017-11-23-wzz) 337
1. Cookie和Session的区别(2017-11-15-lyq) 337
2. session共享怎么做的(分布式如何实现session共享)? 337
3. 在单点登录中,如果cookie被禁用了怎么办?(2017-11-23-gxb) 340
1. 什么是jsp,什么是Servlet?jsp和Servlet有什么区别?(2017-11-23-wzz) 341
2. jsp有哪些域对象和内置对象及他们的作用?(2017-11-25-wzz) 342
1. 什么是xml,使用xml的优缺点,xml的解析器有哪几种,分别有什么区别?(2017-11-25-wzz) 343
1. 谈谈你对ajax的认识?(2017-11-23-wzz) 344
2. jsonp原理(2017-11-21-gxb) 345
2. Linux中如何查看日志?(2017-11-21-gxb) 347
3. Linux怎么关闭进程(2017-11-21-gxb) 348
1. jQueryUI(2017-11-23-lyq) 352
3. AngularJS (2017-11-23-lyq) 355
1. SQL的select语句完整的执行顺序(2017-11-15-lyq) 359
2. SQL之聚合函数(2017-11-15-lyq) 361
3. SQL之连接查询(左连接和右连接的区别)(2017-11-15-lyq) 361
4. SQL之sql注入(2017-11-15-lyq) 362
5. Mysql性能优化(2017-11-15-lyq) 362
6. 必看sql面试题(学生表_课程表_成绩表_教师表)(2017-11-25-wzz) 363
7. Mysql数据库架构图(2017-11-25-wzz) 364
8. Mysql架构器中各个模块都是什么?(2017-11-25-wzz) 365
9. Mysql存储引擎有哪些?(2017-11-25-wzz) 366
10. MySQL事务介绍(2017-11-25-wzz) 367
11. MySQL怎么创建存储过程(2017-11-25-wzz) 369
12. MySQL触发器怎么写?(2017-11-25-wzz) 370
13. MySQL语句优化(2017-11-26-wzz) 371
14. MySQL中文乱码问题完美解决方案(2017-12-07-lwl) 372
15. 如何提高MySQL的安全性(2017-12-8-lwl) 374
1. 什么是存储过程,使用存储过程的好处?(2017-11-25-wzz) 376
2. Oracle存储过程怎么创建?(2017-11-25-wzz) 377
3. 如何使用Oracle的游标?(2017-11-25-wzz) 378
4. Oracle中字符串用什么连接?(2017-11-25-wzz) 378
5. Oracle中是如何进行分页查询的?(2017-11-25-wzz) 379
6. 存储过程和存储函数的特点和区别?(2017-11-25-wzz) 379
7. 存储过程与SQL的对比?(2017-11-21-gxb) 379
8. 你觉得存储过程和SQL语句该使用哪个?(2017-11-21-gxb) 380
9. 触发器的作用有哪些?(2017-11-21-gxb) 381
10. 在千万级的数据库查询中,如何提高效率?(2017-11-23-gxb) 381
1. SpringMVC的工作原理(2017-11-13-lyq) 385
2. SpringMVC常用注解都有哪些?(2017-11-24-gxb) 386
3. 如何开启注解处理器和适配器?(2017-11-24-gxb) 386
4. 如何解决get和post乱码问题?(2017-11-24-gxb) 386
1. 谈谈你对Spring的理解(2017-11-13-lyq) 387
2. Spring中的设计模式(2017-11-13-lyq) 387
3. Spring的常用注解(2017-11-13-lyq) 388
4. 简单介绍一下Spring bean的生命周期(2017-11-21-gxb) 389
5. Spring结构图(2017-11-22-lyq) 390
6. Spring能帮我们做什么?(2017-11-22-lyq) 392
7. 请描述一下Spring的事务(2017-11-22-lyq) 393
8. BeanFactory 常用的实现类有哪些?(2017-12-03-gxb) 396
9. 解释Spring JDBC、Spring DAO和Spring ORM(2017-12-03-gxb) 397
10. 简单介绍一下Spring WEB 模块。(2017-12-03-gxb) 397
11. Spring配置文件有什么作用?(2017-12-03-gxb) 398
12. 什么是Spring IOC 容器?(2017-12-03-gxb) 398
14. ApplicationContext的实现类有哪些?(2017-12-03-gxb) 398
15. BeanFactory与AppliacationContext有什么区别(2017-12-03-gxb) 399
16. 什么是Spring的依赖注入?(2017-12-04-gxb) 399
17. 有哪些不同类型的IOC(依赖注入)方式?(2017-12-04-gxb) 399
18. 什么是Spring beans?(2017-12-04-gxb) 400
19. 一个Spring Beans的定义需要包含什么?(2017-12-04-gxb) 400
20. 你怎样定义类的作用域?(2017-12-04-gxb) 401
21. Spring支持的几种bean的作用域。(2017-12-04-gxb) 401
22. Spring框架中的单例bean是线程安全的吗?(2017-12-04-gxb) 401
23. 什么是Spring的内部bean?(2017-12-04-gxb) 401
24. 在Spring中如何注入一个java集合?(2017-12-04-gxb) 402
25. 什么是bean的自动装配?(2017-12-04-gxb) 402
26. 解释不同方式的自动装配。(2017-12-04-gxb) 402
27. 什么是基于Java的Spring注解配置? 给一些注解的例子(2017-12-05-gxb) 403
28. 什么是基于注解的容器配置?(2017-12-05-gxb) 403
29. 怎样开启注解装配?(2017-12-05-gxb) 403
30. 在Spring框架中如何更有效地使用JDBC?(2017-12-05-gxb) 403
31. 使用Spring通过什么方式访问Hibernate?(2017-12-05-gxb) 404
32. Spring支持的ORM框架有哪些?(2017-12-05-gxb) 404
33. 简单解释一下spring的AOP(2017-12-05-gxb) 404
34. 在Spring AOP 中,关注点和横切关注的区别是什么?(2017-12-05-gxb) 405
35. 什么是连接点?(2017-12-05-gxb) 405
36. Spring的通知是什么?有哪几种类型?(2017-12-05-gxb) 405
37. 什么是切点?(2017-12-05-gxb) 406
38. 什么是目标对象?(2017-12-05-gxb) 406
39. 什么是代理?(2017-12-05-gxb) 406
40. 什么是织入?什么是织入应用的不同点?(2017-12-05-gxb) 406
1. 简单介绍一下Shiro框架(2017-11-23-gxb) 406
2. Shiro主要的四个组件(2017-12-2-wzz) 407
3. Shiro运行原理(2017-12-2-wzz) 408
4. Shiro的四种权限控制方式(2017-12-2-wzz) 408
1. Mybatis中#和$的区别?(2017-11-23-gxb) 410
2. Mybatis的编程步骤是什么样的?(2017-12-2-wzz) 411
3. JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?(2017-12-2-wzz) 411
4. 使用MyBatis的mapper接口调用时有哪些要求?(2017-12-2-wzz) 411
5. Mybatis中一级缓存与二级缓存?(2017-12-4-lyq) 412
6. MyBatis在insert插入操作时返回主键ID(2017-12-4-lyq) 412
1. 简单介绍一下Struts2(2017-11-24-gxb) 413
2. Struts2的执行流程了解么?(2017-11-24-gxb) 414
3. Struts2中Action配置的注意事项有哪些?(2017-11-24-gxb) 416
4. 拦截器和过滤器有哪些区别?(2017-11-24-gxb) 417
5. Struts2的封装方式有哪些?(2017-11-24-gxb) 417
6. 简单介绍一下Struts2的值栈。(2017-11-24-gxb) 419
7. SpringMVC和Struts2的区别?(2017-11-23-gxb) 420
8. Struts2中的 # 和 % 分别是做什么的?(2017-11-30-wzz) 421
9. Struts2中有哪些常用结果类型?(2017-12-1-lyq) 422
1. 简述一下hibernate的开发流程(2017-11-24-gxb) 422
2. hibernate中对象的三种状态(2017-11-24-gxb) 423
3. hibernate的缓存机制。(2017-11-24-gxb) 423
4. Hibernate的查询方式有哪些?(2017-11-24-gxb) 424
5. Hibernate和Mybatis的区别?(2017-11-23-gxb) 424
6. Hibernate和JDBC优缺点对比(2017-11-29-wzz) 425
7. 关于Hibernate的orm思想你了解多少?(2017-11-29-wzz) 426
8. get和load的区别?(2017-11-30-wzz) 426
9. 如何进行Hibernate的优化?(2017-11-30-wzz) 427
10. 什么是Hibernate 延迟加载?(2017-12-1-lyq) 428
11. No Session问题原理及解决方法?(2017-12-4-lyq) 428
12. Spring的两种代理JDK和CGLIB的区别浅谈(2017-12-4-lyq) 429
13. 叙述Session的缓存的作用(2017-12-9-lwl) 430
14. Session的清理和清空有什么区别?(2017-12-10-lwl) 430
15. 请简述Session的特点有哪些?(2017-12-10-lwl) 430
16. 比较Hibernate三种检索策略的优缺点(2017-12-10-lwl) 431
1. 什么是Quartz 框架(2017-12-2-wzz) 432
2.配置文件 applicationContext_job.xml各个属性作用(2017-12-2-wzz) 432
3.Cron表达式详解(2017-12-2-wzz) 432
4. 如何监控 Quartz 的 job 执行状态:运行中,暂停中,等待中? (2017-12-2-wzz) 433
1. Redis的特点?(2017-11-25-wzz) 433
2. 为什么redis需要把所有数据放到内存中?(2017-11-25-wzz) 434
3. Redis常见的性能问题都有哪些?如何解决?(2017-11-25-wzz) 434
4. Redis最适合的场景有哪些?(2017-11-25-wzz) 435
5. Memcache与Redis的区别都有哪些?(2017-11-25-wzz) 435
6. Redis用过RedisNX吗?Redis有哪几种数据结构?(2017-11-14-lyq) 435
7. Redis的优缺点(2017-11-22-lyq) 436
8. Redis的持久化(2017-11-23-lyq) 437
1. 如何使用ActiveMQ解决分布式事务?(2017-11-21-gxb) 439
2. 了解哪些消息队列?(2017-11-24-gxb) 440
3. ActiveMQ如果消息发送失败怎么办?(2017-11-24-gxb) 442
1. Dubbo的容错机制有哪些。(2017-11-23-gxb) 443
2. 使用dubbo遇到过哪些问题?(2017-11-23-gxb) 444
3. Dubbo的连接方式有哪些?(2017-12-1-lyq) 445
1. 如何测试并发量?(2017-11-23-gxb) 448
1. Nginx反向代理为什么能够提升服务器性能?(2017-11-24-gxb) 448
2. Nginx 和 Apache 各有什么优缺点? (2017-11-24-gxb) 449
3. Nginx 多进程模型是如何实现高并发的?(2017-12-5-lyq) 449
1. 简单介绍一下zookeeper以及zookeeper的原理。(2017-11-24-gxb) 450
1. 简单介绍一下solr(2017-11-24-gxb) 451
2. solr怎么设置搜索结果排名靠前?(2017-11-24-gxb) 452
3. solr中IK分词器原理是什么?(2017-11-24-gxb) 452
1. 什么是webService?(2017-11-24-lyq) 452
2. 常见的远程调用技术(2017-11-24-lyq) 452
1. 谈谈你对restful的理解以及在项目中的使用?(2017-11-30-wzz) 453
三、腾讯(2016年校招面试题2017-11-29-wzy) 464
四、北京宝蓝德股份科技有限公司(2017-12-03-wmm) 477
1. 什么叫对象?什么叫类?什么面向对象(OOP)? 551
2. 相对于JDK1.4,JDK1.5 有哪些新特性? 552
3. JAVA中使用final修饰符,对程序有哪些影响? 552
4. Java环境变量Unix/Linux下如何配置? 553
5. 写出5个你在JAVA开发中常用的包含(全名),并简述其作用。 554
6. 写出5个常见的运行时异常(RuntimeException)。 555
7. 方法重载(overload)需要满足什么条件,方法覆盖/方法重写(override)需要满足什么条件?(二选一) 555
8. 继承(inheritance)的优缺点是什么? 556
12. 什么叫对象持久化(OBJect PERSIstence),为什么要进行对象持久化? 558
15. 什么叫脏数据,什么叫脏读(Dirty Read) 561
[if !supportLists]第一章 [endif]内容介绍
该宝典是一份知识点全面又能不断更新,与时俱进的学习手册,不仅收录了作者亲身面试遇到的问题,还收录了近上万名黑马学子面试时遇到的问题。我们会一直不断地更新和充实该宝典,同时也希望读者朋友能够多多提供优质的面试题,也许下一个版本就有你提供的面试题哦。
本人的面试实战记录发布在黑马论坛:http://bbs.itheima.com/thread-196394-1-1.html
大家可以访问上面的网址,通过阳哥的实战记录略微感知一下真实面试的情况,从中学习一些面试技巧以便让自己在未来的面试中能够得心应手,顺利拿到自己喜欢的offer。
注意:该面试宝典仅供参考,由于作者本人的知识水平有限加之编写时间仓促因此难免有bug的存在,希望大家见谅。
该宝典的一个明确目标是能够让90%以上的Java技术面试题都落到该宝典中,如果您有不错的知识或者面试题,您可以发送到wangzhenyang@itcast.cn,本人将不胜感激。让天下没有难学的知识,希望你我的努力能帮到更多的莘莘学子。
世间事,很多都可投机取巧,但技术却必须靠日积月累的努力来提高。本宝典更加注重的是知识的掌握,而不仅仅是对面试题的应付。在展示常见的面试问题以及回答技巧的同时还详细讲解了每一道题所包含的知识点,让读者不仅知其然,更知其所以然。
[if !supportLists]第二章 [endif]JavaSE基础
[if !supportLists]一、[endif]Java面向对象
[if !supportLists]1. [endif]面向对象都有哪些特性以及你对这些特性的理解
1)继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。
2)封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
3)多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
4)抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
注意:默认情况下面向对象有3大特性,封装、继承、多态,如果面试官问让说出4大特性,那么我们就把抽象加上去。
[if !supportLists]2. [endif]访问权限修饰符public、private、protected, 以及不写(默认)时的区别(2017-11-12)
该题目比较简单,不同的权限修饰符的区别见下表。
修饰符当前类同 包子 类其他包
public √√√√
protected√√√×
default√√××
private√×××
[if !supportLists]3. [endif]如何理解clone对象
3.1为什么要用clone?
在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B 任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。
3.2 new一个对象的过程和clone一个对象的过程区别
new操作符的本意是分配内存。程序执行到new操作符时,首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
clone在第一步是和new相似的,都是分配内存,调用clone方法时,分配的内存和原对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。
3.3 clone对象的使用
3.3.1复制对象和复制引用的区别
[if !supportLists]1. [endif]Person p = new Person(23, "zhang");
[if !supportLists]2. [endif]Person p1 = p;
[if !supportLists]3. [endif]System.out.println(p);
[if !supportLists]4. [endif]System.out.println(p1);
当Person p1 = p;执行之后, 是创建了一个新的对象吗? 首先看打印结果:
[if !supportLists]1.[endif]com.itheima.Person@2f9ee1ac
[if !supportLists]2.[endif]com.itheima.Person@2f9ee1ac
可以看出,打印的地址值是相同的,既然地址都是相同的,那么肯定是同一个对象。p和p1只是引用而已,他们都指向了一个相同的对象Person(23, “zhang”) 。 可以把这种现象叫做引用的复制。上面代码执行完成之后, 内存中的情景如下图所示:
而下面的代码是真真正正的克隆了一个对象。
[if !supportLists]1.[endif]Person p = new Person(23, "zhang");
[if !supportLists]2.[endif]Person p1 = (Person) p.clone();
[if !supportLists]3.[endif]System.out.println(p);
[if !supportLists]4.[endif]System.out.println(p1);
从打印结果可以看出,两个对象的地址是不同的,也就是说创建了新的对象,而不是把原对象的地址赋给了一个新的引用变量:
[if !supportLists]1. [endif]com.itheima.Person@2f9ee1ac
[if !supportLists]2. [endif]com.itheima.Person@67f1fba0
以上代码执行完成后,内存中的情景如下图所示:
3.3.2 深拷贝和浅拷贝
上面的示例代码中,Person中有两个成员变量,分别是name和age, name是String类型, age是int类型。代码非常简单,如下所示:
[if !supportLists]1.[endif]public class Person implements Cloneable{
[if !supportLists]2.[endif]privatint age ;
[if !supportLists]3.[endif] private String name;
[if !supportLists]4.[endif] public Person(int age, String name) {
[if !supportLists]5.[endif] this.age = age;
[if !supportLists]6.[endif] this.name = name;
[if !supportLists]7.[endif] }
[if !supportLists]8.[endif] public Person() {}
[if !supportLists]9.[endif] public int getAge() {
[if !supportLists]10.[endif] return age;
[if !supportLists]11.[endif] }
[if !supportLists]12.[endif] public String getName() {
[if !supportLists]13.[endif] return name;
[if !supportLists]14.[endif] }
[if !supportLists]15.[endif] @Override
[if !supportLists]16.[endif] protected Object clone() throws CloneNotSupportedException {
[if !supportLists]17.[endif] return (Person)super.clone();
[if !supportLists]18.[endif] }
[if !supportLists]19.[endif]}
由于age是基本数据类型, 那么对它的拷贝没有什么疑议,直接将一个4字节的整数值拷贝过来就行。但是name是String类型的, 它只是一个引用, 指向一个真正的String对象,那么对它的拷贝有两种方式: 直接将原对象中的name的引用值拷贝给新对象的name字段, 或者是根据原Person对象中的name指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的Person对象的name字段。这两种拷贝方式分别叫做浅拷贝和深拷贝。深拷贝和浅拷贝的原理如下图所示:
下面通过代码进行验证。如果两个Person对象的name的地址值相同, 说明两个对象的name都指向同一个String对象,也就是浅拷贝, 而如果两个对象的name的地址值不同, 那么就说明指向不同的String对象, 也就是在拷贝Person对象的时候, 同时拷贝了name引用的String对象, 也就是深拷贝。验证代码如下:
[if !supportLists]1. [endif]Person p = new Person(23, "zhang");
[if !supportLists]2. [endif]Person p1 = (Person) p.clone();
[if !supportLists]3. [endif]String result = p.getName() == p1.getName()
[if !supportLists]4. [endif]? "clone是浅拷贝的" : "clone是深拷贝的";
[if !supportLists]5. [endif]System.out.println(result);
打印结果为:
[if !supportLists]6. [endif]clone是浅拷贝的
所以,clone方法执行的是浅拷贝, 在编写程序时要注意这个细节。
如何进行深拷贝:
由上一节的内容可以得出如下结论:如果想要深拷贝一个对象,这个对象必须要实现Cloneable接口,实现clone方法,并且在clone方法内部,把该对象引用的其他对象也要clone一份,这就要求这个被引用的对象必须也要实现Cloneable接口并且实现clone方法。那么,按照上面的结论,实现以下代码 Body类组合了Head类,要想深拷贝Body类,必须在Body类的clone方法中将Head类也要拷贝一份。代码如下:
[if !supportLists]1.[endif]static class Body implements Cloneable{
[if !supportLists]2.[endif] public Head head;
[if !supportLists]3.[endif] public Body() {}
[if !supportLists]4.[endif] public Body(Head head) {this.head = head;}
[if !supportLists]5.[endif] @Override
[if !supportLists]6.[endif] protected Object clone() throws CloneNotSupportedException {
[if !supportLists]7.[endif] Body newBody = (Body) super.clone();
[if !supportLists]8.[endif] newBody.head = (Head) head.clone();
[if !supportLists]9.[endif] return newBody;
[if !supportLists]10.[endif] }
[if !supportLists]11.[endif]}
[if !supportLists]12.[endif]static class Head implements Cloneable{
[if !supportLists]13.[endif] public Face face;
[if !supportLists]14.[endif] public Head() {}
[if !supportLists]15.[endif] @Override
[if !supportLists]16.[endif] protected Object clone() throws CloneNotSupportedException {
[if !supportLists]17.[endif] return super.clone();
[if !supportLists]18.[endif] } }
[if !supportLists]19.[endif]public static void main(String[] args) throws CloneNotSupportedException {
[if !supportLists]20.[endif] Body body = new Body(new Head(new Face()));
[if !supportLists]21.[endif] Body body1 = (Body) body.clone();
[if !supportLists]22.[endif] System.out.println("body == body1 : " + (body == body1) );
[if !supportLists]23.[endif] System.out.println("body.head == body1.head : " + (body.head == body1.head));
[if !supportLists]24.[endif]}
打印结果为:
[if !supportLists]1. [endif]body == body1 : false
[if !supportLists]2. [endif]body.head == body1.head : false
[if !supportLists]二、[endif]JavaSE语法(2017-11-12-wl)
[if !supportLists]1. [endif]Java有没有goto语句?(2017-11-12-wl)
goto是Java 中的保留字,在目前版本的Java中没有使用。根据 James Gosling(Java 之父)编写的《The Java Programming Language》一书的附录中给出了一个 Java 关键字列表,其中有 goto 和 const,但是这两个是目前无法使用的关键字,因此有些地方将其称之为保留字,其实保留字这个词应该有更广泛的意义,因为熟悉 C 语言的程序员都知道,在系统类库中使用过的有特殊意义的单词或单词的组合都被视为保留字。
[if !supportLists]2. [endif]& 和 && 的区别(2017-11-12-wl)
&运算符有两种用法:(1)按位与;(2)逻辑与。
&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是 true 整个表达式的值才是 true。
&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是 null 而且不是空字符串,应当写为username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的 equals 比较,否则会产生 NullPointerException 异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
[if !supportLists]3. [endif]在Java中,如何跳出当前的多重嵌套循环(2017-11-14-wl)
在最外层循环前加一个标记如A,然后用 break A;可以跳出多重循环。(Java 中支持带标签的break和continue 语句,作用有点类似于 C 和 C++中的 goto 语句,但是就像要避免使用 goto 一样,应该避免使用带标签的 break 和 continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用)。
[if !supportLists]4. [endif]两个对象值相同(x.equals(y) == true),但却可有不同的hashCode,这句话对不对?(2017-11-14-wl)
不对,如果两个对象x 和 y 满足 x.equals(y) == true,它们的哈希码(hashCode)应当相同。
Java 对于eqauls 方法和 hashCode 方法是这样规定的:(1)如果两个对象相同(equals 方法返回 true),那么它们的hashCode 值一定要相同;(2)如果两个对象的 hashCode 相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在 Set 集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。
关于equals 和 hashCode方法,很多Java程序员都知道,但很多人也就是仅仅知道而已,在Joshua Bloch
的大作《Effective Java》(很多软件公司,《Effective Java》、《Java 编程思想》以及《重构:改善既有代码质量》是 Java 程序员必看书籍,如果你还没看过,那就赶紧去买一本吧)中是这样介绍 equals 方法的。
首先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
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!