day 6-7 面试题:什么是反射、volaitle关键字

面试题:
1. 懒汉单例模式为什么要加volaitle
2. 什么是反射?怎么获取一个类的成员变量、成员方法,注解信息?在项目中反射多吗?主要用来做什么?

1. 面试题解题

1.1 懒汉单例模式为什么要加volaitle

我以前写的一篇单例模式的文章:https://blog.csdn.net/xwh_1230/article/details/78198924

1.1.1 懒汉单例模式

使用时再创建实例。

/**
 * DCL懒加载
 * 1. 懒加载
 * 2. 线程安全,性能较高
 * 3. 易用、易理解
 * Created by Administrator on 2017/10/10.
 */

public class SingleInstance {

private volatile static SingleInstance instance;
    // 私有构造方法
    private SingleInstance(){}

    public static SingleInstance getInstance(){
        // 延迟加载
        if (instance == null){
            // 第一重锁定
            synchronized (SingleInstance.class){
                //第二重锁定
                if (instance == null){
                    instance = new SingleInstance();
                }
            }

        }
        return instance;
    }
}
1.1.2 懒汉单例模式为什么要加volaitle

这个问题的关键在于:instance = new SingleInstance()语句不是原子操作可以分解为:

  1. 给 instance 分配空间
  2. 调用构造方法初始化实例
  3. 将实例对象指向 instance分配空间

JVM中的及时编译存在指令重排序优化,所以说不能保证1-2-3顺序执行,最终也有可能是按照1-3-2执行。假如线程1执行的是1-3,线程2对instance做非空判断时结果是非null,则直接返回未初始化的instance,这个时候线程2就会报错。
添加volatile能禁止指令重排序特性,保证代码的有序性,它可以保证上述的步骤按照1-2-3的顺序执行。

1.2 什么是反射?怎么获取一个类的成员变量、成员方法,注解信息?在项目中反射多吗?主要用来做什么?

1.2.1 反射

运行时才知道要操作的类是什么,并能够调用它的任意方法和属性。这种动态获取对象,动态调用方法称之为反射。

1.2.2 关键Api
  1. 获取Class

    1. 知道类的全路径:

      Class.forName(“java.lang.String”)

    2. String.class

      知道要生成什么对象

    3. book.getClass()

      已有对象,通过对象获取Class

  2. 反射生成类对象

    1. 通过构造方法创建

        // 2. 获取构造方法  
       Constructor<?> constructor = clazz.getConstructor(String.class);
       // 3. 通过构造方法创建对象,可以指定构造参数  
       Object book = constructor.newInstance("通过构造方法传入的book内容");
      
    2. 通过Class创建

       // 3.1 通过Class创建对象,只能调用无参构造方法
       Object book = clazz.newInstance();
      
  3. 获取构造方法、属性、普通方法

     // 2. 获取构造方法
     Constructor<?> constructor = clazz.getConstructor(String.class);
     // 2.1 获取私有构造方法
     Constructor<?> privateConstructor = clazz.getDeclaredConstructor();
    
     // 3.1 获取公有字段
     Field bookContent = clazz.getField("bookContent");
     // 3.2 获取私有字段
     Field num = clazz.getDeclaredField("num");
    
     // 4. 通过Class获取方法
     Method  setBookContent = clazz.getMethod("setBookContent", String.class);
     // 4.1 获取私有的方法
     Method prvateSetNUm = clazz.getDeclaredMethod("setNum", Integer.class);
     
     //这几个是获取多个字段和方法的方式
     clazz.getDeclaredField()
     clazz.getDeclaredFields()
     clazz.getMethods()
     clazz.getDeclaredMethods()
    
1.2.3 反射获取成员变量、成员方法、构造方法及注解信息

下面使用一个简单例子演示一下几种操作

// 反射示例的类
public class Book {

	String bookContent;
	
	public Book(){
		
	}

	public String getBookContent() {
		return bookContent;
	}

	public void setBookContent(String bookContent) {
		this.bookContent = bookContent;
	}

	@Override
	public String toString() {
		return "Book [bookContent=" + bookContent + "]";
	}
	
}


try {
	// 1. 首先获取Class对象
	Class<?> clazz = Class.forName("tree.Book");
	
	// 2. 获取构造方法
	Constructor<?> constructor = clazz.getConstructor();
	
	// 3. 反射的方式创建对象
	Object book = constructor.newInstance();
	
	// 4. 通过Class获取方法
	Method  setBookContent = clazz.getMethod("setBookContent", String.class);
	// 5. 执行反射对象的对应方法
	setBookContent.invoke(book, "这是我反射调用set方法,给book设置的内容");
	
	Method toString = clazz.getMethod("toString");
	
	System.out.println(toString.invoke(book));
	
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (NoSuchMethodException e) {
	e.printStackTrace();
} catch (SecurityException e) {
	e.printStackTrace();
} catch (InstantiationException e) {
	e.printStackTrace();
} catch (IllegalAccessException e) {
	e.printStackTrace();
} catch (IllegalArgumentException e) {
	e.printStackTrace();
} catch (InvocationTargetException e) {
	e.printStackTrace();
}
1.2.3 项目中反射主要用来做什么?
  1. 反射调用系统方法或者sdk方法解决bug

比如有系统bug或者SDK的bug,我们无法改变其代码,只能使用反射的方式,对sdk代码或者系统代码进行hook,进行逻辑修复或者异常处理。

  1. 热修复等场景

使用DexClassLoader去加载未安装的apk或者jar中的方法,修复问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值