反射/代理

反射

反射详解

1
2
3
4
5
6
7
8
9
10
* 常用相关api:
* java.long.Class: 代表一个类 ---test3()
* 1.类的加载过程: 程序执行javac.exe命令以后,会生成一个或多个字节码文件(.class文件)。
* 接着使用java.exe命令对某个字节码文件进行解释运行,相当于某个字节码文件加载到内存中。此过程就称为
* 类的加载。加载到内存中的类,我i们成为运行时类,此运行时类,就作为一个Class的一个实列
* 2.Class实例也就是一个运行时类
* 3.加载到内存的运行时类,会缓存一段时间,在此时间内我们可以通过不同的方式来获取此运行时类
* java.long.reflet.Method: 代表类的方法
* java.long.reflet.Field: 代表类的成员变量
* java.long.reflet.Constructor:代表类的构造器

疑问:

  什么时候用反射?
  编译时期确定不了用哪个类的对象 (servlet 中的体现,根据前端请求确认用户执行那些操作(例如:登陆,注册)创建相关对象)

创建类的对象的几种方式:

  1)new +构造器

  2)类本身或工具类提供的静态方法创建对象

  3)反射

获取Class实例的几种方式
方式一:调用运行时类的属性
1
2
Class<Person> class1 = Person.class;
System.out.println(class1); //输出Person类本身---->class cn.itcast.base.Person
方式二:通过运行时对象
1
2
3
Person p1=new Person();
Class class2 = p1.getClass();
System.out.println(class2); //class cn.itcast.base.Person
方式三:调用Class的静态方法 (推荐)
1
2
3
4
5
6
Class class3 = Class.forName("cn.itcast.base.Person");//类的全类名
System.out.println(class3); //class cn.itcast.base.Person

//比较发现运行时类是同一个
System.out.println(class1 == class2); //true
System.out.println(class1 == class3); //true
方式四 调用类的加载器加载ClassLoader (了解)
1
2
3
4
5
6
7
ClassLoader classLoader = ReflexTest.class.getClassLoader();
try {
Class class4 = classLoader.loadClass("cn.itcast.base.Person");
System.out.println(class4); ////class cn.itcast.base.Person
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

反射操作

Person基类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Person {
private String name;
public int age;
public Person(){

}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name){
this.name=name;
}
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;
}

private void hello(){
System.out.println("private void");
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Person person = (Person) o;

if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}

@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}

@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

}

通过反射Person的操作:

1)通过反射创建Person对象
1
2
3
4
Class<Person> personClass = Person.class;
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
Person person = constructor.newInstance("antusheng", 18);
System.out.println(person.toString()); //Persion{name='antusheng', age=18}
2)通过反射调用对象指定的方法,属性
1
2
3
4
5
6
7
8
Field age = personClass.getDeclaredField("age");
age.set(person,21);
System.out.println(person.toString()); //Persion{name='antusheng', age=21}
//调用方法
Method setName = personClass.getDeclaredMethod("setName", String.class);
//如果调用的方法没有返回值,此invoke返回null
setName.invoke(person,"安徒生");
System.out.println(person.toString()); //Persion{name='安徒生', age=21}
3)调用私有构造器
1
2
3
4
Constructor<Person> cons1 = personClass.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1=cons1.newInstance("Tom");
System.out.println(p1); //Persion{name='Tom', age=0}
4)调用私有属性
1
2
3
4
5
Field name = personClass.getDeclaredField("name");
//属性是private的,设置为true保证属性可访问
name.setAccessible(true);
name.set(p1,"安徒生jy");
System.out.println(p1); //Persion{name='安徒生jy', age=0}
5)调用私有方法
1
2
3
Method hello = personClass.getDeclaredMethod("hello");
hello.setAccessible(true);
hello.invoke(p1); //private void

代理

  代理设计模式原理: 使用一个代理将对象包装起来,然后该代理类对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用到原始对象

静态代理

代理类和被代理类在编译期间都确定下来。

接口定义:

1
2
3
interface ClohtFactory{
void produceCloth();
}

定义代理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class  ProxyClothFactory implements ClohtFactory{
private ClohtFactory factory; //用被代理对象进行实例化
public ProxyClothFactory(ClohtFactory clohtFactory){
this.factory=clohtFactory;
};
@Override
public void produceCloth() {
System.out.println("代理工厂准备一些准备工作");

factory.produceCloth();

System.out.println("代理工厂做后续的一些工作");
}
}

被代理类:

1
2
3
4
5
6
7
class NikeClothFactory implements ClohtFactory {

@Override
public void produceCloth() {
System.out.println("Nike工厂生产一批新款运动服装");
}
}

进行静态代理测试:

1
2
3
4
5
6
7
8
9
10
11
12
public class StaticProxyTest  {
public static void main(String[] args) {
//创建代理类对象
NikeClothFactory nike=new NikeClothFactory();
//创建被代理类对象
ProxyClothFactory proxyClothF=new ProxyClothFactory(nike);
proxyClothF.produceCloth();
//代理工厂准备一些准备工作
//Nike工厂生产一批新款运动服装
//代理工厂做后续的一些工作
}
}

动态代理

在程序运行时确定代理对象,通过反射获得运行时类创建代理类。

接口定义:

1
2
3
4
interface Human{
String getBelief();
void ear(String food);
}

被代理类:

1
2
3
4
5
6
7
8
9
10
11
12
class SuperMan implements  Human{

@Override
public String getBelief() {
return "我相信自己";
}

@Override
public void ear(String food) {
System.out.println("我喜欢吃"+food);
}
}

实现动态代理需要解决问题:

1)如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象?
2)当通过代理类的对象调用方法时,如何动态的取调用被代理类的同名方法?

1
2
3
4
5
6
7
8
9
class ProxyFactory{
//调用此方法。返回一个代理类对象,解决问题一
public static Object getProxyInstance(Object obj){
MyInvocationHandler myHandler = new MyInvocationHandler();
myHandler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),myHandler);
}//通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例。针对不同的代理类,传入相应的代理程序控制器InvocationHandler

}

构建 MyInvocationHandler实现InvocationHandler接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyInvocationHandler implements InvocationHandler{
private Object object; //需要使用被代理类对象进行赋值

public void bind(Object object){
this.object=object;
}

//当通过代理类的对象调用某个方法x时,就会自动调用如下的方法:invoke()方法
//将被代理类要执行的方法x要执行的功能声明在invoke中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

//代理类对象调用的方法,此方法也作为被代理类对象调用的方法
//object 本身就是被代理对象
Object returnInvoke = method.invoke(object, args);
//上述方法的返回值就作为当前类的invoke()方法的返回值
return returnInvoke;
}
}

动态代理测试:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//Object proxyInstance = ProxyFactory.getProxyInstance(superMan);
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.ear("烤肉");
/*我相信自己
我喜欢吃烤肉*/

}
看都看了,不说来点什么!