Java反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
/*
获取Class类型对象的三种方式
*/
import java.util.Date;
public class ReflectTest01
{
public static void main(String[] args) throws Exception{
//第一种方式:
Class c1 = Class.forName("Employee"); //c1引用保存内存地址指向堆中的对象,该对象代表的是Employee整个类.
//第二种方式:
//java中每个类型都有 class 属性.
Class c2 = Employee.class;
//第三种方式:
//java语言中任何一个java对象都有 getClass 方法
Employee e = new Employee();
Class c3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
//因为Employee这个类在JVM中只有一个,所以c1,c2,c3的内存地址是相同的,指向堆中唯一的一个对象.
System.out.println(c1==c2); //true
System.out.println(c2==c3); //true
//c4,c5,c6都代表 Date这个类
Class c4 = Date.class; //c4代表 Date这个类
Class c5 = Class.forName("java.util.Date"); //必须写类全名,类全名带有包名.
Date d = new Date();
Class c6 = d.getClass();
System.out.println(c4==c5); //true
System.out.println(c5==c6); //true
//c7代表 int 类型
Class c7 = int.class;
}
}
/*
获取某个特定的构造方法,然后创建对象.
*/
import java.lang.reflect.*;
public class ReflectTest09
{
public static void main(String[] args) throws Exception{
//1.获取类
Class c = Class.forName("Customer");
//2.获取特定的构造方法
Constructor con = c.getDeclaredConstructor(String.class,int.class);
//3.创建对象
Object o = con.newInstance("张三",25);
System.out.println(o);
}
}
class Customer
{
String name;
int age;
Customer(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return "Customer["+name+","+age+"]";
}
}
/*
java.lang.reflect.Field; 获取某个指定的属性
*/
import java.lang.reflect.*;
public class ReflectTest05
{
public static void main(String[] args) throws Exception{
//以前的方式:
/*
User u = new User();
u.age = 12; //set
System.out.println(u.age); //get
*/
//获取类
Class c = Class.forName("User");
//获取id属性
Field idF = c.getDeclaredField("id");
//获取到某个特定的属性可以用来?set , get
Object o = c.newInstance();
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
idF.set(o, "110"); //set
//get
System.out.println(idF.get(o));
}
}
/*
获取某个特定的方法,通过反射机制执行。
以前:
CustomerService cs = new CustomerService();
boolean isSuccess = cs.login("admin","123");
通过反射机制???
*/
import java.lang.reflect.*;
public class ReflectTest07
{
public static void main(String[] args) throws Exception{
//1.获取类
Class c = Class.forName("CustomerService");
//获取某个特定的方法
//通过:方法名+形参列表
Method m = c.getDeclaredMethod("login",String.class,String.class);
//通过反射机制执行login方法.
Object o = c.newInstance();
//调用o对象的m方法,传递"admin""123"参数,方法的执行结果是retValue
Object retValue = m.invoke(o, "admin","456");
System.out.println(retValue); //true
}
}
代理模式
代理: 就是让代理角色帮助真实角色完成一件事情;
静态代理
静态代理相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理还是原生的处理逻辑,不过在前后添加上需要添加的代码。
缺点:需要为每一个被代理的对象都创建一个代理类。
package 代理模式;
public interface GiveGift {
void giveDolls();
void giveFlowers();
void giveChocolate();
}
package 代理模式;
public class Persuit implements GiveGift {
SchoolGirl mm;
public Persuit(SchoolGirl mm) {
this.mm = mm;
}
@Override
public void giveDolls() {
System.out.println(mm.getName()+" 送你娃娃");
}
@Override
public void giveFlowers() {
System.out.println(mm.getName()+" 送你花花");
}
@Override
public void giveChocolate() {
System.out.println(mm.getName()+" 送你巧克力");
}
}
package 代理模式;
public class Proxy implements GiveGift {
Persuit gg;
public Proxy(SchoolGirl mm) {
gg = new Persuit(mm);
}
@Override
public void giveDolls() {
gg.giveDolls();
}
@Override
public void giveFlowers() {
gg.giveFlowers();
}
@Override
public void giveChocolate() {
gg.giveChocolate();
}
}
package 代理模式;
public class SchoolGirl {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package 代理模式;
public class Test {
public static void main(String[] args) {
SchoolGirl mm = new SchoolGirl();
mm.setName("郝英");
Proxy proxy = new Proxy(mm);
proxy.giveDolls();
proxy.giveFlowers();
proxy.giveChocolate();
}
}
动态代理
Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例; 动态代理是通过 Proxy 创建代理对象,然后将接口方法“代理”给 InvocationHandler 完成的。以下例子代理类同时代理了两个接口;
代码中使用Rent proxy = (Rent) proxyHander.getProxy();或者Rent2 proxy = (Rent2) proxyHander.getProxy();来使用不同接口的方法;
package 代理模式.动态代理;
//出租房屋
public interface Rent {
public void rent();
}
package 代理模式.动态代理;
public interface Rent2 {
public void rent2();
}
package 代理模式.动态代理;
//房东要买房
public class Host implements Rent ,Rent2{
public void rent(){
System.out.println("出租房屋");
}
@Override
public void rent2() {
System.out.println("出租房屋2");
}
}
package 代理模式.动态代理;
import com.sun.org.apache.xml.internal.resolver.readers.ExtendedXMLCatalogReader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyHander implements InvocationHandler {
private Object target;
public ProxyHander(Object target) {
this.target = target;
}
//生成代理对象
public Object getProxy(){
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(target, args);
fare();
return result;
}
public void seeHouse(){
System.out.println("看房");
}
public void fare(){
System.out.println("收取中介费");
}
}
package 代理模式.动态代理;
public class Test {
public static void main(String[] args) {
Host host = new Host();
ProxyHander proxyHander = new ProxyHander(host);
Rent2 proxy = (Rent2) proxyHander.getProxy();
proxy.rent2();
}
}
在调用Proxy.newProxyInstance之前,加一句System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);,就会在项目的根目录生成一个$Proxy0.class,本来这是字节码文件不能直接查看的,但IDEA会自动帮我们反编译class文件。注意以下代码中的: **super.h.invoke(this, m3, (Object[])null);**并不是反射调用因为h并不是Method对象,这里是调用InvocationHandler接口的实现类,也就是ProxyHander的invoke方法.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import 代理模式.动态代理.Rent;
import 代理模式.动态代理.Rent2;
public final class $Proxy0 extends Proxy implements Rent, Rent2 {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void rent() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void rent2() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("代理模式.动态代理.Rent").getMethod("rent");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("代理模式.动态代理.Rent2").getMethod("rent2");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}