知识点复习06 java基础02

反射的原理,反射创建类实例的三种方式是什么?

一、什么是JAVA的反射机制

Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。

换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。

三、JAVA反射机制提供了什么功能

Java反射机制提供如下功能:

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

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

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

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

在运行时创建新类对象

在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。

1、获取类的Class对象

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。获取类的Class对象有多种方式

2、获取类的Fields

可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA 的Class<T>类提供了几个方法获取类的属性。

3、获取类的Method

通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法

4、获取类的Constructor

通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 

Class<T>类提供了几个方法获取类的构造器。

5、通过调用代理对象的方法去调用真实角色的方法。

sub.Request();

输出:

class $Proxy0 新建的代理对象,它实现指定的接口

Method:public abstract void DynamicProxy.Subject.Request(),Args:null

RealSubject 调用的真实对象的方法
 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

为什么new一个对象那么简单,非要用反射技术中的newInstance?

为什么,我可以直接对象a1. 变量访问变量,却非要用反射那么费劲的获得name字段呢?

为什么,我几行代码就能搞定的事情,非要用反射呢?

 

ok,解密答案之前,我们先来思考一个问题?

假设我们定义了很多类,有Animal、Person、Car… ,如果我想要一个Animal实例,那我就new Animal(),如果另一个人想要一个Person实例,那么他需要new Person(),当然,另一个说,我只要一个Car实例,于是它要new Car()…这样一来就导致,每个用户new的对象需求不相同,因此他们只能修改源代码,并重新编译才能生效。这种将new的对象写死在代码里的方法非常不灵活,因此,为了避免这种情况的方法,Java提供了反射机制,典型的应用如下:

newInstance()方法 ---> 获取class类型之后,可以创建该类型的对象

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Class.forName 和 ClassLoader 区别。

ClassLoader.loadClass()Class.forName()大家都知道是反射用来构造类的方法,但是他们的用法还是有一定区别的。

 在讲区别之前,我觉得很有不要把类的加载过程在此整理一下。

 在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三

 步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:

    装载:查找和导入类或接口的二进制数据; 

  链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的; 

  校验:检查导入类或接口的二进制数据的正确性; 

  准备:给类的静态变量分配并初始化存储空间; 

  解析:将符号引用转成直接引用; 

  初始化:激活类的静态变量的初始化Java代码和静态Java代码块。

Class.forName(className)方法,其实调用的方法是Class.forName(className,true,classloader);注意看第2个boolean参数,它表示的意思,在loadClass后必须初始化。比较下我们前面准备jvm加载类的知识,我们可以清晰的看到在执行过此方法后,目标对象的 static块代码已经被执行,static参数也已经被初始化。

 再看ClassLoader.loadClass(className)方法,其实他调用的方法是ClassLoader.loadClass(className,false);还是注意看第2个 boolean参数,该参数表示目标对象被装载后不进行链接,这就意味这不会去执行该类静态块中间的内容。因此2者的区别就显而易见了。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

描述动态代理的几种实现方式,分别说出相应的优缺点

Jdk cglib jdk底层是利用反射机制,需要基于接口方式,这是由于
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
Cglib则是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk

简单案例

根据使用步骤:

首先新建一个接口Subject

然后为接口RealSubject新建一个实现类RealSubject

接着创建一个代理类JDKDynamicProxy实现java.lang.reflect.InvocationHandler接口,重写invoke方法

源码分析

这里查看JDK1.8.0_65的源码,通过debug学习JDK动态代理的实现原理

 大概流程

1、为接口创建代理类的字节码文件

2、使用ClassLoader将字节码文件加载到JVM

3、创建代理类实例对象,执行对象的目标方法

可看到

1、代理类继承了Proxy类并且实现了要代理的接口,由于java不支持多继承,所以JDK动态代理不能代理类

2、重写了equals、hashCode、toString

3、有一个静态代码块,通过反射或者代理类的所有方法

4、通过invoke执行代理类中的目标方法doSomething

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

CGLIB动态代理实现原理

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,

它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。

CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供

方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类

除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,

因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

