JavaDay19-动态代理、反射、注解
一、动态代理
1.1 代理的基本概念
1、代理可以无侵入式的给对象增强其他的功能
2、代理里面是对象需要被代理的方法
3、对象和代理需要实现同一个接口,接口中是被代理的所有方法
//动态代理--测试类
public class Test {
public static void main(String[] args) {
Star star = new Star("鸡哥");
StarProxy starProxy = ProxyUtil.CreatProxy(star);
String s = starProxy.Sing("只因你太美");
System.out.println(s);
}
}
//被代理的对象
public class Star implements StarProxy{
private String name;
public Star() {
}
public Star(String name) {
this.name = name;
}
//被代理的方法之一:唱歌
@Override
public String Sing(String name){
System.out.println(this.name+"正在唱"+name+"...");
return "谢谢";
}
//被代理的方法:跳舞
@Override
public void Dance(){
System.out.println(this.name+"正在跳舞...");
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
public String toString() {
return "Star{name = " + name + "}";
}
}
//被代理的对象中的方法
public interface StarProxy {
//被代理的方法之一:唱歌
public abstract String Sing(String name);
//被代理的方法:跳舞
public abstract void Dance();
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 类的作用:
* 创建代理,代理star对象中的方法,方法放在了StarProxy这个接口中
*/
public class ProxyUtil {
/**
* 方法的作用:
* 创建Star对象的代理
* 形参:
* Star对象
* 返回值:
* 给明星创建的代理--Star对象的接口
*/
public static StarProxy CreatProxy(Star star){
/*
java.long.reflect.Proxy类提供了为对象产生代理对象的方法:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
参数一:指定类加载器,加载生成的代理类
参数二:接口数组,需要代理的方法
参数三:指定生成的代理要干什么事情
*/
StarProxy starp = (StarProxy) java.lang.reflect.Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),//使用当前字节码文件的类加载器,将代理对象加载到内存中
new Class[]{StarProxy.class},//将所有需要代理的方法的字节码文件放到字节码文件数组中
new InvocationHandler(){//代理需要做的事情
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 参数一:代理的对象
* 参数二:要运行的方法
* 参数三:调用要运行的方法时,要传递的实参
*/
if ("Sing".equals(method.getName())){
System.out.println("准备话筒,收钱");
}else if("Dance".equals(method.getName())){
System.out.println("准备场地,收钱");
}
return method.invoke(star,args);
}
});
return starp;
}
}
1.2 实现动态代理的步骤总结:
1、创建JavaBean类,这个类就是需要被代理的对象,需要实现代理接口
2、创建代理接口,里面是需要被代理的方法
3、创建代理类,
- 代理类中只定义了一个方法:createProxy(),
- 此方法的参数是需要被代理的对象(即1中创建的JavaBean类)
- 返回值是代理接口
- createProxy()内部的主体逻辑是:
- 调用Proxy.newProxyInstance()方法
- 返回代理接口的对象
- createProxy()内部的主体逻辑是:
4、Proxy.newProxyInstance()方法的三个参数:
- 参数一:类加载器--代理类的类加载器
- 参数二:代理接口的字节码文件(数组)
- 参数三:InvocationHandler接口的实现类对象
- 需要重写接口的invoke方法,
- 方法内有三个参数,不需要修改,但要知道什么意思,
- 参数一:代理的对象,即创建的JavaBean类
- 参数二:代理接口中的方法
- 参数三:代理接口中的方法需要传递的参数
- 方法体是代理类需要做的事,
- 返回值是JavaBean对象中被代理的方法的返回值。(此例中是bigStar中Sing的返回值)。
Proxy.newProxyInstance()方法的返回值是代理接口的对象。
5、创建测试类:
- 第一步:创建JavaBean对象
- 第二步:创建代理--调用创建代理的方法
- 第三步:通过代理调用JavaBean对象的方法
二、反射
2.1 概念
反射允许对成员变量、成员方法、构造方法的所有信息进行访问
2.2 如何通过反射获取上述信息
- 获取
- class对象--->成员变量Field、成员方法Method、构造方法Constructor
- 解剖
- 成员变量>>>修饰符、名字、类型>>>赋值/获取值
- 成员方法>>>修饰符、名字、形参、抛出的异常、注解、方法体>>>获取返回值
- 构造方法>>>修饰符、名字、形参>>>创建对象
2.3 获取class对象的三种方法
- Class.forName()------源代码阶段:编写.java文件
- 类名.class()------加载阶段:将.class文件加载到内存
- 对象.getClass()------运行阶段:在内存中创建对象
//练习获取class对象的三种方法
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
Student student = new Student();
//第一种方式:Class.forName(全类名=包名+类名)
//最常用
Class class1 = Class.forName("reflectionDemo01.Student");
System.out.println(class1);
//第二种方式:类名.class
//一般当做参数进行传递
Class class2 = Student.class;
System.out.println(class2);
//第三种方式:对象名.class
//当已经有了对象时才可以使用
Class class3 = student.getClass();
System.out.println(class3);
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
2.4 通过获取的class对象获取构造方法
- 获取public修饰的构造方法--getConstructors()
- 获取所有构造方法--getDeclaredConstructors()
- 获取某一个构造方法(参数一致即可)--getConstructor(String.class)、getDeclaredConstructor(int.class)
通过class对象获取了构造方法以后,可以:- 获取构造方法的权限修饰符--getModifiers()
- 获取构造方法的参数--getParameters()
- 创建对象--newInstance()、setAccessible(true)
2.5 通过获取的class对象获取成员变量
-
获取所有public修饰的成员变量--getFields()
-
获取所有的成员变量--getDeclaredFields()
-
获取单个成员变量--getField("name")、getDeclaredField("name")
通过class对象获取了成员变量以后,可以:
- 获取成员变量的权限修饰符--getModifiers()
- 获取成员变量名--getName()
- 获取成员变量的数据类型--getType()
- 获取成员变量记录的值--get(对象)
- 修改变量记录的值--set(对象,"需要修改的值")
2.6 通过获取的class对象获取成员方法
-
获取所有public修饰的成员方法--getMethods()
-
获取所有的成员方法--getDeclaredMethods()
-
获取单个成员方法--getMethods("方法名",参数类型)、getDeclaredMethods("方法名",参数类型)
通过class对象获取了成员方法以后,可以:
- 获取成员方法的权限修饰符--getModifiers()
- 获取成员方法的名字--getName()
- 获取成员方法的参数--getParameters()
- 获取成员方法抛出的异常--getExceptionTypes()
- 运行获取出来的方法--invoke(对象,方法实参)
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
//通过获取的class对象获取构造方法
public class Demo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class stuClass = Class.forName("reflectionDemo02.Student");
//获取所有public的构造
Constructor[] cons = stuClass.getConstructors();
System.out.println("所有public的构造方法:");
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("============================================================");
//获取所有构造
Constructor[] cons1 = stuClass.getDeclaredConstructors();
System.out.println("所有的构造方法(包括private、protected):");
for (Constructor constructor : cons1) {
System.out.println(constructor);
}
System.out.println("============================================================");
//获取某一个构造,参数类型要与构造一致
Constructor consString = stuClass.getConstructor(String.class);
System.out.println("参数为String name的构造方法:");
System.out.println(consString);
System.out.println("============================================================");
//getDeclaredConstructor此方法获取的私有构造只能看 不能创建对象 必须setAccessible(true)
Constructor consInt = stuClass.getDeclaredConstructor(int.class);
System.out.println("参数为Int age的构造方法:");
System.out.println(consInt);
System.out.println("============================================================");
//获取构造方法的权限修饰符
int modifiers = consInt.getModifiers();
System.out.println("参数为Int age的构造方法的权限修饰符编号:");
System.out.println(modifiers);//返回权限修饰符对应的数字
System.out.println("============================================================");
//获取构造方法的参数
Parameter[] parameters = consInt.getParameters();
System.out.println("参数为Int age的构造方法的参数:");
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
System.out.println("============================================================");
//通过获取的构造方法创建对象--构造方法权限为public
Student stu1 = (Student) consString.newInstance("小刘");
System.out.println("用public修饰的构造方法创建对象:");
System.out.println(stu1);
System.out.println("============================================================");
//通过获取的构造方法创建对象--构造方法权限为private
consInt.setAccessible(true);//临时取消私有权限 暴力反射
Student stu2 = (Student) consInt.newInstance(18);
System.out.println("用private修饰的构造方法创建对象:");
System.out.println(stu2);
}
}
import java.lang.reflect.Field;
//通过获取的class对象获取成员变量
public class Demo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> stuClass = Class.forName("reflectionDemo02.Student");
Field[] fields = stuClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
Field[] declaredFields = stuClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field name = stuClass.getDeclaredField("name");
System.out.println(name);
System.out.println(name.getModifiers());
System.out.println(name.getName());//获取变量的名字
System.out.println(name.getType());//获取变量的数据类型
//获取变量中存储的值
Student s = new Student("zhangsa", 28);
name.setAccessible(true);
System.out.println(name.get(s));//输出:zhangsa
name.set(s,"lisi");//修改name中存储的值
System.out.println(s);
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
//通过获取的class对象获取成员方法
public class Demo04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> clazz = Class.forName("reflectionDemo02.Student");
Method[] methods = clazz.getMethods();//同时能够获得父类中所有的公共方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("========================================================");
Method[] methods2 = clazz.getDeclaredMethods();//不能获取父类的,但能获取本类中私有的方法
for (Method method : methods2) {
System.out.println(method);
}
System.out.println("========================================================");
Method eat = clazz.getDeclaredMethod("eat", String.class);
System.out.println(eat.getName());
System.out.println(eat.getModifiers());
Parameter[] parameters = eat.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
for (Class<?> exceptionType : eat.getExceptionTypes()) {
System.out.println(exceptionType);
}
Student s = new Student();
eat.setAccessible(true);
eat.invoke(s,"螺蛳粉");//参数一:对象;参数二:实参
}
}
public class Student {
private String name;
private int age;
//无参构造
public Student() {
}
//name构造
public Student(String name) {
this.name = name;
}
//age构造
private Student(int age) {
this.age = age;
}
//所有参数的构造
protected Student(String name, int age) {
this.name = name;
this.age = age;
}
//sleep()
public void sleep(){
System.out.println("Sleeping...");
}
//eat()
private void eat(String something){
System.out.println("Eating"+something);
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
三、注解 Annotation
3.1 内置注解
1、@Override--用于修饰方法,表示一个方法重写父类方法
2、@Deprecated--用于修饰方法、属性、类,表示不鼓励使用这样的元素,因为它很危险或者存在更好的选择
3、@SuppressWarning--用于抑制编译时的警告信息,需要添加参数(all、unchecked等)
3.2 元注解 meta-annotation
用于对其他注解做说明
1、@Target--用于描述注解的适用范围
2、@Retention--描述注解的生命周期(SOURCE<CLASS<RUNTIME)
3、@Document--说明该注解将被包含在javadoc中
4、@Inherited--说明该注解可以被子类继承
3.3 自定义注解
1、定义方式:@interface
2、书写方式
@Target({ElementType.METHOD})//表示该注解可以用在方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{
String name() default "";//value是变量,不写的话默认是0
}
3、使用方式:
@MyAnnotation(name="wan")

浙公网安备 33010602011771号