反射是动态语言的关键
1.反射的功能如下:
1).在运行时判断任意一个对象所属的类;
2).在运行时构造任意类的对象。
3).在运行时判断任意一个类所具有的成员变量和方法;
4).在运行时调用任意一个对象的成员变量和方法;
5).生成动态代理
2.相关的API:
java.lang.Class:代表一个类
java.lang.reflect.Method:类的方法
java.lang.reflect.field :类的成员变量
java.lang.reflect.Constructor:类的构造方法
3.反射的源头:java.lang.Class
所涉及到的反射的类都在java.lang.reflect子包下
public final Class getClass() 通过对象反射求出类的名称
4.正常方式:引入需要的包类名->通过new实例化->取得实例化对象
在有反射以前,创建一个类的对象,调用方法、属性
public void test1(){
Person p=new Person();
p.setAge(10);
p.setName("cyj");
System.out.println(p);
p.show();
//p.display("sichuan");
}
反射:实例化对象->getClass()方法->得到完整的包类名称
有了反射,通过反射创建一个类的对象,调用其中的结构
public void test2() throws Exception{
Class clazz=Person.class;
//创建clazz对应的运行时类Person类的对象
Person p=(Person)clazz.newInstance();
System.out.println(p);
//通过反射调用运行时类的指定属性
Field f1 = clazz.getField("name");
f1.set(p,"cyj");
System.out.println(p);
Field f2=clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.setInt(p,19);
System.out.println(p);
//通过反射调用运行时类的指定方法
Method m1=clazz.getMethod("show", null);
m1.invoke(p, null);
Method m2=clazz.getMethod("display",new Class[]{String.class});
m2.invoke(p,new Object[]{ "CHN"});
}
5.类的加载过程:
使用该类若该类还未被加载到内存中则通过以下对该类进行初始化:
1).类的加载(将类的claaa文件读入内存,并创建一个java.lang.Class对象,由类加载器完成)
2).类的连接(将类的二进制数据合并到JRE中)
3).类的初始化(JVM负责对类进行初始化)
类的加载器ClassLoader
ClassLoader loader1=ClassLoader.getSystemClassLoader();
//app 系统类加载器 System Classloader
ClassLoader loader2=loader1.getParent();
//ext扩展类加载器 Extension Classloader
ClassLoader loader3=loader2.getParent();
//null引导类加载器 ,加载核心类库,无法直接获取 Bootstap Classloader
Class clazz1=Person.class;
ClassLoader loader4=clazz1.getClassLoader();
//系统类加载器
String className="java.lang.Object";
Class clazz2=Class.forName(className);
ClassLoader loader5=clazz2.getClassLoader();
//引导类加载器,核心类String .....
类加载器的运用
从包里获取配置文件
ClassLoader loader=this.getClass().getClassLoader();
InputStream is=loader.getResourceAsStream("com\\atBedroom\\java\\jdbc.properties");
Properties pros=new Properties();
pros.load(is);
String name=pros.getProperty("user");
System.out.println(name);
从工程里获取配置文件
FileInputStream is1=new FileInputStream(new File("jabc1.properties"));
Properties pros1=new Properties();
pros.load(is1);
String name1=pros1.getProperty("user");
6.创建Class的实例
1)过程:创建一个类,通过编译(java.exe),生成对应的.class文件,之后使用java.exe加载(JVM 的类加载器完成的)此.class文件,此.class文件加载到内存后就是一个运行时类,存在缓存区,那么这个运 行时类本身就是一个Class的实例。
1)过程:创建一个类,通过编译(java.exe),生成对应的.class文件,之后使用java.exe加载(JVM 的类加载器完成的)此.class文件,此.class文件加载到内存后就是一个运行时类,存在缓存区,那么这个运 行时类本身就是一个Class的实例。
2)Class的一个对象对应着一个运行时类,相当于一个运行时类本身就充当了Class的一个实例。
3)每个运行时类只加载一次。
实例化Class的方法
//1.调用运行时类本身的.class属性
Class clazz1=Person.class;
System.out.println(clazz1.getName());
//2.通过运行时类的对象获取
Person p=new Person();
Class clazz3=p.getClass();
//3.通过Class的静态方法获取,反射的动态性
String className="com.atBedroom.java.Person";
Class clazz4=Class.forName(className);
//clazz4.newInstance();
//4.通过类的加载器
ClassLoader classLoader=this.getClass().getClassLoader();
Class clazz5=classLoader.loadClass(className);
7.有了class实例后
应用一:创建对应的运行时类的对象(调用class对象的newInstance()方法)
要求 :该类必须有无参的构造器; 类的构造器的访问权限要足够
Class clazz=Animal.class;
Constructor cons=clazz.getDeclaredConstructor(String.class,Integer.class);
Animal a=(Animal)cons.newInstance("Tom",10);
Class clazz=Class.forName("com.atBedroom.Animal");
Object obj=clazz.newInstance();
Animal a=(Animal)obj;
应用二:获取对应的运行时类的完整的类的结构(属性、方法、构造器、包、父类、接口、泛型、注解、异常、内部类)
属性:
1)获取到申明为public的属性及其父类中申明为public的属性
Class clazz=Person.class;
Field[] fields=clazz.getFields();
for(int i=0;i<fields.length;i++){
System.out.println(fields[i]);
}
2)获取到运行时类本身所有属性
Field[] fields1=clazz.getDeclaredFields();//获取到运行时类本身所有属性
for(Field f:fields1){
System.out.println(f.getName());
}
3)获取每个属性权限修饰符
for(Field f:fields1){
//获取每个属性权限修饰符
int i=f.getModifiers();//public1,private2,....
String str=Modifier.toString(i);
System.out.print(str+" ");
}
4)获取属性的类型
Class type=f.getType();
System.out.print(type.getName()+" ");
f.getName();
方法:
1)获取运行时类及其父类public的方法
Class clazz=Person.class;
Method[] m1=clazz.getMethods();
for(Method m:m1){
System.out.println(m);
}
Method[] m2=clazz.getDeclaredMethods();
3)权限修饰符
String str=Modifier.toString(m.getModifiers());
4)返回值类型
Class returnType=m.getReturnType();
System.out.println(returnType.getName()+" ");
5)形参列表
Class[] params=m.getParameterTypes();
for(Class p:params){
System.out.println(p.getName()+"arg-");
}
6)方法名
m.getName();
7)异常类型
Class[] exps=m.getExceptionTypes();
8)构造器
public void test2() throws Exception{
String className="com.atBeedroom.java.Person";
Class clazz=Class.forName(className);
Constructor[] constructors=clazz.getDeclaredConstructors();
}
1)获取注解
public void test3(){
Class clazz =Person.class;
Annotation[] anns=clazz.getAnnotations();
}
2)所在包
public void test2(){
Class clazz =Person.class;
Package pack=clazz.getPackage();
}
3)获取实现的接口
public void test1(){
Class clazz =Person.class;
Class[] interfaces=clazz.getInterfaces();
}
4)获取父类的泛型
public void test(){
Class clazz =Person.class;
Type type1=clazz.getGenericSuperclass();
ParameterizedType param=(ParameterizedType)type1;
Type[] ars=param.getActualTypeArguments();
System.out.println((((Class) ars[0]).getName()));
}
应用三:调用对应的运行时类中指定的结构(指定的属性、方法、构造器)
调用指定属性
//调用public的指定属性
Class clazz=Person.class;
Field name=clazz.getField("name");//获取属性
Person p=(Person) clazz.newInstance();//创建对象
name.set(p,"caiyuejiao");//给指定属性赋值
//调用指定属性
Field age=clazz.getDeclaredField("age");
age.setAccessible(true);//设置为可访问
age.set(p,19);
Class clazz=Person.class;
//获取public方法 getMethod(String methodName,Class...params)
Method m1=clazz.getMethod("show");
Person p=(Person) clazz.newInstance();
//invoke(Object obj,Object...obj)
Object returnVal=m1.invoke(p);
System.out.println(returnVal);
Method m2=clazz.getMethod("toString");
Object returnVal1=m2.invoke(p);
System.out.println(returnVal1);
//静态方法的调用
Method m3=clazz.getMethod("info");
m3.invoke(Person.class);
Method m4=clazz.getDeclaredMethod("display",String.class,Integer.class);
m4.setAccessible(true);
Object value=m4.invoke(p,"CHN",10);
调用运行时类空参构造器
public void test1() throws Exception{
String className="com.atBeedroom.java.Person";
Class clazz=Class.forName(className);
Object obj=clazz.newInstance();//调用运行时类空参构造器
Person p=(Person)obj;
}
调用指定构造器
public void test3() throws Exception{
String className="com.atBedroom.java.Person";
Class clazz=Class.forName(className);
Constructor cons=clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p=(Person)cons.newInstance("caiyuejiao",19);
}
1:代理设计模式原理:使用一个代理将对象包装起来,用该代理对象取代原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
1)动态代理:在程序运行时,根据被代理类及其实现的接口动态创建一个代理类,当调用代理类实现抽样方法是实际上执行的是被代理类同样的方法的调用,客户通过代理类来调用其他对象的方法,并在程序运行时根据需要创建目标类的代理对象
使用场合:调试 远程方法调用
涉及:提供一个实现了InvoactionHandler接口实现类,并重写invoke()方法。
Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),h);
obj:被代理类对象 h:实现类InvocationHandler接口的实现类的对象
2)静态代理:代理类和目标对象的类都是在编译期间确定下来的,每一个代理类只能为一个接口服务,被代理类与代理类同时实现相应的一套接口,通过被代理的对象调用重写接口方法时,实际上执行的是被代理类的同样方法的调用。
静态代理模式
package com.atBedroom1;
//静态代理模式
//接口
interface ClothFactory{
void productCloth();
}
//被代理类
class NickClothFactory implements ClothFactory{
public void productCloth(){
System.out.println("Nick衣服");
}
}
//代理类
class ProxyFactory implements ClothFactory{
ClothFactory cf;//创建代理类对象时,实际传入一个被代理类的对象
public ProxyFactory(ClothFactory cf){
this.cf=cf;
}
public void productCloth() {
// TODO Auto-generated method stub
System.out.println("执行代理");
cf.productCloth();//代理类开始执行
}
}
public class testClothProduct {
public static void main(String[] args){
NickClothFactory nick=new NickClothFactory();//创建被代理类对象
ProxyFactory proxy=new ProxyFactory(nick);//创建代理类对象
proxy.productCloth();//执行代理 Nick衣服
}
}
动态代理
package com.atBedroom1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理的使用 反射式动态语言的关键
interface Subject{
void action();
}
//被代理类
class RealSubject implements Subject{
public void action(){
System.out.println("我是被代理类");
}
}
class MyInvocationHandler implements InvocationHandler{
Object obj;//实现了接口的被代理类对象的申明
//给被代理类的对象实例化 返回一个代理类的对象
public Object blind(Object obj){
this.obj=obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
}
//当通过被代理类的对象发起对被重写的方法的调用时,都会转换为对invoke方法的调用
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//mehod方法的返回值是returnVal
Object returnVal=method.invoke(obj,args);
return returnVal;
}
}
public class testProxy {
public static void main(String[] args){
//被代理类对象
RealSubject real=new RealSubject();
//创建一个实现了InvocationHandler 接口的类的对象
MyInvocationHandler handler=new MyInvocationHandler();
//调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类对象
Object obj=handler.blind(real);
//此时的sub就是代理类对象
Subject sub=(Subject)obj;
//转到对InvocationHandler接口的实现类的invoke()方法的调用
sub.action();//我是被代理类
//另一个例子
NickClothFactory nick=new NickClothFactory();
ClothFactory proxyCloth=(ClothFactory)handler.blind(nick);//代理类对象
proxyCloth.productCloth(); //Nick衣服
}
}
AOP
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Human{
void info();
void fly();
}
class SuperMan implements Human{
public void info() {
System.out.println("我是超人!");
}
public void fly() {
System.out.println("我相信我会飞!");
}
}
class HumanUtil{
public void method1(){
System.out.println("方法一");
}
public void method2(){
System.out.println("方法二");
}
}
class MyInvocationHandler implements InvocationHandler{
Object obj;//被代理类对象的申明
public void setObject(Object obj){
this.obj=obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
HumanUtil h=new HumanUtil();
h.method1();
Object returnVal=method.invoke(obj,args);
h.method2();
return returnVal;
}
}
//动态创建一个代理类对象
class MyProxy{
public static Object getProxyInstance(Object obj){
MyInvocationHandler handler=new MyInvocationHandler();
handler.setObject(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),handler);
}
}
public class testAOP {
public static void main(String[] args){
SuperMan man=new SuperMan();
Object obj=MyProxy.getProxyInstance(man);
Human hu=(Human)obj;
hu.info();
System.out.println();
hu.fly();
}
}
宋讲师笔记