自定义一个MethodInterceptor,里面的intercept方法,实现代理增强的逻辑

调用enhancer.create()生成proxy代理对象

三 CGLIB动态代理源码分析

实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:

这个接口只有一个intercept()方法,这个方法有4个参数:

1)obj表示增强的对象,即实现这个接口类的一个对象;

2)method表示要被拦截的方法;

3)args表示要被拦截方法的参数;

4)proxy表示要触发父类的方法对象;

在上面的Client代码中,通过Enhancer.create()方法创建代理对象,create()方法的源码:

先从cache中获取data

真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:

abstract protected Object nextInstance(Object instance) throws Exception;

在子类Enhancer中实现,实现源码如下:

看看data.newInstance(argumentTypes, arguments, callbacks)方法,

第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。

最后根据这些参数,通过反射生成代理对象,

CGLib采用了非常底层的字节码技术,其原理是通过目标类的字节码为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++

深拷贝和浅拷贝区别。

浅拷贝

首先让我们来说说浅拷贝。对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。"里面的对象“会在原来的对象和它的副本之间共享。例如,我们会为一个 Person对象创建第二个 Person 对象, 而两个 Person 会共享相同的 Name 和 Address 对象。

让我们来看看代码示例。在示例 5 中,我们有一个类 Person,类里面包含了一个 Name 和 Address 对象。拷贝构造器会拿到 originalPerson 对象,然后对其应用变量进行复制

浅拷贝的问题就是两个对象并非独立的。如果你修改了其中一个 Person 对象的 Name 对象,那么这次修改也会影响奥另外一个 Person 对象。

让我们在示例中看看这个问题。假如说我们有一个 Person 对象,然后也会有一个引用变量 monther 来指向它;然后当我们对 mother 进行拷贝时,创建第二个 Person 对象 son。如果在此后的代码中, son 尝试用 moveOut() 来修改他的 Address 对象, 那么 mother 也会跟着他一起搬走

不过,故事到这儿并没有结束。要创建一个真正的深拷贝,就需要我们一直这样拷贝下去,一直覆盖到 Person 对象所有的内部元素, 最后只剩下原始的类型以及“不可变对象(Immutables)”。让我们观察下如下这个 Street 类以获得更好的理解

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=

[数据结构] 数组与链表的优缺点和区别

总结

1、存取方式上,数组可以顺序存取或者随机存取,而链表只能顺序存取; 

2、存储位置上,数组逻辑上相邻的元素在物理存储位置上也相邻,而链表不一定; 

3、存储空间上,链表由于带有指针域,存储密度不如数组大; 

4、按序号查找时,数组可以随机访问,时间复杂度为O(1),而链表不支持随机访问,平均需要O(n); 

5、按值查找时,若数组无序,数组和链表时间复杂度均为O(1),但是当数组有序时,可以采用折半查找将时间复杂度降为O(logn); 

6、插入和删除时,数组平均需要移动n/2个元素,而链表只需修改指针即可; 

7、空间分配方面: 
  数组在静态存储分配情形下,存储元素数量受限制,动态存储分配情形下,虽然存储空间可以扩充,但需要移动大量元素,导致操作效率降低,而且如果内存中没有更大块连续存储空间将导致分配失败; 
  链表存储的节点空间只在需要的时候申请分配,只要内存中有空间就可以分配,操作比较灵活高效

error 和 exception 的区别

Java Exception 和Error有什么区别?

① Exception 和Error 都是继承了Throwable类,在Java中只有Throwable类型的实例才可以被抛出或者捕获,它是异常处理机制的基本类型。

 

② Exception和Error体现了Java平台设计者对不同异常情况的分类。

⑴Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。

⑵Exception又分为可检查(checked)异常和不可检查(unchecked)异常。可检查异常在源代码里必须显式的进行捕获处理,这是编译期检查的一部分。不可检查时异常是指运行时异常,像NullPointerException、ArrayIndexOutOfBoundsException之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

⑶Error是指正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序处于非正常的、不可恢复的状态。既然是非正常情况,不便于也不需要捕获。常见的比如OutOfMemoryError之类都是Error的子类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值