校招准备:(二):java高级知识(反射,动态代理,java和jvm内存模型,垃圾回收,类加载)

目录

3.1深入理解Java类型信息(Class对象)与反射机制

3.2、java的反射机制

3.3代理模式,静态代理,动态代理

3.3java注解的原理(拓展)

3.4java动态代理和cglib动态代理区别,Spring aop与aspectJ的区别:

4.jmm(java memory model)内存模型与垃圾回收:

4.1java四种引用:

4.2深入理解JVM(一)--Java 内存区域

4.3判断对象是否存活 

4.4垃圾回收算法 :

4.5GC是什么时候触发的

4.6知道哪些垃圾收集器?

4.7静态对象要成为垃圾被回收,要满足三个条件: 

4.8几种常量池:

5类加载:

5.1java类加载的方式分为两种:

5.2类初始化的时机

5.3类的加载机制:

5.2classloader讲解:

5.3关于静态内部类的问题。

6.Java的解释执行


3.1深入理解Java类型信息(Class对象)与反射机制

RTTI(Run-Time Type Identification)运行时类型识别,其作用是在运行时识别一个对象的类型和类的信息,这里分两种:传统的”RRTI”,它假定我们在编译期已知道了所有类型(在没有反射机制创建和使用类对象时,一般都是编译期已确定其类型,如new对象时该类必须已定义好),另外一种是反射机制,它允许我们在运行时发现和使用类型的信息。在Java中用来表示运行时类型信息的对应类就是Class类。

Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应Class对象并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件保存的就是Class对象)。jJVM将类加载后,就会根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。

  • Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载

  • Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要(关于反射稍后分析)。

获取class对象三种方式:
class.forname(),类名.class,对象.getclass()

在执行class.forname("classname")时,JVM会在classapth中去找对应的类并加载,这时JVM会执行该类的静态代码段。

//字面常量的方式获取Class对象
Class clazz = Gum.class;
通过字面量的方法获取Class对象的引用不会自动初始化该类,触发的应该是加载阶段个class.forname相同。更加有趣的是字面常量的获取Class对象引用方式不仅可以应用于普通的类,也可以应用用接口,数组以及基本数据类型,这点在反射技术应用传递参数时很有帮助,

在Java SE5引入泛型后,使用我们可以利用泛型来表示Class对象更具体的类型,比如Class<Integer>,即使在运行期间会被擦除,但编译期足以确保我们使用正确的对象类型。

强制转换,这得归功于RRTI,要知道在Java中,所有类型转换都是在运行时进行正确性检查的,利用RRTI进行判断类型是否正确从而确保强制转换的完成,如果类型转换失败,将会抛出类型转换异常。
除了强制转换外,在Java SE5中新增一种使用Class对象进行类型转换的方式

Animal animal= new Dog();
//这两句等同于Dog dog = (Dog) animal;
Class<Dog> dogType = Dog.class;
Dog dog = dogType.cast(animal)

关于instanceof 关键字,它返回一个boolean类型的值,这样可以避免抛出类型转换的异常。

而isInstance方法则是Class类中的一个Native方法,也是用于判断对象类型的

3.2、java的反射机制

反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。一直以来反射技术都是Java中的闪亮点,这也是目前大部分框架(如Spring/Mybatis等)得以实现的支柱。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

在Java中,Class类与java.lang.reflect类库一起对反射技术进行了全力的支持。
在反射包中,我们常用的类主要有:
Constructor类表示的是Class 对象所表示的类的构造方法,利用它可以在运行时动态创建对象、
Field表示Class对象所表示的类的成员变量,通过它可以在运行时动态修改成员变量的属性值(包含private)、
Method表示Class对象所表示的类的成员方法,通过它可以动态调用对象的方法(包含private),

java反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;生成动态代理

通过反射机制可以实现动态代理,基于此spring框架实现面相切面aop和拦截器以及mabtis框架。
反射可以实现动态编译,体现多态,降低类的藕合性。
缺点是对性能有影响。

