1,Servlet3.0
package t1.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "Demo01Servlet",
urlPatterns = "/demo01",
loadOnStartup = 1,
initParams = @WebInitParam(name="username",value="root")
)
public class Demo01Servlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("Demo01Servlet init");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Demo01Servlet处理请求");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2,类加载图例
3,反射
获取Class对象的三种方式
这里clazz01,clazz02,clazz03都是同一个对象–同一个类的Class对象
4运用反射的课堂案例
写程序过程中为了避免耦合度太高,可以通过工厂模式降低耦合,结合使用多态,使可拓展性增强,运用反射,又可以减少代码。用水果工厂的案例来模拟一下;
创建Fruit父类,使用继承,解决Apple类、Banana类的代码复用性
package t3.bean;
public class Fruit {
private String fruitName;
public Fruit(){}
public Fruit(String fruitName) {
this.fruitName = fruitName;
}
public String getFruitName() {
return fruitName;
}
public void setFruitName(String fruitName) {
this.fruitName = fruitName;
}
@Override
public String toString() {
return "Fruit{" +
"fruitName='" + fruitName + '\'' +
'}';
}
}
package t3.bean;
public class Apple extends Fruit{
private int height;
public Apple() {
}
public Apple(String fruiName,int height) {
super(fruiName);
this.height = height;
}
}
package t3.bean;
public class Banana extends Fruit {
private int width;
public Banana() {
}
public Banana(String fruitName, int width) {
super(fruitName);
this.width = width;
}
}
使用工厂模式,解决Banana、Apple和其他模块耦合较高
package t3.factory;
import t3.bean.Fruit;
public class FruitFactory {
public static Fruit getFruit(String fruitName) throws Exception {
return (Fruit) Class.forName(fruitName).newInstance();
}
}
使用反射机制,* * 解决工厂的getFruit方法中if…else代码过多
package t3.demo;
import t3.bean.Apple;
import t3.bean.Banana;
import t3.bean.Fruit;
import t3.factory.FruitFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Apple apple = (Apple) FruitFactory.getFruit("t3.bean.Apple");
Banana banana = (Banana)FruitFactory.getFruit("t3.bean.Banana");
}
}
5,反射操作构造器
package t3.demo;
import java.lang.reflect.Constructor;
/**
* 反射操作构造方法
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
//获取User类对应的Class对象
Class<?> clazz = Class.forName("t3.bean.User");
//获取无参构造方法对象
Constructor<?> c1 = clazz.getConstructor();
//使用无参创建User类对象
Object obj1 = c1.newInstance();
System.out.println(obj1);
System.out.println("---------------");
//获取User类对应的有参构造方法对象
Constructor<?> c2 = clazz.getConstructor(Integer.class, String.class, String.class);
//使用有参创建User对象
Object obj2 = c2.newInstance(1, "小明", "root");
System.out.println(obj2);
System.out.println("---------------");
//通过该方法可以获取私有构造方法对象
Constructor<?> c3 = clazz.getDeclaredConstructor(String.class, String.class);
//暴力反射,让私有构造器对象可以被外界访问
c3.setAccessible(true);
Object obj3 = c3.newInstance("小王", "root123");
System.out.println(obj3);
}
}
6,反射操作成员变量
package t3.demo;
import t3.bean.User;
import java.lang.reflect.Field;
/**
* 反射操作成员变量
*/
public class Demo03 {
public static void main(String[] args) throws Exception {
//获取User类的Class对象
Class<User> clazz = User.class;
User user = clazz.newInstance();
//操作public修饰的成员变量
Field idField = clazz.getField("id");
//设置该成员变量值
//obj:需要设置的对象
//value:需要设置的值
//给user对象的id属性设置值为250
idField.set(user,250);
System.out.println(user);
//获取该成员变量值
Object idValue = idField.get(user);
System.out.println(idValue);
System.out.println("---------------------");
//操作非public修饰的成员变量
Field usernameField = clazz.getDeclaredField("username");
usernameField.setAccessible(true);
usernameField.set(user,"小王");
System.out.println(user);
Object usernameValue = usernameField.get(user);
System.out.println(usernameValue);
}
}
**7,反射操作成员方法
package t3.demo;
import t3.bean.User;
import java.lang.reflect.Method;
public class Demo04 {
public static void main(String[] args) throws Exception {
//获取User类的Class对象
Class<User> clazz = User.class;
User user = clazz.newInstance();
//获取public修饰的成员方法
Method method01 = clazz.getMethod("setPassword", String.class);
//使用方法对象
//obj:哪个对象在执行该方法
//args:方法执行时所需的参数值
method01.invoke(user,"123456");
System.out.println(user);
System.out.println("--------------");
//操作非public修饰的成员方法
Method method02 = clazz.getDeclaredMethod("show");
method02.setAccessible(true);
Object result = method02.invoke(user);
//invoke方法返回值,就是操作方法的返回值
System.out.println(result);
}
}
反射越过泛型检查
package t3.demo;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Demo05 {
public static void main(String[] args) throws Exception {
//创建List集合对象
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);
//泛型只在编译期有效!!!
//反射越过泛型检查
//反射可以在程序运行时,动态地调用List中的add方法去添加元素
Class<? extends List> clazz = list.getClass();
Method add = clazz.getDeclaredMethod("add", Object.class);
add.setAccessible(true);
Object result = add.invoke(list, "hello , generic type !");
System.out.println(result);
System.out.println(list);
}
}
9,反射通用方法案例
给指定对象的指定字段设置指定值
package t3.demo;
import t3.bean.User;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Demo06 {
public static void main(String[] args) throws Exception {
User user = new User();
setValue(user,"id" , 123);
System.out.println(user);
}
/**
* 给指定对象的指定属性设置指定值
* @param obj : 指定对象
* @param fieldName : 指定属性
* @param value : 指定值
*/
public static void setValue(Object obj , String fieldName , Object value) throws Exception {
Class<?> clazz = obj.getClass();
//根据属性名称获取对应的set方法名称
// String methodName = "set" + "U" + "sername";(0,1)表示从下标0开始的第一个,(1)表示下标1开始往后的内容
String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
Field field = clazz.getDeclaredField(fieldName);
//获取字段的数据类型
Class<?> fieldType = field.getType();
//获取到set方法对象
Method method = clazz.getMethod(methodName, fieldType);
//执行set方法
method.invoke(obj , value);
}
}
10,反射结合配置文件
编写bean.properties,配置对象的唯一标识及对象的全类名,根据这段配置创建一个对象
读取配置文件
bean01=t3.bean.User
bean02=t3.bean.Banana
根据配置文件中的className生成对象
package t3.demo;
import java.io.InputStream;
import java.util.Properties;
public class Demo07 {
public static void main(String[] args)throws Exception{
//需求:编写bean.properties,配置对象的唯一标识及对象的全类名,根据这段配置创建一个对象
Properties properties = new Properties();
//将bean.properties中的数据存储到inputStream中
InputStream inputStream = Demo07.class.getClassLoader().getResourceAsStream("bean.properties");
//将bean.properties中的数据绑定到了Properties中!
properties.load(inputStream);
//获取全类名
String className = properties.getProperty("bean01");
//根据上述全类名创建了一个对象!
Object obj = Class.forName(className).newInstance();
System.out.println(obj);
String className2 = properties.getProperty("bean02");
Object obj2 = Class.forName(className2).newInstance();
System.out.println(obj2);
}
}
反思水果工厂获取水果对象存在的问题:
com.qfedu.bean.Apple对应的对象
将以上"com.qfedu.bean.Apple"字符串写到java代码中,合适吗?
不合适!!!全类名发生改变了,那你就必须修改java源代码,必须要重新部署项目!
"com.qfedu.bean.Apple"字符串和java程序的耦合性非常高!!
"com.qfedu.bean.Apple"字符串不能放到java代码中,而应该放置到配置文件中!!
仅仅修改配置文件,是不需要重新部署工程的!
这也就是为什么要将"com.mysql.jdbc.Driver"配置到jdbc.properties中!
解耦!!降低耦合!!
总结:
配置文件+工厂模式+反射+注解+xml解析 就是spring框架的核心原理!!!
12,静态代理设计模式–增强被代理类的功能
步骤
- 自定义类实现和被代理类相同的接口
- 在代理类中声明被代理类的对象
- 在代理类的方法中使用被代理类调用方法
package t3.dao;
//1,自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
/**
* 代理类(增强类)
* 完成非必要功能
* 权限校验
* 日志记录
*/
public class UserDaoImplProxy implements UserDao{
//2,在代理类中声明被代理类的引用
private UserDao userDao ;
public UserDaoImplProxy(){
userDao = new UserDaoImpl();
}
@Override
public void addUser() {
//3,在代理类的方法中使用被代理类调用方法
System.out.println("权限校验");
userDao.addUser();
System.out.println("日志记录");
}
@Override
public void deleteUser() {
userDao.deleteUser();
}
@Override
public void updateUser() {
userDao.updateUser();
}
@Override
public void selectUser() {
userDao.selectUser();
}
}
package t3.demo;
import t3.dao.UserDaoImplProxy;
public class Demo08 {
public static void main(String[] args) {
//静态代理设计模式
//实现步骤
//自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
//在代理类中声明被代理类的引用
//在代理类的方法中使用被代理类调用方法
UserDaoImplProxy userDaoImplProxy = new UserDaoImplProxy();
userDaoImplProxy.addUser();
}
}
特点
- 缺点:必须要重写被代理类接口的所有的方法(包括不需要增强的方法,增高了耦合性)
- 作用:增强被代理类的功能
- 特点:可以控制被代理类对象