java面试(反射)05

Wesley13
• 阅读 734

1.什么是反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取类信息以及动态调用对象内容就称为java语言的反射机制

2.反射的作用

  • 在运行时判断任意一个对象所属的类;

  • 在运行时构造任意一个类的对象;

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

3.反射的实现

 我们知道,要使用一个类,就要先把它加载到虚拟机中,生成一个Class对象。这个class对象就保存了这个类的一切信息。

    反射机制的实现,就是获取这个Class对象,通过Class对象去访问类、对象的元数据以及运行时的数据。

    有三种方法获得类的Class对象:****Class.forName(String className)、className.class、实例对象.getClass();

4.什么是 Java 序列化?什么情况下需要序列化?

Java 序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。

以下情况需要使用 Java 序列化:

  • 想把的内存中的对象状态保存到一个文件中或者数据库中时候;
  • 想用套接字在网络上传送对象的时候;
  • 想通过RMI(远程方法调用)传输对象的时候。

5.动态代理是什么?有哪些应用?

动态代理是运行时动态生成代理类。

动态代理的应用有 spring aop、hibernate 数据查询、测试框架的后端 mock、rpc,Java注解对象获取等。

6.怎么实现动态代理?

JDK 原生动态代理和 cglib 动态代理。JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。

7.为什么要使用克隆对象?

在java中,我们使用对象的时候直接去new一个对象就好了,为什么还要克隆对象呢?

       当我们new一个对象之后是要对该对象进行初始化的,不然这个对象是空的没有内容。而使用克隆,则会得到一个原对象以及原对象里面包含的内容。例如,你有一个User对象,里面的包含了相关的属性。此时你想要修改里面的某一属性,但又不想破坏原对象里面的数据,此时就可以克隆User这个对象,然后在克隆的这个User对象上进行修改操作。除此,如果你在操作完之后判断一下属性是否更改成功,则使用克隆的对象和原对象做一下对比即可。

8.如何克隆一个对象?

8.1浅复制

浅克隆就是把原对象中的一些属性值克隆过来。使用clone()方法进行浅克隆。但注意:必须要在被克隆类上实现Cloneable接口,并重写clone方法。若不没有实现该接口,则会抛出CloneNotSupportedException异常!

package interview;

public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        User user = new User();
        user.setName("张三");
        user.setAge(18);
        System.out.println("原对象(user)的属性值:");
        System.out.println("姓名为:" + user.getName() + ",年龄为:" + user.getAge()+"\n");

        // 对user对象进行克隆
        User user1 = (User) user.clone();
        // 查看一下克隆对象中的属性值
        System.out.println("克隆后user1对象中的属性值:");
        System.out.println("姓名为:" + user1.getName() + ",年龄为:" + user1.getAge()+"\n"); // 结果和原对象中属性值相同

        // 对user1对象进行修改
        user1.setName("李四");
        // 查看修改后的结果
        System.out.println("user1对象进行修改后的属性值:");
        System.out.println("姓名为:" + user1.getName() + ",年龄为:" + user1.getAge()+"\n"); 
        
        System.out.println("user1对象进行修改后user对象的属性值:");
        System.out.println("姓名为:" + user.getName() + ",年龄为:" + user.getAge()+"\n"); 
    }

}

class User implements Cloneable {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }
}

java面试(反射)05

从结果上可以看出,克隆对象user1和原对象user在修改属性数据时,两个对象之间的数据互不受影响。

       那么如果后期需要调整代码,需要在原有的user对象中添加一个引用类型Address字段,那么克隆的user1对象会能受到影响吗?能和原对象user中的数据一致吗?

看下面代码演示,在原有基础代码上加入一个Address的类,并分别在User类和Address类中加入重写Object的方法。注意:User类中的引用address字段的权限修饰符为public,否则无法运行!

package interview;

public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        // 创建原对象,并为原对象中的属性进行赋值,然后打印出结果
        Address address = new Address("中国", "山东");
        User user = new User("张三", 18, address);
        System.out.println("原对象(user)的属性值:");
        System.out.println("姓名为:" + user.getName() + ",年龄为:" + user.getAge() + ",地址为:" + user.getAddress() + "\n");

        // 对user对象进行克隆
        User user1 = (User) user.clone();
        // 查看一下克隆对象中的属性值
        System.out.println("克隆后user1对象中的属性值:");
        System.out.println("姓名为:" + user1.getName() + ",年龄为:" + user1.getAge() + ",地址为:" + user1.getAddress() + "\n");
        
         // 对user1对象进行修改
         user1.setName("李四");
         user1.getAddress().setCity("北京");
         // 查看修改后的结果
         System.out.println("user1对象进行修改后的属性值:");
         System.out.println("姓名为:" + user1.getName() + ",年龄为:" + user1.getAge() +",地址为:" + user1.getAddress() + "\n");
        
         System.out.println("user1对象进行修改后user对象的属性值:");
         System.out.println("姓名为:" + user.getName() + ",年龄为:" + user.getAge() + ",地址为:" + user.getAddress() + "\n");
    }

}