newInstance和new创建对象的区别
在使用newInstance()方法的时候,必须保证这个类已经加载并且已经连接了,而这可以通过Class的静态方法forName()来完成的。
new关键字能调用任何构造方法。
newInstance()只能调用无参构造方法。
newInstance: 弱类型(GC是回收对象的限制条件很低,容易被回收)、低效率、只能调用无参构造,new 强类型(GC不会自动回收,只有所有的指向对象的引用被移除是才会被回收,若对象生命周期已经结束,但引用没有被移除,经常会出现内存溢出)

3.3代理模式,静态代理,动态代理

轻松学,Java 中的代理模式及动态代理

静态代理代码见上面给的链接。

动态代理:

public interface SellWine {
	 void mainJiu();

}

public class MaotaiJiu implements SellWine {
	@Override
	public void mainJiu() {
		// TODO Auto-generated method stub
		System.out.println("我卖得是茅台酒。");
	}
}

public class Wuliangye implements SellWine {
	@Override
	public void mainJiu() {
		// TODO Auto-generated method stub
		System.out.println("我卖得是五粮液。");
	}
}

InvocationHandler:
InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。

  • proxy 代理对象
  • method 代理对象调用的方法
  • args 调用的方法中的参数
public class GuitaiA implements InvocationHandler {
	
	private Object pingpai;
	
	public GuitaiA(Object pingpai) {
		this.pingpai = pingpai;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("销售开始  柜台是: "+this.getClass().getSimpleName());
		method.invoke(pingpai, args);
		System.out.println("销售结束");
		return null;
	}
}
public class Test {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MaotaiJiu maotaijiu = new MaotaiJiu();
	
		Wuliangye wu = new Wuliangye();
		
		InvocationHandler jingxiao1 = new GuitaiA(maotaijiu);
		InvocationHandler jingxiao2 = new GuitaiA(wu);
		
		SellWine dynamicProxy = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
				MaotaiJiu.class.getInterfaces(), jingxiao1);
		SellWine dynamicProxy1 = (SellWine) Proxy.newProxyInstance(MaotaiJiu.class.getClassLoader(),
				MaotaiJiu.class.getInterfaces(), jingxiao2);
		
		dynamicProxy.mainJiu();
		
		dynamicProxy1.mainJiu();
	}
}

 Proxy 的静态方法 newProxyInstance 才会动态创建代理。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

  • loader 自然是类加载器
  • interfaces 代码要用来代理的接口
  • h 一个 InvocationHandler 对象

结果:

销售开始  柜台是: GuitaiA
我卖得是茅台酒。
销售结束
销售开始  柜台是: GuitaiA
我卖得是五粮液。
销售结束

原理:
è¿éåå¾çæè¿°

红框中 $Proxy0就是通过 Proxy 动态生成的。
$Proxy0实现了要代理的接口。
$Proxy0通过调用 InvocationHandler来执行任务。

动态代理的应用:

还是在不修改被代理对象的源码上,进行功能的增强。

 AOP 面向切面编程:日志记录,性能统计,安全控制,事务处理,异常处理等等。

3.3java注解的原理(拓展)

我就不摘内容了,直接看这两篇文章就够了:

秒懂,Java 注解 (Annotation)你可以这样学

深入理解Java注解类型(@Annotation)

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

我之前看到的注解在javaweb应用:https://github.com/JinBinPeng/springboot-jwt

功能:通过注解来判断是否对接口方法进行拦截验证。

首先定义两个注解,一个需要验证,一个不需要验证的注解。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
    boolean required() default true;
}

然后将注解放到controller中的方法上

@UserLoginToken
    @GetMapping("/getMessage")
    public String getMessage(){
        return "你已通过验证";
    }

然后在拦截器中,通过method.isAnnotationPresent()来判断注解,进行逻辑处理。

 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        // 如果不是映射到方法直接通过
        if(!(object instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod=(HandlerMethod)object;
        Method method=handlerMethod.getMethod();
        //检查是否有passtoken注释,有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new R
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值