1 反射的概述
1.1 反射的理解
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
框架 = 反射 + 注解 + 设计模式
1.2 反射相关的API
java.lang.Class 反射的源头
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor
1.3 反射机制的功能
在运行时判断任意一个对象所属的类在运行时构造任意一个类的对象在运行时判断任意一个类所具有的成员变量和方法在运行时获取泛型信息在运行时调用任意一个对象的成员变量和方法在运行时处理注解生成动态代理
1.4 体会反射的动态性
@Test
public void test1(){
for (int i
= 0; i
< 50; i
++) {
int rand
= new Random().nextInt(3);
String classPath
= "";
switch (rand
){
case 0:
classPath
= "java.util.Date";
break;
case 1:
classPath
= "java.lang.Object";
break;
case 2:
classPath
= "com.jiwei.java.Person";
break;
}
Object instance
= null
;
try {
instance
= getInstance(classPath
);
System
.out
.println(instance
);
} catch (Exception e
) {
e
.printStackTrace();
}
}
}
public Object
getInstance(String classPath
){
Class
clazz = Class
.forName(classPath
);
return clazz
.newInstance
;
}
2 Class类
2.1 Class类的理解
类的加载过程:
程序经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾)
接着我们使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中。此过程就成为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
换句话说,Class的实例就对应着一个运行时类。
加载到内存的运行时类,会缓存一段时间。在此时间内,我们可以通过不同的方式来获得此运行时类。
2.2 获得Class实例的几种方式。
方式一:(最常用的方式!)
Class clazz = Class.forName(String 全类名)
方式二:调用运行时类的属性:.class
Class clazz = 类名.class()
方式三:通过运行时类的对象,调用getClass()
Class clazz = 对象名.getClass()
方式四:(了解)使用类的加载器:ClassLoader
ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass(“com.atguigu.java.Person”);
@Test
public void test5() throws Exception
{
Class
clazz = Class
.forName("com.jiwei.exer.Person3");
System
.out
.println(clazz
);
Class
clazz1 = Person3
.class;
System
.out
.println(clazz1
);
Person3 p
= new Person3("Tom", 23, 20000);
Class
clazz2 = p
.getClass();
System
.out
.println(clazz2
);
}
2.3 创建类的对象的方式
方式一:new + 构造器方式二:要创建Xxx的对象,可以考虑:Xxx、Xxxs、XxxFactory、XxxBuilder类中是否含有静态的方法,可以调用静态的方法,创建Xxx对象。方式三:通过反射
创建对象,调用结构
@Test
public void test1(){
Person3 p1
= new Person3("Tom", 23, 7777);
p1
.name
= "Jerry";
double salary
= p1
.getSalary();
}
通过反射创建对象,调用结构
@Test
public void test2() throws Exception
{
Class
clazz = Class
.forName("com.jiwei.exer.Person3");
Constructor constructor
= clazz
.getConstructor(String
.class, int.class, double.class);
Person3 tom
= (Person3
) constructor
.newInstance("Tom", 23, 7763);
tom
.name
= "Marry";
tom
.setSalary(2222.1);
System
.out
.println(tom
);
}
通过反射调用私有的结构
@Test
public void test3() throws Exception
{
Class
clazz = Class
.forName("com.jiwei.exer.Person3");
Constructor constructor
= clazz
.getDeclaredConstructor(String
.class);
constructor
.setAccessible(true);
Person3 tom
= (Person3
) constructor
.newInstance("Tom");
System
.out
.println(tom
);
}
@Test
public void test4() throws Exception
{
Class
clazz = Class
.forName("com.jiwei.exer.Person3");
Constructor constructor
= clazz
.getConstructor(String
.class, int.class, double.class);
Person3 tom
= (Person3
) constructor
.newInstance("Tom", 29, 88888);
Field salary
= clazz
.getDeclaredField("salary");
salary
.setAccessible(true);
salary
.set(tom
, 6666);
System
.out
.println(tom
);
Method method
= clazz
.getDeclaredMethod("getNation",String
.class);
method
.setAccessible(true);
System
.out
.println(method
.invoke(tom
, "中国"));
}
2.4 Class实例可以是哪些结构
3 类的加载ClassLoader
3.1 类的加载过程
3.2 类的加载器的作用
3.3 类的加载器的分类
3.4 Java类编译、运行的执行的流程
3.5 使用ClassLoader加载src目录下的配置文件
@Test
public void test1() throws IOException
{
Properties properties
= new Properties();
FileInputStream fis
= new FileInputStream("jdbc.properties");
properties
.load(fis
);
String name
= properties
.getProperty("name");
System
.out
.println(name
);
String password
= properties
.getProperty("password");
System
.out
.println(password
);
Properties properties
= new Properties();
ClassLoader classLoader
= ClassLoaderTest
.class.getClassLoader();
InputStream inputStream
= classLoader
.getResourceAsStream("jdbc1.properties");
properties
.load(inputStream
);
String name
= properties
.getProperty("name");
System
.out
.println(name
);
String password
= properties
.getProperty("password");
System
.out
.println(password
);
}
4 创建运行时类的对象
newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。
要想此方法正常的创建运行时类的对象,要求: 1.运行时类必须提供空参的构造器 2.空参的构造器的访问权限得够。通常,设置为public。
在javabean中要求提供一个public的空参构造器。原因: 1.便于通过反射,创建运行时类的对象 2.便于子类继承此运行时类时,默认调用super()时,保证父类此构造器
4.1 无参构造器
区别:方式1:Class的对象直接.newInstance()
方式2:Class的对象调用getDeclaredConstructor()得到Constructor对象,通过Constructor对象调用newInstance()
方式3:Class的对象调用getConstructor()得到Constructor对象,通过Constructor对象调用newInstance()
Class
<?> aClass
= Class
.forName("com.jiwei.java.Person");
Object o
= aClass
.newInstance();
System
.out
.println(o
instanceof Person);
System
.out
.println(o
);
Constructor
<?> constructor
= aClass
.getDeclaredConstructor();
Object o1
= constructor
.newInstance();
System
.out
.println(o1
instanceof Person);
System
.out
.println(o1
);
Constructor
<?> constructor1
= aClass
.getConstructor();
Object o2
= constructor1
.newInstance();
System
.out
.println(o2
instanceof Person);
System
.out
.println(o2
);
4.2 有参构造器
Class的对象调用getConstructor();
@Test
public void test2() throws Exception
{
Class
<?> aClass
= Class
.forName("com.jiwei.review.Person");
Constructor
<?> constructor
= aClass
.getConstructor(String
.class, int.class, double.class);
Object o
= constructor
.newInstance("Tom", 22, 22222.2);
System
.out
.println(o
);
System
.out
.println(o
instanceof Person);
Constructor
<?> constructor1
= aClass
.getDeclaredConstructor(String
.class, int.class, double.class);
Object o1
= constructor1
.newInstance("Jerry", 33, 33333.21);
System
.out
.println(o1
);
System
.out
.println(o1
instanceof Person);
Constructor
<?> constructor2
= aClass
.getDeclaredConstructor(String
.class);
constructor2
.setAccessible(true);
Object o2
= constructor2
.newInstance("Mary");
System
.out
.println(o2
);
System
.out
.println(o2
instanceof Person);
}
5 获取运行时类的完整结构
我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
5.1 属性
getField(String name);获得运行时类的属性(子类和父类中public的属性)getDeclaredField(String name);获得运行时类的属性(子类中全部的属性,所有访问权限的)getFields();返回运行类中所有public的属性getDeclaredFields();返回运行时类的所有的属性,包括所有访问权限的
对运行时类的属性操作
首先由一个运行时类的实例对象对私有的属性还需要设置setAccessible(true)
@Test
public void test3() throws Exception
{
Class
<?> aClass
= Class
.forName("com.jiwei.review.Person");
Field
[] fields
= aClass
.getFields();
for (Field field
: fields
) {
System
.out
.println(field
);
}
System
.out
.println("-----------------------------------");
Field
[] fields1
= aClass
.getDeclaredFields();
for (Field field
: fields1
) {
System
.out
.println(field
);
}
System
.out
.println("-----------------------------------------");
Field salary
= aClass
.getField("salary");
System
.out
.println(salary
);
System
.out
.println("------------------------------------------");
Field name
= aClass
.getDeclaredField("name");
System
.out
.println(name
);
Object o
= (Person
)aClass
.newInstance();
Field name1
= aClass
.getDeclaredField("name");
name1
.setAccessible(true);
name1
.set(o
, "Yam");
System
.out
.println(o
);
}
5.2 方法
getMethod(String 方法名; calss 方法的class类型)getDeclaredMethod(String 方法名; calss 方法的class类型)getMethods();获取该运行时类以及其父类中所有的public的方法getDeclaredMethods();获取该运行时类中所有的方法
@Test
public void test4() throws Exception
{
Class
<?> aClass
= Class
.forName("com.jiwei.review.Person");
Method
[] methods
= aClass
.getMethods();
for (Method method
: methods
) {
System
.out
.println(method
);
}
System
.out
.println("--------------------------------------");
Method
[] methods1
= aClass
.getDeclaredMethods();
for (Method method
: methods1
) {
System
.out
.println(method
);
}
System
.out
.println("----------------------------------------");
Constructor
<?> constructor
= aClass
.getDeclaredConstructor(String
.class);
constructor
.setAccessible(true);
Object o
= constructor
.newInstance("Tom");
Method show
= aClass
.getDeclaredMethod("show", String
.class);
show
.setAccessible(true);
Object invoke
= show
.invoke(o
, "中国");
System
.out
.println(invoke
);
}
5.3 构造器
@Test
public void test1(){
Class
clazz = Person
.class;
Constructor
[] constructors
= clazz
.getConstructors();
for(Constructor c
: constructors
){
System
.out
.println(c
);
}
System
.out
.println();
Constructor
[] declaredConstructors
= clazz
.getDeclaredConstructors();
for(Constructor c
: declaredConstructors
){
System
.out
.println(c
);
}
}
5.4 父类
@Test
public void test5(){
Class
<Person> personClass
= Person
.class;
Class
<? super Person
> superclass
= personClass
.getSuperclass();
System
.out
.println(superclass
);
}
5.5 带泛型的父类
@Test
public void test3(){
Class
clazz = Person
.class;
Type genericSuperclass
= clazz
.getGenericSuperclass();
System
.out
.println(genericSuperclass
);
}
5.6 运行时类的带泛型的父类的泛型
@Test
public void test4(){
Class
clazz = Person
.class;
Type genericSuperclass
= clazz
.getGenericSuperclass();
ParameterizedType paramType
= (ParameterizedType
) genericSuperclass
;
Type
[] actualTypeArguments
= paramType
.getActualTypeArguments();
System
.out
.println(((Class
)actualTypeArguments
[0]).getName());
}
5.7 获取运行时类实现的接口
@Test
public void test5(){
Class
clazz = Person
.class;
Class
[] interfaces
= clazz
.getInterfaces();
for(Class
c : interfaces
){
System
.out
.println(c
);
}
System
.out
.println();
Class
[] interfaces1
= clazz
.getSuperclass().getInterfaces();
for(Class
c : interfaces1
){
System
.out
.println(c
);
}
}
5.8 获取运行时类所在的包
@Test
public void test6(){
Class
clazz = Person
.class;
Package pack
= clazz
.getPackage();
System
.out
.println(pack
);
}
5.9 获取运行时类声明的注解
@Test
public void test7(){
Class
clazz = Person
.class;
Annotation
[] annotations
= clazz
.getAnnotations();
for(Annotation annos
: annotations
){
System
.out
.println(annos
);
}
}
6 调用运行时类的指定结构
6.1 调用指定的属性
@Test
public void testField1() throws Exception
{
Class
clazz = Person
.class;
Person p
= (Person
) clazz
.newInstance();
Field name
= clazz
.getDeclaredField("name");
name
.setAccessible(true);
name
.set(p
,"Tom");
System
.out
.println(name
.get(p
));
}
6.2 调用指定的方法
@Test
public void testMethod() throws Exception
{
Class
clazz = Person
.class;
Person p
= (Person
) clazz
.newInstance();
Method show
= clazz
.getDeclaredMethod("show", String
.class);
show
.setAccessible(true);
Object returnValue
= show
.invoke(p
,"CHN");
System
.out
.println(returnValue
);
System
.out
.println("*************如何调用静态方法*****************");
Method showDesc
= clazz
.getDeclaredMethod("showDesc");
showDesc
.setAccessible(true);
Object returnVal
= showDesc
.invoke(Person
.class);
System
.out
.println(returnVal
);
}
6.3 调用指定的构造器:
@Test
public void testConstructor() throws Exception
{
Class
clazz = Person
.class;
Constructor constructor
= clazz
.getDeclaredConstructor(String
.class);
constructor
.setAccessible(true);
Person per
= (Person
) constructor
.newInstance("Tom");
System
.out
.println(per
);
}
7 动态代理
7.1 代理模式的原理
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
7.2 静态代理
代码示例
实现Runnable接口的方法创建多线程。
Class
MyThread implements Runnable{}
Class
Thread implements Runnable{}
main(){
MyThread t
= new MyThread();
Thread thread
= new Thread(t
);
thread
.start();
}
静态代理的缺点
① 代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。 ② 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
7.3 动态代理的实现
需要解决的两个主要问题
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。 (通过Proxy.newProxyInstance()实现)问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。 (通过InvocationHandler接口的实现类及其方法invoke())
代码示例
interface Human{
String
getBelief();
void eat(String food
);
}
class SuperMan implements Human{
@Override
public String
getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food
) {
System
.out
.println("我喜欢吃" + food
);
}
}
class HumanUtil{
public void method1(){
System
.out
.println("====================通用方法一====================");
}
public void method2(){
System
.out
.println("====================通用方法二====================");
}
}
class ProxyFactory{
public static Object
getProxyInstance(Object obj
){
MyInvocationHandler handler
= new MyInvocationHandler();
handler
.bind(obj
);
return Proxy
.newProxyInstance(obj
.getClass().getClassLoader(),obj
.getClass().getInterfaces(),handler
);
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj
;
public void bind(Object obj
){
this.obj
= obj
;
}
@Override
public Object
invoke(Object proxy
, Method method
, Object
[] args
) throws Throwable
{
HumanUtil util
= new HumanUtil();
util
.method1();
Object returnValue
= method
.invoke(obj
,args
);
util
.method2();
return returnValue
;
}
}
public class ProxyTest {
public static void main(String
[] args
) {
SuperMan superMan
= new SuperMan();
Human proxyInstance
= (Human
) ProxyFactory
.getProxyInstance(superMan
);
String belief
= proxyInstance
.getBelief();
System
.out
.println(belief
);
proxyInstance
.eat("四川麻辣烫");
System
.out
.println("*****************************");
NikeClothFactory nikeClothFactory
= new NikeClothFactory();
ClothFactory proxyClothFactory
= (ClothFactory
) ProxyFactory
.getProxyInstance(nikeClothFactory
);
proxyClothFactory
.produceCloth();
}
}