class User implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public User(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }
}

// 定义一个address类
class Address {
    private String country;
    private String city;

    public Address(String country, String city) {
        this.country = country;
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address [country=" + country + ", city=" + city + "]";
    }

}

java面试(反射)05

从结果上看,user1在克隆完后修改了姓名和地址值,修改后和原对象对比,发现姓名和地址的确发生了改变。但再次查看原对象的结果时,发现原对象的姓名值虽没变,但地址值却随着user1对象的改变而改变了!这样的话反而失去了克隆的意义。那么为什么会出现这种情况呢?因为浅克隆只是克隆原对象中的引用类型指向,并非克隆了原对象中的全部数据。

3.2 深克隆

深克隆和浅克隆的区别在于:浅克隆只克隆了原对象的引用类型的指向。深克隆则是克隆了原对象的所有。也就是说像上面案例所示,如果使两个对象之间互不影响,则使用深克隆。

深克隆的使用:在引用类型所在的类使其实现Cloneable接口,并使用public修饰符重写Clone()方法。

package interview;

public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        // 创建原对象,并为原对象中的属性进行赋值,然后打印出结果
        Address address = new Address("中国", "山东");
        User user = new User("张三", 18, address);
        System.out.println("原对象(user)的属性值:");
        System.out.println("姓名为:" + user.getName() + ",年龄为:" + user.getAge() + ",地址为:" + user.getAddress() + "\n");

        // 对user对象进行克隆
        User user1 = (User) user.clone();
        // 查看一下克隆对象中的属性值
        System.out.println("克隆后user1对象中的属性值:");
        System.out.println("姓名为:" + user1.getName() + ",年龄为:" + user1.getAge() + ",地址为:" + user1.getAddress() + "\n");

        // 对user1对象进行修改
        user1.setName("李四");
        user1.getAddress().setCity("北京");
        // 查看修改后的结果
        System.out.println("user1对象进行修改后的属性值:");
        System.out.println("姓名为:" + user1.getName() + ",年龄为:" + user1.getAge() + ",地址为:" + user1.getAddress() + "\n");

        System.out.println("user1对象进行修改后user对象的属性值:");
        System.out.println("姓名为:" + user.getName() + ",年龄为:" + user.getAge() + ",地址为:" + user.getAddress() + "\n");
    }

}

class User implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public User(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        // 这一步返回的这个user对象还只是一个浅克隆,
        User user = (User) super.clone();
        // 然后克隆的过程中获得这个克隆的user,然后调用这个getAddress()这个方方法得到这个Addrress对象。然后实现克隆。在设置到这个user中的Address。
        // 这样实现了双层克隆使得那个Address对象也得到了复制。
        user.setAddress((Address) user.getAddress().clone());
        return user;
    }
}

// 定义一个address类
class Address implements Cloneable {
    private String country;
    private String city;

    public Address(String country, String city) {
        this.country = country;
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address [country=" + country + ", city=" + city + "]";
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }

}

java面试(反射)05

9.如何实现对象克隆?

  • 实现 Cloneable 接口并重写 Object 类中的 clone() 方法。
  • 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
点赞
收藏
评论区
推荐文章
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java中 什么是反射?
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言(https://www.oschina.net/act
浪人 浪人
3年前
Java基础与提高干货系列——Java反射机制
前言今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来。那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现。正文Java反射机制定义Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以
Wesley13 Wesley13
3年前
java中的反射和代理
  Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制。java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的耦合性。这些都是java的基础知识,要想成为一名合格的程序猿,必须掌握!Java反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知
lzy lzy
3年前
RPC框架手撕之路---java反射以及动态代理机制
在上一篇文章中,我们提到了,RPC框架所需要的java基础,第一点就是java的动态代理机制,动态代理机制的基础是反射,无论是在实际编程或者是面试时,都是java知识的重中之重。java反射:定义:在运行状态中,对于任意一个类,都能够知道这一个类的所有属性和方法,对于任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息以及动态调用类方法
御弟哥哥 御弟哥哥
3年前
Java基础与提高干货系列 -- Java反射机制
前言今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来。那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现。正文Java反射机制定义Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性
桃浪十七丶 桃浪十七丶
3年前
工厂模式实例(顺便回忆反射机制的应用)
一、原理反射机制的原理JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。工厂模式自述所谓工厂模式,是说由某个产品类接口、产品实现类、工厂类、客户端(单元测试主类)构成的一个模式,大程度的降低了代码的
Wesley13 Wesley13
3年前
Java基础之反射(非常重要)
反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))一、反射的概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法
Wesley13 Wesley13
3年前
Java重点基础:反射机制
一、什么是反射?Java反射说的是在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。对于任何一个对象,我们都能够对它的方法和属性进行调用。我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。二、反射的三种方式
Wesley13 Wesley13
3年前
Java反射机制及适用场景
什么是Java反射机制?JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为Java的反射机制。反射的适用场景是什么?1.当你做一个软件可以安装插件的功能,你连插件的类型名称都不知道,你怎么实例化这个对象呢