*0 泛型设计
a)泛型只是在源码级别上(.java)一个约束,字节码级别上(.class)该约束“擦除”
b)对于多个Dao在编码上非常类似
c)写一个BaseDao类,让具体类扩展其对应的方法,但在BaseDao中不能引入任何与具体类型的变量
d)可以通过构造方法为实例变量赋值
*1 反射泛型
//取得BaseDao的字节码对象
Class baseDaoClass = this.getClass();
//取得BaseDao的泛型类型
Type type = (Type) baseDaoClass.getGenericSuperclass();
//将Type转发ParameterizedType,即取得BaseDao<Type>的参数化类型
ParameterizedType pt = (ParameterizedType) type;
//取得参数化类型中的实例参数类型,即Type
this.clazz = (Class) pt.getActualTypeArguments()[0];
int index = this.clazz.getName().lastIndexOf(".");
//表名
this.tableName = this.clazz.getName().substring(index+1).toLowerCase();
BaseDao<T>泛型类型
BaseDao<Type>参数化类型
2 Annotation(注解@)
a)// /**/ /** */javadoc 注释给程序员看,注解是给编译器看。
b)JDK中有三个基本的注解
@Override(检测是否覆盖父类的方法)
@Deprecated(标识该方法已过时)
@SuppressWarnings("unchecked")(压制编译器不要警告)
或
@SuppressWarnings(value={"unchecked"})(压制编译器不要警告)
c)注解:
普通注解: 修饰方法的注解。
元注解 : 修饰注解的注解。
*3 自定义注解和反射注解
a)定义注解格式如下:
//自定义注解
public @interface MyAnnotation {
//属性
String who();
int age();
String gender();
//注解无方法
}
//注解使用
@MyAnnotation(who="merry", age=20, gender="man")
b)设置注解的默认值
public @interface YouAnnotation {
String who() default "marry";
int age() default 22;
String gender() default "female";
}
//注解使用
@YouAnnotation
or
@YouAnnotation(who="sisi", age=21, gender="male") //覆盖所有默认属性
or
@YouAnnotation(who="sisi") //覆盖部分默认属性
c)数组情况:
public @interface TheyAnnotation {
String[] value(); //value是个特殊的属性,可以省略value名字
}
//注解使用
@TheyAnnotation(value={"电视","洗衣机","电脑"})
or
@TheyAnnotation({"电视","洗衣机","电脑"})
d)反射注解:注解可以在一定程度上替代参数,属性文件,XML文件
code:
//Annotation类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Role {
String username() default "jack";
String password() default "123456";
}
//使用注解类
public class AnnotationDemo {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Boolean flag = isOk("merry", "123");
System.out.println(flag);
flag = isOk("jack", "123456");
System.out.println(flag);
}
@Role
private static Boolean isOk(String username, String password) throws NoSuchMethodException, SecurityException {
//反射注解
Class clazz = AnnotationDemo.class;
Method method = clazz.getDeclaredMethod("isOk", String.class, String.class);
Role role = method.getAnnotation(Role.class);
String annUsername = role.username();
String annPassword = role.password();
if (username.equals(annUsername) && password.equals(annPassword)) return true;
return false;
}
}
e)注解的策略[@Retention]
1)RetentionPolicy.SOURCE:源码级别上可见,在字节码级别和运行时不可见,无法反射
2)RetentionPolicy.CLASS:(默认)字节码级别上可见,在运行时不可见,无法反射
3)RetentionPolicy.RUNTIME:运行时可见,可以反射,即在SOURCE和CLASS级别上都有
f)标识注解可以使用的位置[@Target]
ElementType.TYPE、ElementType.FIELD、ElementType.METHOD、ElementType.PARAMETER、ElementType.CONSTRUCTION、ElementType.LOCAL_VARIABLE
g)写入文档[@Documented]
被该元Annotation修饰的Annation类将被javadoc工具提取成文档。
h)增加继承性[@Inherited]
被它修饰的Annotation类将具有继承性。即:
如果某个类使用了@Inherited修饰的Annotation类,那么被注解的类的子类也继承父类所对应的注解。
注意:元注解可以修饰其它注解,元注解本身也可由其它元注解或其本身所修饰
*4 代理
a)静态代理 (一个代理类唯一代理一个对象)
为什么会有代理?
阻止对目标对象的直接访问
如何代理?
在代理对象中,写一个与目标对象一样的业务方法
code:
//明星接口
public interface Star {
public void sing();
}
//明星Jack
public class StarJack implements Star {
@Override
public void sing() {
System.out.println("唱歌");
}
}
//明星Jack经纪人
public class JackProxy implements Star{
private StarJack jack = new StarJack();
@Override
public void sing() {
jack.sing();
}
//得到明星Jack实体
public Star getProxy() {
return jack;
}
}
//歌迷
public class Fans {
public static void main(String[] args) {
//得到明星Jack的经纪人
JackProxy proxy = new JackProxy();
//通过代理人得到Jack对象
StarJack jack = (StarJack) proxy.getProxy();
//jack唱歌
jack.sing();
}
}
b)动态代理 (一个代理类可以代理多个对象)
代理类的开发步骤:
1)写一个普通类,无需任何继承或实现
2)写一个实例变量,为代理的目标实例对象
3)使用构造方法为实例变量赋值
4)写一个普通方法,该方法的返回值是接口,该接口是目标对象的实现接口
code:
//明星接口
public interface Star {
public String sing(Integer money);
public void dance(Integer money, String name);
public void run(Integer money);
}
//明星Jack
public class StarJack implements Star{
@Override
public String sing(Integer money) {
System.out.println("唱歌");
return "谢谢";
}
@Override
public void dance(Integer money, String name) {
System.out.println("jack 跳舞:" + name);
}
@Override
public void run(Integer money) {
System.out.println("跑步!");
}
}
//Jack经纪人
public class JackProxy {
private StarJack jack = new StarJack();
//参数一:代理类的类加载器
//参数二:代理的目标类的接口
//参数三:表示动态代理对象的拦截类,每次调用目标对象都会执行此类的invoke()方法。
public Star getProxy() {
//invoke()方法的三个参数的含义
//参数一:动态产生的代理对象本身,此处为JackProxy实例对象proxy
//参数二:method表示调用的方法
//参数三:args表示调用方法的参数
//***返回值: 作为代理的类的方法的返回值。
Star star = (Star) Proxy.newProxyInstance(
JackProxy.class.getClassLoader(),
jack.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println(method.getName());//sing
// System.out.println(args[0]);//200
Integer money = (Integer) args[0];
if ( money< 200) {
System.out.println("钱不够!");
} else {
if ("sing".equals(method.getName())) {
String returnValue = (String) method.invoke(jack, args);
System.out.println(returnValue);//谢谢!
} else if ("dance".equals(method.getName())) {
method.invoke(jack, args);
} else if ("run".equals(method.getName())) {
System.out.println("今天有事,不跑步了!");
}
}
return null;
}
});
return star;
}
}
//歌迷
public class Fans {
public static void main(String[] args) {
JackProxy proxy = new JackProxy();
Star star = proxy.getProxy();
star.sing(180);//钱不够!
star.sing(200);//唱歌 谢谢
star.dance(200, "恰恰舞");//jack 跳舞:恰恰舞
star.run(200);//今天有事,不跑步了!
}
}
5 动态代理案例
1)解决网站POST和GET的统一编码问题
code:
//jsp
GET方式:<a href="${pageContext.request.contextPath}/login?username=<%=URLEncoder.encode("杰克", "utf-8")%>&password=123456" >登录</a>
<hr />
POST方式:
<form method="POST" action="${pageContext.request.contextPath}/login">
<input type="text" name="username" /><br/>
<input type="password" name="password"/> <br/>
<input type="submit" vlaue="提交">
</form>
//Filter
public class EncoderFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
RequestProxy proxy = new RequestProxy(request);
chain.doFilter(proxy.getProxy(), response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
//Proxy
public class RequestProxy {
private HttpServletRequest request;
public RequestProxy(ServletRequest request) {
this.request = (HttpServletRequest) request;
}
public HttpServletRequest getProxy() { //返回值必须是接口
return (HttpServletRequest) Proxy.newProxyInstance(RequestProxy.class.getClassLoader(),
request.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String funMethod = method.getName();
if ("getParameter".equals(funMethod)) {
String requestMethod = request.getMethod();
if ("GET".equals(requestMethod)) {
String data = request.getParameter((String) args[0]);
byte[] userBuf = data.getBytes("ISO8859-1");
data = new String(userBuf, "UTF-8");
return data;//此返回值,即为被代理的对象调用方法的返回值。
} else {
request.setCharacterEncoding("UTF-8");
return method.invoke(request, args);
}
} else {
return method.invoke(request, args);
}
}
});
}
}
//Servlet
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username + " : " + password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username + " : " + password);
}
}
2)解决网站输出流压缩的问题
code:
3)解决网站中返回Connection对象的代理问题
code:
//自定义连接池
public class Pool {
private static LinkedList<Connection> linkedList = new LinkedList<Connection>();
static{
//在加载Pool类时,创建10个连接,并加入到连接池中
for(int i=0;i<10;i++){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bbs","root","root");
linkedList.addLast(conn);
} catch (Exception e) {
}
}
}
//取得连接池中连接的个数
public int getSize() {
return linkedList.size();
}
/*取得一个空闲的连接,只能返回Connection的动态代理对象
public Connection getConnection() {
final Connection conn = linkedList.removeFirst();
return (Connection) Proxy.newProxyInstance(
Pool.class.getClassLoader(),
conn.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(
Object proxy,
Method method,
Object[] args) throws Throwable {
//如果调用的是close()方法
if("close".equals(method.getName())){
//将连接放回连接池
linkedList.addLast(conn);
//返回null
return null;
}else{
return method.invoke(conn,args);
}
}
});
}
*/
public Connection getConnection() {
Connection conn = linkedList.removeFirst();
return conn;//返回真Connection
}
}
6 了解类加载的特点
Java的类加载器有三层:
1)BootStrap加载核心类库(最先), 即:加载jre/lib/rt.jar
2)ExtClassLoader加载非核心的辅助类库(其次) ,即:加载jre/lib/ext/ *.jar
3)AppClassLoader加载每个应用自已的类库(最后),即:加载classpath指定的所有jar和目录
每个Java程序运行都需要启用上述三个类加载器
a)全盘负责
当加载一个非核心非辅助的类库时,如果涉及到其他的非核心非辅助类,都由该AppClassLoader全盘负责加载
b)委托机制
当加载一个类时,首先由父加载器依次加载,如果所有的父加载器都加载不到,最后再由自已加载
c)缓存机制
当加载一个类时,如果事先缓存中有对应的字节码,则直接取来用;如果没有,再临时加载,完成后依然放入到缓存中,以
使下次重用
7 URL和HttpURLConnection的使用
1)服务端[GET]->手机
(1)手机先发送请求,再接收服务端的响应
(2)在服务端写到GET方式中
code:
2)手机->服务端[POST]
(1)在服务端写到POST方式中
code:
3)对于中文方式:
(1)通过URLEncoder进行URL编码,
String username = "杰克";
username = URLEncoder.encode(username,"UTF-8");
(2)在服务端进行编码设置:
request.setCharacterEncoding("UTF-8");
(3)必须确保URL编码和解析一致