基础加强
注解 annotation
什么是注解?
注解和接口、类一样都属于数据类型-
注解作用
- 编译检查
- 配置(后期用的多)
- 生成帮助文档
-
注解特点
- 注解可以在 变量、方法和类之上加载
- 注解可以有属性也可以没属性 @Override @Test(timeout=1000)
- 注解的作用范围 (源码、编译期间、运行期间)
- 源码期有效:String类之上 @Author、@Since、@See
作用:使用命令javadoc命令将当前的源码生成帮助文件,可以识别在String类上的相关的注解 - 编译器有效:@Override @Deprecated @Susspresswarning
作用:告诉编译器部分信息 - 运行期间有效:@Test
作用: 当我们在当前代码上以JUnit方式运行时, JUnit会运行方法上包含@Test注解的方法
- 源码期有效:String类之上 @Author、@Since、@See
回顾JDK中出现的三种注解:
@Override、@Deprecated、@Suppresswarning举例
//以下注解的含义是:抑制编译器发生警告信息(如果有变量未使用,未遵循泛型格式错误不报警告)
@SuppressWarnings("unused")
int i = 10;
//以下注解的含义是:抑制编译器发生警告信息(如果有变量未使用,未遵循泛型格式错误不报警告)
@SuppressWarnings({ "unused", "rawtypes" })
List list = new ArrayList();
//以下注解的含义是:声明以下的方法是过时的方法,不建议大家使用
@Deprecated
public void test2()
{
}
- 自定义注解
- 格式:
public @interface 注解名字{
public 属性类型 属性名字1();
public 属性类型 属性名称2() default 默认值;
}
自定义注解属性支持的类型:基本数据类型(4类8种),String,Class,Annotation(注解类型),枚举类型,以及以上类型的一维数组类型
- 注解作用:配置作用
配置:开发的时候部分信息不希望写死在程序中, 例如数据库的用户名和密码,可以将用户名和密码存放在.txt,.properties,.xml文件中, 利用程序来读取文件中的内容
例如: 新建一个类继承HttpServlet 然后给类注解 @WebServlet("/DemoServlet") 那么就不用在web.xml中进行servlet的注册和隐射, 如果你创建的wb框架是3.0版本,那么默认是没有web.xml 都是按照注解来配置的
@WebServlet("/DemoServlet")
@WebInitParam(name="name", value="tom")
public class DemoServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
System.out.println("来了一个请求");
String value = req.getServletContext().getInitParameter("name");
resp.getWriter().write("hello demoServlet:" + value);
}
- 模拟JUnit
- 自定义注解@MyTest,通过原注解@Retention和@Target声明当前注解作用域以及目标对象,如果没有声明,在运行期间是无法获取到注解的信息
// 自定义注解 相当于JUnit@Test
// 定义注解的时候, 需要通过元注解Retention说明此注解是运行时注解(class runtime source)
// 约束注解的宿主是什么类型
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest
{
public int timeout() default -1;
}
- 定义UserDao类,创建四个方法addUser delUser getUser uptUser,在前三个方法上加载注解
public class UserDao
{
@MyTest
public void addUsr()
{
System.out.println("增加用户");
}
@MyTest
public void delUsr()
{
System.out.println("删除用户");
}
@MyTest
public void getUsr()
{
System.out.println("获取用户");
}
public void updateUsr()
{
System.out.println("更新用户");
}
}
- 定义类MyJunit ,模拟JUnit
- 将UserDao.class 文件加载到内存
- 获取到字节码文件所有的方法
- 遍历方法,判断每个方法上是否加载了@MyTest注解,有的话执行这个方法
public class MyJunit
{
public static void main(String[] args) throws Exception
{
// 加载UserDao.class 字节码文件中的方法, 判断哪些方法上有自定义注解@MyTest,若有则执行此方法
// 1. 将UserDao.class 字节码文件加载到内存中, class对象(代表字节码文件在内存中的对象)
try
{
Class clazz = Class.forName("myjava.com.dao.UserDao");
// 2.获取字节码对象上所有的方法, 返回Method数组对象,数组中的每一个元素都代表Method对象(想当于字节码上的每一个方法)
Method[] methods = clazz.getMethods();
for (Method method : methods)
{
if (method.isAnnotationPresent(MyTest.class))
{
method.invoke(new UserDao());
}
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
System.out.println("hello MyJUnit");
}
}
动态代理 解决网站中文编码问题
装饰者模式
- 场景: 二次开发的时候, 无法获取到源码,无法使用继承前提下, 要对已经存在对象上的功能进行封装与增强
- 前提:可以获取到被装饰的对象GoogleCar实现的所有接口
- 实现思路:自定义装饰类实现ICar接口, 为自定义装饰类传递被装饰的对象
- 弊端:如果被实现的接口中的方法过多,装饰类中的方法过多冗余
动态代理模式
- 原理: 通过虚拟机在内存中创建类似MyCar.class文件
- 前提
- 字节码加载器: jdk 有一些程序, 专业将各种字节码文件加载到内存, 这类程序简称为字节码加载器
底层实现过程:利用IO流技术,获取到文件中的数据加载到内存
共同父类:java.lang.ClassLoader
分为三种类型:
引导类加载器 :BootstrapClassLoader 不是类 ClassLoader classLoader = String.class.getClassLoader(); // 由于String.class int.class 等频繁的被加载到内存中 所有用c++加载 所以返回的classloader 是null
扩展类加载器:ExtClassLoader(extension) 类 ClassLoader classLoader2 = sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader();
应用类加载器:AppClassLoader
使用 类.class.getClassLoader()获取加载自己的类加载器。 自己定义的类的加载器都是应用类加载器 System.out.println(TestClassLoader.class.getClassLoader()); - 动态代理解决全站乱码问题
- 使用filter进行请求过滤
- 在post请求上 增加
request.setCharacterEncoding("UTF-8");
- 在get请求下 进行动态代理
HttpServletRequest myreq = (HttpServletRequest) Proxy.newProxyInstance(ServletFilter.class.getClassLoader(),
arg0.getClass().getInterfaces(), new InvocationHandler()
{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object retObj = null;
if (method.getName().equalsIgnoreCase("getParameter"))
{
retObj = method.invoke(request, args);
String val = (String)retObj;
val = new String(val.getBytes("iso-8859-1"), "utf-8");
System.out.println("val:" + val + "hashcode:" + request.hashCode());
return val;
}
else
{
retObj = method.invoke(request, args);
}
return retObj;
}
});