第四模块答案
反射
57. 什么是反射?
反射主要是指程序可以访问, 检测和修改它本身状态或行为的一种能力
Java 反射:
在 Java 运行时环境中, 对于任意一个类, 能否知道这个类有哪些属性和方法? 对于任意一个对象, 能否调用它的任意一个方法
Java 反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类.
在运行时构造任意一个类的对象.
在运行时判断任意一个类所具有的成员变量和方法.
在运行时调用任意一个对象的方法.
58. 什么是 java 序列化? 什么情况下需要序列化?
简单说就是为了保存在内存中的各种对象的状态(也就是实例变量, 不是方法), 并且可以把保存的对象状态再读出来. 虽然你可以用你自己的各种各样的方法来保存 object states, 但是 Java 给你提供一种应该比你自己好的保存对象状态的机制, 那就是序列化.
什么情况下需要序列化: 更多面试题获取, JAVA 高阶交流群: 851531810;
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过 RMI 传输对象的时候;
59. 动态代理是什么? 有哪些应用?
动态代理:
当想要给实现了某个接口的类中的方法, 加一些额外的处理. 比如说加日志, 加事务等. 可以给这个类创建一个代理, 故名思议就是创建一个新的类, 这个类不仅包含原来类方法的功能, 而且还在原来的基础上添加了额外处理的新类. 这个代理类并不是定义好的, 是动态生成的. 具有解耦意义, 灵活, 扩展性强.
动态代理的应用:
Spring 的 AOP
加事务
加权限
加日志
60. 怎么实现动态代理?
首先必须定义一个接口, 还要有一个 InvocationHandler(将实现接口的类的对象传递给它)处理类. 再有一个工具类 Proxy(习惯性将其称为代理类, 更多面试题获取, JAVA 高阶交流群: 851531810; 因为调用他的 newInstance()可以产生代理对象, 其实他只是一个产生代理对象的工具类). 利用到 InvocationHandler, 拼接代理类源码, 将其编译生成代理类的二进制码, 利用加载器加载, 并将其实例化产生代理对象, 最后返回.
第五模块答案
对象拷贝
更多面试题获取, JAVA 高阶交流群: 851531810;
61. 为什么要使用克隆?
想对一个对象进行处理, 又想保留原有的数据进行接下来的操作, 就需要克隆了, Java 语言中克隆针对的是类的实例.
62. 如何实现对象克隆?
有两种方式:
1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;
2). 实现 Serializable 接口, 通过对象的序列化和反序列化实现克隆, 可以实现真正的深度克隆, 代码如下:
importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;publicclassMyUtil{privateMyUtil(){thrownewAssertionError(); }@SuppressWarnings("unchecked")publicstaticTclone(T obj)throwsException{ByteArrayOutputStream bout =newByteArrayOutputStream();ObjectOutputStream oos =newObjectOutputStream(bout); oos.writeObject(obj);ByteArrayInputStream bin =newByteArrayInputStream(bout.toByteArray());ObjectInputStream ois =newObjectInputStream(bin);return(T) ois.readObject();// 说明: 调用 ByteArrayInputStream 或 ByteArrayOutputStream 对象的 close 方法没有任何意义 // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源, 这一点不同于对外部资源 (如文件流) 的释放 }}
下面是测试代码:
- importjava.io.Serializable;/*** 人类更多面试题获取, JAVA 高阶交流群: 851531810;*@authornnngu * */classPersonimplementsSerializable{
- privatestaticfinallongserialVersionUID = -9102017020286042305L;privateString name;// 姓名 privateintage;// 年龄 privateCar car;// 座驾 publicPerson(String name,intage, Car car){
- this.name = name;this.age = age;this.car = car;
- }publicStringgetName(){
- returnname;
- }publicvoidsetName(String name){
- this.name = name;
- }publicintgetAge(){
- returnage;
- }publicvoidsetAge(intage){
- this.age = age;
- }publicCargetCar(){
- returncar;
- }publicvoidsetCar(Car car){
- this.car = car;
- }@OverridepublicStringtoString(){
- return"Person [name="+ name +", age="+ age +", car="+ car +"]";
- }
- }
- /** * 小汽车类 *@authornnngu * */classCarimplementsSerializable{
- privatestaticfinallongserialVersionUID = -5713945027627603702L;privateString brand;// 品牌 privateintmaxSpeed;// 最高时速 publicCar(String brand,intmaxSpeed){
- this.brand = brand;this.maxSpeed = maxSpeed;
- }publicStringgetBrand(){
- returnbrand;
- }publicvoidsetBrand(String brand){
- this.brand = brand;
- }publicintgetMaxSpeed(){
- returnmaxSpeed;
- }publicvoidsetMaxSpeed(intmaxSpeed){
- this.maxSpeed = maxSpeed;
- }@OverridepublicStringtoString(){
- return"Car [brand="+ brand +", maxSpeed="+ maxSpeed +"]";
- }
- }
- classCloneTest{
- publicstaticvoidmain(String[] args){
- try{
- Person p1 =newPerson("郭靖",33,newCar("Benz",300));Person p2 = MyUtil.clone(p1);// 深度克隆 p2.getCar().setBrand("BYD");// 修改克隆的 Person 对象 p2 关联的汽车对象的品牌属性 // 原来的 Person 对象 p1 关联的汽车不会受到任何影响 // 因为在克隆 Person 对象时其关联的汽车对象也被克隆了 System.out.println(p1);
- }catch(Exception e) {
- e.printStackTrace();
- }
- }
- }
注意: 基于序列化和反序列化实现的克隆不仅仅是深度克隆, 更重要的是通过泛型限定, 可以检查出要克隆的对象是否支持序列化, 这项检查是编译器完成的, 不是在运行时抛出异常, 这种是方案明显优于使用 Object 类的 clone 方法克隆对象. 让问题在编译的时候暴露出来总是好过把问题留到运行时.
63. 深拷贝和浅拷贝区别是什么?
浅拷贝只是复制了对象的引用地址, 两个对象指向同一个内存地址, 所以修改其中任意的值, 另一个值都会随之变化, 这就是浅拷贝(例: assign())
深拷贝是将对象及值复制过来, 两个对象修改其中任意的值另一个值不会改变, 这就是深拷贝 (例: JSON.parse() 和 JSON.stringify(), 但是此方法无法复制函数类型)
更多面试题获取, JAVA 高阶交流群: 851531810;
(完)
来源: http://www.jianshu.com/p/43b387bcbb76