1.
{
class Perosn(){}
通过反射创建运行时类的对象的方式
1.new + 构造器(Person();)
通过反射实现
2.clazz.newInstance();
3.类名.class.getDeclaredConstructors().newInstance();
获取Class的实例
1.Person.class;
2.Person p = new Perosn();
p.getClass();
构建Class的一些结构
3.调用Class中的静态方法
Class.forName("运行时类的相对目录\(根目录)")
}
一:关于反射的理解:Reflection(反射)时被视为动态语言的关键,反射机制允许程序执行期间借助与Reflection API取得任何类的内部信息,
并能直接操作任意对象的内部属性及方法
二:框架= 反射+注解 +设计模式
三:反射的动态性:FanShe\src\Text\NewInstanceTest 中的例题。
四:反射机制提供的功能
2
关于java。long.Class的理解 1.类的加载过程: 程序经过java.exe命令以后,会生成一个或多个字节码文件(.Class)结尾。 接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件 加载到内存中。此过程 就称为类的加载。加载到内存中的类,我们就称为运行时类,此 运行时类,就作为Class的一个实例。 2.换句话说,Class的实例就对应着一个运行时类。 3.加载到内存中的运行时类,会在缓存区中缓存一定的时间,我们可以通过不同的方式来获取 此运行时的类。
3.类的加载器(classloader)
1.类加载器的作用
将class文件字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生产一个这个类的java.lang.Class对象,作为方法区中类数据的访问入口
2.使用classloader加载SRC下的文件
Properties ps = new Properties(); //读取配置文件的方式一 此时的文件默认在当前的module下。 // FileInputStream fis = new FileInputStream("L3.properties"); // ps.load(fis); //读取配置文件的方式二;使用ClassLoader //配置文件默认为:当前module的src下 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("L2.properties"); ps.load(is); String name = ps.getProperty("name"); String password = ps.getProperty("password"); System.out.println("name = "+name+" password = "+password); 4.
1.创建运行时类的对象
//newInstance();调用此方法创建对应的运行时类的对象、内部调用了运行时类的空参构造器 // 要想此方法能正常创建运行时类的对象,要求: // 1.运行时类必须有空参构造器 // 2.访问权限要够。通常为public
// 在javabean中要求提供一个空参构造器。1,便于通过反射,创建运行时类的对象, // 2,便于子类继承父类时,默认调用super()时保证父类有此构造器
Class<Person> clazz = Person.class; // Person o = clazz.newInstance(); // 此方法已经被getDeclaredConstructor().newInstance();替代 Person person = Person.class.getDeclaredConstructor().newInstance(); System.out.println(person);
2.获取运行时类中的一些结构
————————————————————————————
获取构造器结构:
public void test() {
Class clazz = Person.class;
//getConstructors()获取当前运行时类的所有public的构造器
Constructor[] constructor = clazz.getConstructors();
for (Constructor c: constructor) {
System.out.println(c);
}
//getDeclaredConstructors()获取当前运行时类的所有的构造器
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor c: constructors) {
System.out.println(c);
}
}
//获取运行时类的父类
@Test
public void test2() {
Class clazz = Person.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
//获取带泛型的父类
Type type = clazz.getGenericSuperclass();
System.out.println(type);
}
/*
获取带泛型的父类的泛型
*/
@Test
public void test3() {
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
ParameterizedType parmeType = (ParameterizedType) genericSuperclass;
//获取泛型类型
Type[] actualTypeArguments = parmeType.getActualTypeArguments();
System.out.println(((Class)actualTypeArguments[0]).getName());
}
————————————————————
3.获取指定结构
@Test
public void test() throws Exception {
//获取运行时类的对象
// Person person = Person.class.getDeclaredConstructor().newInstance();
Class aClass = Person.class;
Person o = (Person) aClass.newInstance();
//获取指定属性
Field id = aClass.getField("age");
//year获取静态属性
Field year = aClass.getDeclaredField("year");
/*
设置当前属性的值
set():参数1:指明设置那个对象的属性 参数2:将此属性值设置为多少
setAccessible(true);保证当前属性是可访问的
*/
year.setAccessible(true);
year.set(null,2021);
id.set(o,100111);
/*
获取当前属性的值
get():参数1:获取那个对象的当前属性值
*/
int o1 = (int) id.get(o);
System.out.println(o1);
System.out.println(year.get(null));
}
/*
如何操作运行时类中的指定的属性*
*/
@Test
public void test2() throws Exception {
Class personClass = Person.class;
//获取运行时类的对象
Object o = personClass.newInstance();
//getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
Field field = personClass.getDeclaredField("sex");
//确保当前属性时可访问的
field.setAccessible(true);
//获取,设置指定对象的此属性值
field.set(o,"男");
Object o1 = field.get(o);
System.out.println(o1);
}
/*
如何操作运行时类中的指定的方法*
*/
@Test
public void test3() throws Exception {
Class personClass = Person.class;
//获取运行时类的对象
Person p = (Person) personClass.newInstance();
/*
获取指定的方法
getDeclaredMethod(): 参数1 :获取指定方法的方法名 参数2:指定方法中的形参列表。
*/
Method show = personClass.getDeclaredMethod("getCH", String.class);
//保证当前的方法是可访问的
show.setAccessible(true);
/*
调用invoke():参数1:方法的调用者(运行时类的对象),参数2给方法的形参赋值。
invoke方法的返回值即为对应类中调用方法的返回值
*/
Object invoke = show.invoke(p, "中国");
System.out.println(invoke);
System.out.println("———————————调用静态的方法———————————");
// public static void LXD()
Method lxd = personClass.getDeclaredMethod("LXD");
lxd.setAccessible(true);
//invoke()方法有一个返回值,如果调用的运行时类的方法中无返回值则返回null
// Object invoke1 = lxd.invoke(Person.class);
Object invoke1 = lxd.invoke(null);
System.out.println(invoke1);//null
5。代理模式与动态代理
代理设计模式的原理:
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
动态代理使用场合:
调试
远程方法调用
动态代理相比于静态代理的优点:
抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。
5.1静态代理举例:
interface ClothFactory {
public void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory Cloth;
public ProxyClothFactory(ClothFactory Cloth){
this.Cloth = Cloth;
}
@Override
public void produceCloth() {
System.out.println("我是代理类做一些准备工作");
Cloth.produceCloth();
System.out.println("代理类完成了代理操作");
}
}
//被代理类
class ProxyPerson implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("我是被代理类,");
}
}
public class StaticDaiLiTest {
public static void main(String[] args) {
//创建被代理类对象
ProxyPerson p = new ProxyPerson();
//创建代理类对象
ProxyClothFactory factory = new ProxyClothFactory(p);
factory.produceCloth();
}
}
5.2动态代理举例
package DaiLi;
/*
动态代理
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Human{
public String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "我是No:1";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃"+food);
}
}
/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
问题二:当通过代理类的对象调用方法A时,如何动态的去调用被代理类中的同名方法A。
*/
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){//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;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method:即为代理类对象调用的方法,此方法也作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object returnValue = method.invoke(obj, args);
//代理类方法的返回值就作为当前类中的invoke方法的返回值。
return returnValue;
}
}
public class RunDaiLiTest {
public static void main(String[] args) {
SuperMan sup = new SuperMan();
//proxyInstance;代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(sup);
//当通过代理类对象调用方法时,会自动调用被代理类中同名的方法
System.out.println(proxyInstance.getBelief());
proxyInstance.eat("西红柿");
System.out.println("***************");
ProxyPerson proxyPerson = new ProxyPerson();
ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(proxyPerson);
proxyInstance1.produceCloth();
}
}
5.3AOP
前面介绍的Proxy和InvocationHandler,很难看出这种动态代理的优势,下面介绍一种更实用的动态代理机制
- 改进后的说明:代码段1、代码段2、代码段3和深色代码段分离开了,但代码段1、2、3又和一个特定的方法A耦合了!最理想的效果是:代码块1、2、3既可以执行方法A,又无须在程序中以硬编码的方式直接调用深色代码的方法。
- 使用Proxy生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有太大的意义。通常都是为指定的目标对象生成动态代理
- 这种动态代理在AOP中被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理中的方法与目标对象的方法存在差异:AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理。
图示
实例一:
package DaiLi;
/*
动态代理
*/
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Human{
public String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "我是No:1";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃"+food);
}
}
//动态代理AOP模式举例
class HumanUtil{
public void method1(){
System.out.println("——————————————————通用方法1——————————————————");
}
public void method2(){
System.out.println("——————————————————通用方法2——————————————————");
}
}
/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
问题二:当通过代理类的对象调用方法A时,如何动态的去调用被代理类中的同名方法A。
*/
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){//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;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理AOP模式举例
HumanUtil hum = new HumanUtil();
hum.method1();
//method:即为代理类对象调用的方法,此方法也作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object returnValue = method.invoke(obj, args);
//动态代理AOP模式举例
hum.method2();
//代理类方法的返回值就作为当前类中的invoke方法的返回值。
return returnValue;
}
}
public class RunDaiLiTest {
public static void main(String[] args) {
SuperMan sup = new SuperMan();
//proxyInstance;代理类的对象
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(sup);
//当通过代理类对象调用方法时,会自动调用被代理类中同名的方法
System.out.println(proxyInstance.getBelief());
proxyInstance.eat("西红柿");
System.out.println("***************");
ProxyPerson proxyPerson = new ProxyPerson();
ClothFactory proxyInstance1 = (ClothFactory) ProxyFactory.getProxyInstance(proxyPerson);
proxyInstance1.produceCloth();
}
}