diff --git a/README.md b/README.md index 1511b81..c02d183 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ 不定时进行调整和补充,需要关注更新的请 watch、star、fork - ----- # 仓库目录 diff --git a/blogs/README.md b/blogs/README.md index 57d6ca8..ba4bef9 100644 --- a/blogs/README.md +++ b/blogs/README.md @@ -2,26 +2,25 @@ 如果你只是单纯要阅读的话,建议移步CSDN或者oschina上观看,访问速度快很多: ->* CSDN:[我的java&javaweb学习笔记(汇总)](http://blog.csdn.net/h3243212/article/details/50659471) ->* oschina:[我的java&javaweb学习笔记(汇总)](http://my.oschina.net/brianway/blog/614355) - +> * CSDN:[我的java&javaweb学习笔记(汇总)](http://blog.csdn.net/h3243212/article/details/50659471) +> * oschina:[我的java&javaweb学习笔记(汇总)](http://my.oschina.net/brianway/blog/614355) # 目录 -- [javase](/blogs/javase) - - [java基础巩固笔记(1)-反射.md](/blogs/javase/java基础巩固笔记(1)-反射.md) - - [java基础巩固笔记(2)-泛型.md](/blogs/javase/java基础巩固笔记(2)-泛型.md) - - [java基础巩固笔记(3)-类加载器.md](/blogs/javase/java基础巩固笔记(3)-类加载器.md) - - [java基础巩固笔记(4)-代理.md](/blogs/javase/java基础巩固笔记(4)-代理.md) - - [java基础巩固笔记(4)-实现AOP功能的封装与配置的小框架.md](/blogs/javase/java基础巩固笔记(4)-实现AOP功能的封装与配置的小框架.md) - - [java基础巩固笔记(5)-多线程之传统多线程.md](/blogs/javase/java基础巩固笔记(5)-多线程之传统多线程.md) - - [java基础巩固笔记(5)-多线程之共享数据.md](/blogs/javase/java基础巩固笔记(5)-多线程之共享数据.md) - - [java基础巩固笔记(5)-多线程之线程并发库.md](/blogs/javase/java基础巩固笔记(5)-多线程之线程并发库.md) - - [java基础巩固笔记(6)-注解.md](/blogs/javase/java基础巩固笔记(6)-注解.md) -- [javaweb](/blogs/javaweb) - - [javaweb入门笔记(1)-Tomcat.md](/blogs/javaweb/javaweb入门笔记(1)-Tomcat.md) - - [javaweb入门笔记(2)-http入门.md](/blogs/javaweb/javaweb入门笔记(2)-http入门.md) - - [javaweb入门笔记(3)-Servlet.md](/blogs/javaweb/javaweb入门笔记(3)-Servlet.md) - - [javaweb入门笔记(4)-request和response.md](/blogs/javaweb/javaweb入门笔记(4)-request和response.md) - - [javaweb入门笔记(5)-cookie和session.md](/blogs/javaweb/javaweb入门笔记(5)-cookie和session.md) - - [javaweb入门笔记(6)-JSP技术.md](/blogs/javaweb/javaweb入门笔记(6)-JSP技术.md) \ No newline at end of file +- [javase](/blogs/javase) + - [java基础巩固笔记(1)-反射.md](/blogs/javase/java基础巩固笔记(1)-反射.md) + - [java基础巩固笔记(2)-泛型.md](/blogs/javase/java基础巩固笔记(2)-泛型.md) + - [java基础巩固笔记(3)-类加载器.md](/blogs/javase/java基础巩固笔记(3)-类加载器.md) + - [java基础巩固笔记(4)-代理.md](/blogs/javase/java基础巩固笔记(4)-代理.md) + - [java基础巩固笔记(4)-实现AOP功能的封装与配置的小框架.md](/blogs/javase/java基础巩固笔记(4)-实现AOP功能的封装与配置的小框架.md) + - [java基础巩固笔记(5)-多线程之传统多线程.md](/blogs/javase/java基础巩固笔记(5)-多线程之传统多线程.md) + - [java基础巩固笔记(5)-多线程之共享数据.md](/blogs/javase/java基础巩固笔记(5)-多线程之共享数据.md) + - [java基础巩固笔记(5)-多线程之线程并发库.md](/blogs/javase/java基础巩固笔记(5)-多线程之线程并发库.md) + - [java基础巩固笔记(6)-注解.md](/blogs/javase/java基础巩固笔记(6)-注解.md) +- [javaweb](/blogs/javaweb) + - [javaweb入门笔记(1)-Tomcat.md](/blogs/javaweb/javaweb入门笔记(1)-Tomcat.md) + - [javaweb入门笔记(2)-http入门.md](/blogs/javaweb/javaweb入门笔记(2)-http入门.md) + - [javaweb入门笔记(3)-Servlet.md](/blogs/javaweb/javaweb入门笔记(3)-Servlet.md) + - [javaweb入门笔记(4)-request和response.md](/blogs/javaweb/javaweb入门笔记(4)-request和response.md) + - [javaweb入门笔记(5)-cookie和session.md](/blogs/javaweb/javaweb入门笔记(5)-cookie和session.md) + - [javaweb入门笔记(6)-JSP技术.md](/blogs/javaweb/javaweb入门笔记(6)-JSP技术.md) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(1)-\345\217\215\345\260\204.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(1)-\345\217\215\345\260\204.md" index cf7a1e4..7cc9b36 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(1)-\345\217\215\345\260\204.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(1)-\345\217\215\345\260\204.md" @@ -1,51 +1,46 @@ -# java基础巩固笔记(1)-反射 +# java 基础巩固笔记 (1)- 反射 -标签: java +标签:java --- **Contents** -- [java基础巩固笔记(1)-反射](#java基础巩固笔记1-反射) - - [反射基本使用](#反射基本使用) - - [数组的反射](#数组的反射) - - [配置文件加载](#配置文件加载) - - [内省(Instropector) & JavaBean](#内省instropector--javabean) - - +- [java 基础巩固笔记 (1)- 反射](#java 基础巩固笔记 1 - 反射) + - [反射基本使用](# 反射基本使用) + - [数组的反射](# 数组的反射) + - [配置文件加载](# 配置文件加载) + - [内省 (Instropector) & JavaBean](# 内省 instropector--javabean) --- - -**反射:将类的属性和方法映射成相应的类。** +** 反射:将类的属性和方法映射成相应的类。** ## 反射基本使用 -获取Class类的三种方法: - -- 类名.class -- 对象名.getClass() -- Class.forName("要加载的类名") - -根据API写就行了,大致流程就是: +获取 Class 类的三种方法: -- 用上述三种方式之一获取特定类的`Class`类,即该类对应的字节码 -- 调用`Class`对象的`getConstructor(Class... parameterTypes)`获取构造方法对象 -- 调用是构造方法类`Constructor`的`newInstance(Object... initargs)`方法新建对象 -- 调用`Class`对象的`getMethod(String name, Class... parameterTypes)`获取方法对象 -- 调用方法对象类`Method`的`invoke(Object obj, Object... args)`方法,调用对象上相应方法 +- `类名.class` +- `对象名.getClass()` +- `Class.forName("要加载的类名")` -*用方法的参数类型唯一标识一个方法,依据:方法的重载* +根据 API 写就行了,大致流程就是: +- 用上述三种方式之一获取特定类的 `Class` 类,即该类对应的字节码 +- 调用 `Class` 对象的 `getConstructor(Class... parameterTypes)` 获取构造方法对象 +- 调用是构造方法类 `Constructor` 的 `newInstance(Object... initargs)` 方法新建对象 +- 调用 `Class` 对象的 `getMethod(String name, Class... parameterTypes)` 获取方法对象 +- 调用方法对象类 `Method` 的 `invoke(Object obj, Object... args)` 方法,调用对象上相应方法 ## 数组的反射 + 下面这个例子主要说明几点: -- 对于元素同类型的数组,同维数组,class一样 -- 不同维,class不同 -- 不同维的,父类都是Object,一样 -- 基本类型一维数组不能直接转换为Object[] -- `java.util.Arrays`的`asList`方法API看看 +- 对于元素同类型的数组,同维数组,class 一样 +- 不同维,class 不同 +- 不同维的,父类都是 Object, 一样 +- **基本类型一维数组不能直接转换为 Object[]** +- `java.util.Arrays` 的 `asList` 方法 API 看看 ```java public class ReflectTest { @@ -59,11 +54,12 @@ public class ReflectTest { System.out.println(a1.getClass().getSuperclass() == a3.getClass().getSuperclass());//true System.out.println(a2.getClass().getSuperclass());//class java.lang.Object - //下句编译不通过:Error:(15, 42) java: 不可比较的类型: java.lang.Class和java.lang.Class + // 下句编译不通过:Error:(15, 42) java: 不可比较的类型: java.lang.Class 和 java.lang.Class //System.out.println(a1.getClass() == a3.getClass()); - Object []b3 = a3;//通过 - //下句编译不通过 Error:(17, 24) java: 不兼容的类型: int[]无法转换为java.lang.Object[] + Object []b3 = a3;// 通过 + // 下句编译不通过 Error:(17, 24) java: 不兼容的类型: int[] 无法转换为 java.lang.Object[] //Object [] b1 = a1; String s1 = "abc"; @@ -73,8 +69,6 @@ public class ReflectTest { } ``` - - 输出: ``` @@ -88,93 +82,72 @@ class java.lang.Object ``` 乱入: -hashcode与内存泄露问题 -参考java api: +hashcode 与内存泄露问题 ->* hashcode一旦生成,不要变 ->* 对象equals方法返回true,则hashcode要一致 ->* 反之,equals方法返回false,hashcode不一定互异 +参考 java api: -如果参与hashcode计算的成员变量中途发生变化,则后面remove时失败,造成内存泄露 +> * hashcode 一旦生成,不要变 +> * 对象 equals 方法返回 true, 则 hashcode 要一致 +> * 反之,equals 方法返回 false,hashcode 不一定互异 +如果参与 hashcode 计算的成员变量中途发生变化,则后面 remove 时失败,造成内存泄露 ---- ## 配置文件加载 -- 类加载器加载只读配置文件 +- 类加载器加载只读配置文件 -`类名.class.getClassLoader().getResourceAsStream(str);` + `类名.class.getClassLoader().getResourceAsStream(str);` -- 类名.class.getResourceAsStream(str),实质还是调用类加载器。 -源码截取(java.lang包下的Class.java): +- `类名.class.getResourceAsStream(str)`, 实质还是调用类加载器。 -```java - public InputStream getResourceAsStream(String name) { - name = resolveName(name); - ClassLoader cl = getClassLoader0(); - if (cl==null) { - // A system class. - return ClassLoader.getSystemResourceAsStream(name); + 源码截取 (java.lang 包下的 Class.java): + + ```java + public InputStream getResourceAsStream(String name) { + name = resolveName(name); + ClassLoader cl = getClassLoader0(); + if (cl==null) { + // A system class. + return ClassLoader.getSystemResourceAsStream(name); + } + return cl.getResourceAsStream(name); } - return cl.getResourceAsStream(name); -} -``` + ``` -关于路径str,写法有点讲究。 +关于路径 str,写法有点讲究。 -- 不加斜杠,相对路径: - `str = "config.properties";` -- 加斜杠,从classpath的根路径找: - `str = "/org/iot/ui/config.properties";` +- 不加斜杠,相对路径:`str = "config.properties";` +- 加斜杠,从 classpath 的根路径找: `str = "/org/iot/ui/config.properties";` -*以前编译java代码时,有些`conf/`文件夹还要添加进依赖或者标记成source文件夹,里面明明都是xml文件,没Java源码。从这里,我现在知道了,是使用反射加载配置文件的缘故* +*以前编译 java 代码时,有些 `conf/` 文件夹还要添加进依赖或者标记成 source 文件夹,里面明明都是 xml 文件,没 Java 源码。 +从这里,我现在知道了,是使用反射加载配置文件的缘故* --- -## 内省(Introspector) & JavaBean -JavaBean读取属性x的值的流程:变大写、补前缀、获取方法。 +## 内省 (Introspector) & JavaBean + +JavaBean 读取属性 x 的值的流程:变大写、补前缀、获取方法。 ``` "x"-->"X"-->"getX"-->"MethodGetX" ``` -- 自己用内省操作 +- 自己用内省操作 -我目前没用上,所以不贴代码了,只附上核心类 + 我目前没用上,所以不贴代码了,只附上核心类 -简单实现: -使用`java.beans.PropertyDescriptor`类 + 简单实现:使用 `java.beans.PropertyDescriptor` 类 -麻烦实现: -使用`java.beans.Introspector`类,遍历`getBeanInfo`方法的返回值 + 麻烦实现: 使用 `java.beans.Introspector` 类, 遍历 `getBeanInfo` 方法的返回值 -**JavaBean必须有一个不带参数的构造函数** + **JavaBean 必须有一个不带参数的构造函数 ** -- 使用BeanUtils工具包 +- 使用 BeanUtils 工具包 - - 字符串和整数转换(对比(PropertyUtils) - - 属性级联操作 - - 操作map + - 字符串和整数转换 (对比 (PropertyUtils) + - 属性级联操作 + - 操作 map - - -[作者更多文章:@brianway](http://brianway.github.io/) - - - - - - - - - - - - - - - - - - +[作者更多文章:@brianway](http://brianway.github.io/) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(2)-\346\263\233\345\236\213.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(2)-\346\263\233\345\236\213.md" index 974faa5..31b9a94 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(2)-\346\263\233\345\236\213.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(2)-\346\263\233\345\236\213.md" @@ -7,94 +7,95 @@ **Contents** - [java基础巩固笔记(2)-泛型](#java基础巩固笔记2-泛型) - - [术语](#术语) - - ["?"通配符](#通配符) - - [通配符的扩展](#通配符的扩展) - - [自定义泛型方法](#自定义泛型方法) - - ["擦除"实例](#擦除实例) - - [类型参数的类型推断](#类型参数的类型推断) - - [自定义泛型类](#自定义泛型类) - - [泛型方法和泛型类的比较](#泛型方法和泛型类的比较) - - [泛型和反射](#泛型和反射) - - [通过反射获得泛型的实际类型参数](#通过反射获得泛型的实际类型参数) - - + - [术语](#术语) + - ["?"通配符](#通配符) + - [通配符的扩展](#通配符的扩展) + - [自定义泛型方法](#自定义泛型方法) + - ["擦除"实例](#擦除实例) + - [类型参数的类型推断](#类型参数的类型推断) + - [自定义泛型类](#自定义泛型类) + - [泛型方法和泛型类的比较](#泛型方法和泛型类的比较) + - [泛型和反射](#泛型和反射) + - [通过反射获得泛型的实际类型参数](#通过反射获得泛型的实际类型参数) --- 本文对泛型的基本知识进行较为全面的总结,并附上简短的代码实例,加深记忆。 - 泛型:将集合中的元素限定为一个特定的类型。 ## 术语 -- `ArrayList` -- 泛型类型 -- `ArrayList` -- 原始类型 -- `E` -- 类型参数 -- `<>` -- 读作"typeof" -- `ArrayList` -- 参数化的类型 -- `Integer` -- 实际类型参数 +- `ArrayList` -- 泛型类型 +- `ArrayList` -- 原始类型 +- `E` -- 类型参数 +- `<>` -- 读作 "typeof" +- `ArrayList` -- 参数化的类型 +- `Integer` -- 实际类型参数 几点注意: -- 参数化类型和原始类型相互兼容 +- 参数化类型和原始类型相互兼容 -```java -ArrayList collection1 = new ArrayList();//通过,无warning -ArrayList collection2 = new ArrayList();//通过,有warning -``` + ```java + ArrayList collection1 = new ArrayList(); // 通过,无warning + ArrayList collection2 = new ArrayList(); // 通过,有warning + ``` -- 参数化类型不考虑类型参数的继承关系 +- 参数化类型不考虑类型参数的继承关系 -```java -ArrayList collection3 = new ArrayList();//编译不通过 -ArrayList collection4 = new ArrayList();//编译不通过 -``` + ```java + ArrayList collection3 = new ArrayList(); // 编译不通过 + ArrayList collection4 = new ArrayList(); // 编译不通过 + ``` -但是 + 但是 -```java -ArrayList collection5 = new ArrayList(); -ArrayList collection6 = collection5;//编译通过 -``` + ```java + ArrayList collection5 = new ArrayList(); + ArrayList collection6 = collection5; //编译通过 + ``` --- ## "?"通配符 -"?"表示任意类型,使用"?"通配符可以引用各种参数化的类型,可以调用与参数化无关的方法(如size()方法),不能调用与参数化有关的方法(如add()方法) + +"?"表示任意类型,使用"?"通配符可以引用各种参数化的类型,可以调用与参数化无关的方法(如size()方法), +不能调用与参数化有关的方法(如add()方法) ### 通配符的扩展 -- 限定通配符的上边界 +- 限定通配符的上边界: extends -```java -ArrayList collection1= new ArrayList();//编译通过 -ArrayList collection2= new ArrayList();//编译不通过 -``` + ```java + ArrayList collection1= new ArrayList();//编译通过 + ArrayList collection2= new ArrayList();//编译不通过 + ``` -- 限定通配符的下边界 +- 限定通配符的下边界: super -```java -ArrayList collection3= new ArrayList();//编译通过 -ArrayList collection4= new ArrayList();//编译不通过 -``` + ```java + ArrayList collection3= new ArrayList();//编译通过 + ArrayList collection4= new ArrayList();//编译不通过 + ``` --- ## 自定义泛型方法 -C++模板函数 + +C++ 模板函数 ```cpp -template T add(T x, T y){ +template T add(T x, T y) { return (T)(x+y); } ``` - -而java的泛型基本上完全在编译器中实现,用于编译器执行类型检查和类型判断,然后生成普通的**非泛型**的字节码,这种实现技术为“擦除”(erasure)。 +而 java 的泛型基本上完全在编译器中实现,用于编译器执行类型检查和类型判断,然后生成普通的**非泛型**的字节码, +这种实现技术为“擦除”(erasure)。 ### "擦除"实例 -泛型是提供给javac编译器使用的,限定集合的输入类型,编译器编译带类型说明的集合时会去掉“类型”信息。 + +泛型是提供给 javac 编译器使用的,限定集合的输入类型,编译器编译带类型说明的集合时会去掉“类型”信息。 ```java public class GenericTest { @@ -110,7 +111,7 @@ public class GenericTest { //两者class类型一样,即字节码一致 System.out.println(collection2.getClass().getName()); - //class均为java.util.ArrayList,并无实际类型参数信息 + //class均为java.util.ArrayList, 并无实际类型参数信息 } } ``` @@ -125,6 +126,7 @@ java.util.ArrayList *使用反射可跳过编译器,往某个泛型集合加入其它类型数据。* 只有引用类型才能作为泛型方法的实际参数 + 例子: ```java @@ -148,6 +150,7 @@ public class GenericTest { ``` 但注意基本类型**有时**可以作为实参,因为有**自动装箱**和**拆箱**。 + 例子(编译通过了): ```java @@ -167,7 +170,7 @@ public class GenericTest { } ``` -同时,该例还表明,**当实参不一致时,T取交集,即第一个共同的父类。** +同时,该例还表明,**当实参不一致时,T 取交集,即第一个共同的父类。** 另外,如果用`Number b = biggerOne(3,5.5);`改为`String c = biggerOne(3,5.5);`则编译报错: ``` @@ -180,51 +183,55 @@ Error:(17, 29) java: 不兼容的类型: 推断类型不符合上限 ![泛型调试截图-1](http://7xph6d.com1.z0.glb.clouddn.com/javaSE_%E6%B3%9B%E5%9E%8B%E8%B0%83%E8%AF%95%E6%88%AA%E5%9B%BE-1.png) 不知道b为什么是Double类型的(但直接`Double b`接收返回值会编译报错)。不知道跟IDE有没有关系,是不是IDE在debug时会显示这个对象最精确的类型? +哎……这人水平其实不高啊……这是声明,当然要找两者共同的父类,但实际引用指向的地址,是一个 Double 型,完全没有问题!! ### 类型参数的类型推断 + 编译器判断泛型方法的实际类型参数的过程称为类型推断。 -- 当某个类型变量只在整个参数列表的所有参数和返回值中的**一处被应用**了,那么根据调用方法时该处的实际应用类型来确定。即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。 -例如: +- 当某个类型变量只在整个参数列表的所有参数和返回值中的**一处被应用**了, + 那么根据调用方法时该处的实际应用类型来确定。即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。 例如: -`swap(new String[3],1,2)` -> `static void swap(E[]a,int i,int j)` + `swap(new String[3],1,2)` -> `static void swap(E[]a,int i,int j)` - 当某个类型变量在整个参数列表的所有参数和返回值中的**多处被应用**了,如果调用方法时这么多处的实际应用类型都 *对应同一种类型*,则泛型参数的类型就是该类型。 例如: `add(3,5)` -> `static T add(T a,T b)` -- 当某个类型变量在整个参数列表的所有参数和返回值中的***多处被应用**了,如果调用方法时这么多处的实际应用类型 *对应不同的类型,且没有返回值*,则取多个参数中的最大交集类型,即第一个公共父类。 -例如: +- 当某个类型变量在整个参数列表的所有参数和返回值中的***多处被应用**了,如果调用方法时这么多处的实际应用类型 + *对应不同的类型,且没有返回值*,则取多个参数中的最大交集类型,即第一个公共父类。 例如: -`fill(new Integer[3],3.5)` -> `static void fill(T a[],T v)` + `fill(new Integer[3],3.5)` -> `static void fill(T a[],T v)` -该例子实际对应的类型就是Number,编译通过,运行出问题。 + 该例子实际对应的类型就是Number,编译通过,运行出问题。 -- 当某个类型变量在整个参数列表的所有参数和返回值中的**多处被应用**了,如果调用方法时这么多处的实际应用类型*对应不同的类型,且使用有返回值*,则**优先考虑返回值的类型** +- 当某个类型变量在整个参数列表的所有参数和返回值中的**多处被应用** + 了,如果调用方法时这么多处的实际应用类型*对应不同的类型,且使用有返回值*,则**优先考虑返回值的类型** -例如: + 例如: -`int x = add(3,3.5)` -> `static T add(T a,T b)` + `int x = add(3,3.5)` -> `static T add(T a,T b)` -上例编译报错,x类型改为float也报错,改为Number成功。 + 上例编译报错,x类型改为float也报错,改为Number成功。 -- 参数类型的类型推断具有传递性 +- 参数类型的类型推断具有传递性 -例子: + 例子: -`copy(new Integer[5],new String[5])` -> `static void copy(T []a,T []b)` + `copy(new Integer[5],new String[5])` -> `static void copy(T []a,T []b)` -该例推断实际参数类型为Object,编译通过. + 该例推断实际参数类型为Object,编译通过. - `copy(new ArrayList,new Integer[5])` -> `static void copy(Collectiona,T[]b)` + `copy(new ArrayList,new Integer[5])` -> `static void copy(Collectiona,T[]b)` -该例则根据参数化的ArrayList类实例将类型变量直接确定为String类型,编译报错。 + 该例则根据参数化的ArrayList类实例将类型变量直接确定为String类型,编译报错。 ---- ## 自定义泛型类 + 例子 ```java @@ -256,9 +263,11 @@ public class GenericDao{ } ``` -注意:当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。*因为静态成员是被所参数化的类所共享的,所以静态成员不应该有类级别的类型参数*。 +注意:当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型), +而不能被静态变量和静态方法调用。*因为静态成员是被所参数化的类所共享的,所以静态成员不应该有类级别的类型参数*。 ### 泛型方法和泛型类的比较 + 例子: ```java @@ -292,6 +301,7 @@ public class A(){ ## 泛型和反射 ### 通过反射获得泛型的实际类型参数 + 把泛型变量当成方法的参数,利用Method类的getGenericParameterTypes方法来获取泛型的实际类型参数 例子: @@ -320,7 +330,6 @@ public class GenericTest { public static void applyMap(Map map){ } - } ``` @@ -333,5 +342,4 @@ class java.lang.Integer class java.lang.String ``` -作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) - +作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(3)-\347\261\273\345\212\240\350\275\275\345\231\250.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(3)-\347\261\273\345\212\240\350\275\275\345\231\250.md" index ddc2ad6..5899a56 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(3)-\347\261\273\345\212\240\350\275\275\345\231\250.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(3)-\347\261\273\345\212\240\350\275\275\345\231\250.md" @@ -6,34 +6,32 @@ **Contents** -- [java基础巩固笔记(3)-类加载器](#java基础巩固笔记3-类加载器) - - [默认类加载器](#默认类加载器) - - [类加载器的委托机制](#类加载器的委托机制) - - [自定义类加载器的编写原理](#自定义类加载器的编写原理) - - [参考资料](#参考资料) - - +- [java基础巩固笔记(3)-类加载器](#java基础巩固笔记3-类加载器) + - [默认类加载器](#默认类加载器) + - [类加载器的委托机制](#类加载器的委托机制) + - [自定义类加载器的编写原理](#自定义类加载器的编写原理) + - [参考资料](#参考资料) --- - java类加载器就是在运行时在JVM中动态地加载所需的类,java类加载器基于三个机制:委托,可见,单一。 -把 classpath 下的那些 `.class` 文件加载进内存,处理后形成可以被虚拟机直接使用的 Java 类型,这些工作是类加载器做的。 - -- **委托机制**指的是将加载类的请求传递给父加载器,如果父加载器找不到或者不能加载这个类,那么再加载他。 -- **可见性机制**指的是父加载器加载的类都能被子加载器看见,但是子加载器加载的类父加载器是看不见的。 -- **单一性机制**指的是一个类只能被同一种加载器加载一次。 +**把 classpath 下的那些 `.class` 文件加载进内存,处理后形成可以被虚拟机直接使用的 Java 类型,这些工作是类加载器做的。** +- **委托机制**指的是将加载类的请求传递给父加载器,如果父加载器找不到或者不能加载这个类,那么再加载他。 +- **可见性机制**指的是父加载器加载的类都能被子加载器看见,但是子加载器加载的类父加载器是看不见的。 +- **单一性机制**指的是一个类只能被同一种加载器加载一次。 ## 默认类加载器 + 系统默认三个类加载器: -- `BootStrap` -- `ExtClassLoader` -- `AppClassLoader` +- `BootStrap` +- `ExtClassLoader` +- `AppClassLoader` *类加载器也是java类,而BootStrap不是。* + 验证代码: ```java @@ -57,9 +55,10 @@ Exception in thread "main" java.lang.NullPointerException at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) ``` -可见,System类是由BootStrap类加载器加载。 +**可见,System类是由 BootStrap 类加载器(不是 Java 类)加载。** ## 类加载器的委托机制 + 类加载器的树状图 ![类加载器](http://7xph6d.com1.z0.glb.clouddn.com/javaSE_%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8%E7%BB%93%E6%9E%84%E5%9B%BE.png) @@ -67,9 +66,9 @@ Exception in thread "main" java.lang.NullPointerException 一般加载类的顺序: -- 首先当前线程的类加载器去加载线程中的第一个类 -- 如果类A应用了类B,java虚拟机将使用加载类A的类加载器来加载类B -- 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类 +- 首先当前线程的类加载器去加载线程中的第一个类 +- 如果类A应用了类B,java虚拟机将使用加载类A的类加载器来加载类B +- 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类 ------------------- @@ -77,15 +76,15 @@ Exception in thread "main" java.lang.NullPointerException API: -> [Class ClassLoader](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/ClassLoader.html) +> [Class ClassLoader](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/ClassLoader.html) 模板方法设计模式 父类: -- `loadClass`(类加载的流程,模板) -- `findClass`供子类覆盖的、被`loadClass`方法调用的类加载逻辑 -- `defineClass`得到class文件转换成字节码 +- `loadClass`(类加载的流程,模板) +- `findClass`供子类覆盖的、被`loadClass`方法调用的类加载逻辑 +- `defineClass`得到class文件转换成字节码 子类:覆盖`findClass`方法 @@ -152,14 +151,11 @@ class NetworkClassLoader extends ClassLoader { } ``` - - ## 参考资料 ->* [java类加载机制工作原理](http://ju.outofmemory.cn/entry/142486) ->* [Java类加载器总结 - 寂静大海 - 博客频道 - CSDN.NET](http://blog.csdn.net/gjanyanlig/article/details/6818655) - +> * [java类加载机制工作原理](http://ju.outofmemory.cn/entry/142486) +> * [Java类加载器总结 - 寂静大海 - 博客频道 - CSDN.NET](http://blog.csdn.net/gjanyanlig/article/details/6818655) --------- -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\344\273\243\347\220\206.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\344\273\243\347\220\206.md" index baeb6fc..4bd0ba9 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\344\273\243\347\220\206.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\344\273\243\347\220\206.md" @@ -6,236 +6,222 @@ **Contents** -- [java基础巩固笔记(4)-代理](#java基础巩固笔记4-代理) - - [概念](#概念) - - [动态代理](#动态代理) - - [创建动态类](#创建动态类) - - [动态代理的工作原理](#动态代理的工作原理) - - [面向切面编程](#面向切面编程) - - [参考资料](#参考资料) - - +- [java基础巩固笔记(4)-代理](#java基础巩固笔记4-代理) + - [概念](#概念) + - [动态代理](#动态代理) + - [创建动态类](#创建动态类) + - [动态代理的工作原理](#动态代理的工作原理) + - [面向切面编程](#面向切面编程) + - [参考资料](#参考资料) --- -代理是实现AOP(Aspect oriented program,面向切面编程)的核心和关键技术。 +**代理是实现AOP(Aspect oriented program,面向切面编程)的核心和关键技术。** ## 概念 -代理是一种设计模式,其目的是为其他对象提供一个代理以控制对某个对象的访问,代理类负责为委托类预处理消息,过滤消息并转发消息以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口 -- 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,也就是说在程序运行前代理类的.class文件就已经存在。 -- 动态代理:在程序运行时运用反射机制动态创建生成。 +代理是一种设计模式,其目的是为其他对象提供一个代理以控制对某个对象的访问,代理类负责为委托类预处理消息, +过滤消息并转发消息以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口 + +- 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,也就是说在程序运行前代理类的.class文件就已经存在。 +- 动态代理:在程序运行时运用反射机制动态创建生成。 ![代理架构图](http://7xph6d.com1.z0.glb.clouddn.com/javaSE_%E4%BB%A3%E7%90%86%E6%9E%B6%E6%9E%84%E5%9B%BE.png) -*紫色箭头代表类的继承关系,红色连线表示调用关系* +``` +before(); +method.invoke(obj, args...) +after(); +``` +*紫色箭头代表类的继承关系,红色连线表示调用关系* ## 动态代理 -- JVM可以在运行期动态生成类的字节码,该类往往被用作动态代理类。 -- JVM生成的动态类必须实现一个或多个接口,所以这种只能用作具有相同接口的目标类的代理。 -- CGLIB库可以动态生成一个类的子类,一个类的子类也可作为该类的代理,这个可用来为没有实现接口的类生成动态代理类。 -- 代理类可在*调用目标方法之前、之后、前后、以及处理目标方法异常的catch块中*添加系统功能代码。 +- JVM可以在运行期动态生成类的字节码,该类往往被用作动态代理类。 +- JVM生成的动态类必须实现一个或多个接口,所以这种只能用作具有相同接口的目标类的代理。 +- CGLIB库可以动态生成一个类的子类,一个类的子类也可作为该类的代理,这个可用来为没有实现接口的类生成动态代理类。 +- 代理类可在*调用目标方法之前、之后、前后、以及处理目标方法异常的catch块中*添加系统功能代码。 ### 创建动态类 -API: -> [java.lang.reflect:Class Proxy](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/reflect/Proxy.html) -> [java.lang.reflect:Interface InvocationHandler](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/reflect/InvocationHandler.html) +API: -- 查看代理类方法列表信息 +> [java.lang.reflect:Class Proxy](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/reflect/Proxy.html) +> [java.lang.reflect:Interface InvocationHandler](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/reflect/InvocationHandler.html) -```java -package com.iot.proxy; +- 查看代理类方法列表信息 -import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.Collection; + ```java + package com.iot.proxy; -/** - * Created by brian on 2015/12/27. - */ -public class ProxyTest { - public static void main(String[] args) throws Exception { - Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); - System.out.println(clazzProxy1); - printConstructors(clazzProxy1); - printMethods(clazzProxy1); + import java.lang.reflect.*; + import java.util.ArrayList; + import java.util.Collection; - } + public class ProxyTest { + public static void main(String[] args) throws Exception { + Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); + System.out.println(clazzProxy1); + printConstructors(clazzProxy1); + printMethods(clazzProxy1); - /** - * 打印构造方法列表 - * @param clazz - */ - public static void printConstructors(Class clazz){ - System.out.println("-------------constructors list-------------"); - Constructor[] constructors = clazz.getConstructors(); - System.out.print(getExecutableList(constructors)); - } - - /** - * 打印成员方法列表 - * @param clazz - */ - public static void printMethods(Class clazz) { - System.out.println("-------------methods list-------------"); - Method[] methods = clazz.getMethods(); - System.out.print(getExecutableList(methods)); - } - - /** - * 获取要打印的列表数据 - * 每行一个方法,按照func(arg1,arg2)的格式 - * @param executables - * @return - */ - public static String getExecutableList(Executable[] executables){ - StringBuilder stringBuilder = new StringBuilder(); - for (Executable executable : executables) { - String name = executable.getName(); - stringBuilder.append(name); - stringBuilder.append("("); - Class[] clazzParams = executable.getParameterTypes(); - for (Class clazzParam : clazzParams) { - stringBuilder.append(clazzParam.getName()).append(","); - } - if (clazzParams != null && clazzParams.length != 0) { - stringBuilder.deleteCharAt(stringBuilder.length() - 1); - } - stringBuilder.append(")\n"); } - return stringBuilder.toString(); - } + public static void printConstructors(Class clazz){ + System.out.println("-------------constructors list-------------"); + Constructor[] constructors = clazz.getConstructors(); + System.out.print(getExecutableList(constructors)); + } -} -``` - -输出结果: - -``` -class com.sun.proxy.$Proxy0 --------------constructors list------------- -com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler) --------------methods list------------- -add(java.lang.Object) -remove(java.lang.Object) -equals(java.lang.Object) -toString() -hashCode() -clear() -contains(java.lang.Object) -isEmpty() -iterator() -size() -toArray([Ljava.lang.Object;) -toArray() -spliterator() -addAll(java.util.Collection) -stream() -forEach(java.util.function.Consumer) -containsAll(java.util.Collection) -removeAll(java.util.Collection) -removeIf(java.util.function.Predicate) -retainAll(java.util.Collection) -parallelStream() -isProxyClass(java.lang.Class) -getInvocationHandler(java.lang.Object) -getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;) -newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler) -wait() -wait(long,int) -wait(long) -getClass() -notify() -notifyAll() -``` - -- 创建实例对象 - -```java -/** - * 测试创建实例对象 - * @throws NoSuchMethodException - * @throws IllegalAccessException - * @throws InvocationTargetException - * @throws InstantiationException - */ -private static void createProxyInstance( ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { - /** - * 方法1:先创建代理类,再使用反射创建实例对象 - */ - Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); - Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class); - Collection proxy1 = (Collection) constructor.newInstance(new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - return null; + public static void printMethods(Class clazz) { + System.out.println("-------------methods list-------------"); + // 包括继承来的,如果不要继承来的 method,可以用 getDeclaredMethods + Method[] methods = clazz.getMethods(); + System.out.print(getExecutableList(methods)); } - }); - - /** - * 方法2:直接使用newProxyInstance方法创建实例对象 - */ - Collection proxy2 = (Collection)Proxy.newProxyInstance( - Collection.class.getClassLoader(), - new Class[]{Collection.class}, - new InvocationHandler() { - ArrayList target = new ArrayList(); - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //ArrayList targetTmp = new ArrayList(); - System.out.println("before invoke method: "+method.getName()); - return method.invoke(target,args); + // Constructor 和 Method 都继承自 Executable,里面有 getName 和 getParameterTypes + public static String getExecutableList(Executable[] executables){ + StringBuilder stringBuilder = new StringBuilder(); + for (Executable executable : executables) { + String name = executable.getName(); + stringBuilder.append(name).append("("); + Class[] clazzParams = executable.getParameterTypes(); + for (Class clazzParam : clazzParams) { + stringBuilder.append(clazzParam.getName()).append(","); + } + if (clazzParams != null && clazzParams.length != 0) { + stringBuilder.deleteCharAt(stringBuilder.length() - 1); + } + stringBuilder.append(")\n"); + } + return stringBuilder.toString(); } - }); + } + ``` + + 输出结果: + + ``` + class com.sun.proxy.$Proxy0 + -------------constructors list------------- + com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler) + -------------methods list------------- + add(java.lang.Object) + remove(java.lang.Object) + equals(java.lang.Object) + toString() + hashCode() + clear() + contains(java.lang.Object) + isEmpty() + iterator() + size() + toArray([Ljava.lang.Object;) + toArray() + spliterator() + addAll(java.util.Collection) + stream() + forEach(java.util.function.Consumer) + containsAll(java.util.Collection) + removeAll(java.util.Collection) + removeIf(java.util.function.Predicate) + retainAll(java.util.Collection) + parallelStream() + isProxyClass(java.lang.Class) + getInvocationHandler(java.lang.Object) + getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;) + newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler) + wait() + wait(long,int) + wait(long) + getClass() + notify() + notifyAll() + ``` + +- 创建实例对象 + + ```java + private static void createProxyInstance( ) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + + /** + * 方法1:先创建代理类,再使用反射创建实例对象 + */ + Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); + Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class); + Collection proxy1 = (Collection) constructor.newInstance(new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return null; + } + }); + + /** + * 方法2:直接使用newProxyInstance方法创建实例对象 + */ + Collection proxy2 = (Collection)Proxy.newProxyInstance( + Collection.class.getClassLoader(), + new Class[]{Collection.class}, + new InvocationHandler() { + ArrayList target = new ArrayList(); + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + //ArrayList targetTmp = new ArrayList(); + System.out.println("before invoke method: "+method.getName()); + return method.invoke(target,args); - proxy2.add("aaa"); - proxy2.add("bbb"); - System.out.println(proxy2.size()); - System.out.println(proxy2); - System.out.println(proxy2.getClass().getName()); + } + }); -} -``` + proxy2.add("aaa"); + proxy2.add("bbb"); + System.out.println(proxy2.size()); + System.out.println(proxy2); + System.out.println(proxy2.getClass().getName()); + } + ``` -输出结果: + 输出结果: -``` -before invoke method: add -before invoke method: add -before invoke method: size -2 -before invoke method: toString -[aaa, bbb] -com.sun.proxy.$Proxy0 -``` + ``` + before invoke method: add + before invoke method: add + before invoke method: size + 2 + before invoke method: toString + [aaa, bbb] + com.sun.proxy.$Proxy0 + ``` 上述代码相关说明: -- 若将`method.invoke(target,args);`改为`method.invoke(proxy,args);`会出现死循环 -- 从输出结果可知,每次调用代理类的方法,实际都是调用`invoke`方法 -- 若将`method.invoke(target,args);`改为`method.invoke(targetTmp,args);`,则`proxy2.size()`为0。因为每次调用`invoke`方法时,`targetTmp`为新的局部变量 -- `Object`类只有的`hashCode`, `equals`, or `toString`方法会被交到`InvocationHandler`,其他方法自己有实现,不交给handler,所以最后打印结果为`com.sun.proxy.$Proxy0`而不是`Collection` +- 若将`method.invoke(target,args);`改为`method.invoke(proxy,args);`会出现死循环 +- 从输出结果可知,每次调用代理类的方法,实际都是调用`invoke`方法 +- 若将`method.invoke(target,args);`改为`method.invoke(targetTmp,args);`,则`proxy2.size()`为0。因为每次调用`invoke`方法时,`targetTmp`为新的局部变量 +- `Object`类只有的`hashCode`, `equals`, or `toString`方法会被交到`InvocationHandler`,其他方法自己有实现,不交给handler,所以最后打印结果为`com.sun.proxy.$Proxy0`而不是`Collection` -- `InvocationHandler`对象的运行原理** +- `InvocationHandler`对象的运行原理** -`InvocationHandler`接口只有一个`invoke`方法,每次调用代理类的方法,即调用了`InvocationHandler`对象的`invoke`方法 + `InvocationHandler`接口只有一个`invoke`方法,每次调用代理类的方法,即调用了`InvocationHandler`对象的`invoke`方法 -`invoke`方法涉及三个要素: + `invoke`方法涉及三个要素: -- 代理对象 -- 代理对象调用的方法 -- 方法接受的参数 + - 代理对象 + - 代理对象调用的方法 + - 方法接受的参数 -注:Object类的`hashCode`,`equals`,`toString`方法交给invoke,其他的Object类的方法,Proxy有自己的实现。 - -> If a proxy interface contains a method with the same name and parameter signature as the hashCode, equals, or toString methods of java.lang.Object, when such a method is invoked on a proxy instance, the Method object passed to the invocation handler will have java.lang.Object as its declaring class. In other words, the public, non-final methods of java.lang.Object logically precede all of the proxy interfaces for the determination of which Method object to pass to the invocation handler. + 注:Object类的`hashCode`,`equals`,`toString`方法交给invoke,其他的Object类的方法,Proxy有自己的实现。 + > If a proxy interface contains a method with the same name and parameter + > signature as the hashCode, equals, or toString methods of java.lang.Object, + > when such a method is invoked on a proxy instance, the Method object passed + > to the invocation handler will have java.lang.Object as its declaring + > class. In other words, the public, non-final methods of java.lang.Object + > logically precede all of the proxy interfaces for the determination of + > which Method object to pass to the invocation handler. ### 动态代理的工作原理 @@ -249,8 +235,8 @@ com.sun.proxy.$Proxy0 所以需要传递两个参数: -1.目标(Object target) -2.通知(自定义的adviser类) +1. 目标(Object target) +2. 通知(自定义的adviser类) 定义`Advice`接口 @@ -303,7 +289,6 @@ private static Object getProxy(final Object target,final Advice advice){ } ``` - 调用: ```java @@ -325,14 +310,11 @@ size cost total 0 2 ``` - ## 参考资料 ->* [Java动态代理的实现机制](http://developer.51cto.com/art/201509/492614.htm) ->* [Java基础加强总结(三)——代理(Proxy)](http://www.cnblogs.com/xdp-gacl/p/3971367.html) +> * [Java动态代理的实现机制](http://developer.51cto.com/art/201509/492614.htm) +> * [Java基础加强总结(三)——代理(Proxy)](http://www.cnblogs.com/xdp-gacl/p/3971367.html) +--- - ---------- - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\345\256\236\347\216\260AOP\345\212\237\350\203\275\347\232\204\345\260\201\350\243\205\344\270\216\351\205\215\347\275\256\347\232\204\345\260\217\346\241\206\346\236\266.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\345\256\236\347\216\260AOP\345\212\237\350\203\275\347\232\204\345\260\201\350\243\205\344\270\216\351\205\215\347\275\256\347\232\204\345\260\217\346\241\206\346\236\266.md" index 62ec766..c261b25 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\345\256\236\347\216\260AOP\345\212\237\350\203\275\347\232\204\345\260\201\350\243\205\344\270\216\351\205\215\347\275\256\347\232\204\345\260\217\346\241\206\346\236\266.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(4)-\345\256\236\347\216\260AOP\345\212\237\350\203\275\347\232\204\345\260\201\350\243\205\344\270\216\351\205\215\347\275\256\347\232\204\345\260\217\346\241\206\346\236\266.md" @@ -6,18 +6,16 @@ **Contents** -- [java基础巩固笔记(4)-实现AOP功能的封装与配置的小框架](#java基础巩固笔记4-实现aop功能的封装与配置的小框架) - - [设计](#设计) -- [xxx=java.util.ArrayList](#xxxjavautilarraylist) - - [代码](#代码) - - [`Advice`接口](#advice接口) - - [`MyAdvice`类](#myadvice类) - - [`BeanFactory`类](#beanfactory类) - - [`ProxyFactoryBean`类](#proxyfactorybean类) - - [`AopFrameWorkTest`类](#aopframeworktest类) - - [输出](#输出) - - +- [java基础巩固笔记(4)-实现AOP功能的封装与配置的小框架](#java基础巩固笔记4-实现aop功能的封装与配置的小框架) + - [设计](#设计) +- [xxx=java.util.ArrayList](#xxxjavautilarraylist) + - [代码](#代码) + - [`Advice`接口](#advice接口) + - [`MyAdvice`类](#myadvice类) + - [`BeanFactory`类](#beanfactory类) + - [`ProxyFactoryBean`类](#proxyfactorybean类) + - [`AopFrameWorkTest`类](#aopframeworktest类) + - [输出](#输出) --- @@ -46,15 +44,11 @@ xxx.target=java.util.ArrayList 包:`com.iot.proxy.aopframework`,有如下几个类/接口: -- `BeanFactory`,用于读取配置文件,根据配置创建相应的对象 -- `ProxyFactoryBean`,用于生成代理对象,含有两个私有属性:目标和通知 -- `Advice`,通知接口,用于把切面的代码以**对象**的形式传递给InvocationHandler的的invoke方法 -- `MyAdvice`,`Advice`接口的一个实现类,打印执行方法前的时间及执行耗时 -- `AopFrameWorkTest`,测试效果 - - - - +- `BeanFactory`,用于读取配置文件,根据配置创建相应的对象 +- `ProxyFactoryBean`,用于生成代理对象,含有两个私有属性:目标和通知 +- `Advice`,通知接口,用于把切面的代码以**对象**的形式传递给InvocationHandler的的invoke方法 +- `MyAdvice`,`Advice`接口的一个实现类,打印执行方法前的时间及执行耗时 +- `AopFrameWorkTest`,测试效果 ## 代码 @@ -64,9 +58,7 @@ xxx.target=java.util.ArrayList package com.iot.proxy.aopframework; import java.lang.reflect.Method; -/** - * Created by brian on 2016/2/2. - */ + public interface Advice { void beforeMethod(Method method); void aftereMethod(Method method); @@ -80,9 +72,6 @@ package com.iot.proxy.aopframework; import java.lang.reflect.Method; -/** - * Created by brian on 2016/2/2. - */ public class MyAdvice implements Advice{ long beginTime = 0 ; @Override @@ -99,7 +88,6 @@ public class MyAdvice implements Advice{ } ``` - ### `BeanFactory`类 ```java @@ -109,9 +97,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.Properties; -/** - * Created by brian on 2016/2/2. - */ public class BeanFactory { Properties properties = new Properties(); public BeanFactory(InputStream inputStream){ @@ -122,7 +107,7 @@ public class BeanFactory { } } - public Object getBean(String name){ + public Object getBean(String name) { String className = properties.getProperty(name); Object bean = null; try { @@ -169,9 +154,6 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -/** - * Created by brian on 2016/2/3. - */ public class ProxyFactoryBean { private Object target; private Advice advice; @@ -211,7 +193,6 @@ public class ProxyFactoryBean { } ``` - ### `AopFrameWorkTest`类 ```java @@ -220,9 +201,6 @@ package com.iot.proxy.aopframework; import java.io.InputStream; import java.util.Collection; -/** - * Created by brian on 2016/2/3. - */ public class AopFrameWorkTest { public static void main(String[] args) { InputStream inputStream = AopFrameWorkTest.class.getResourceAsStream("config.properties"); @@ -235,7 +213,7 @@ public class AopFrameWorkTest { ## 输出 -- 配置`xxx=com.iot.proxy.aopframework.ProxyFactoryBean` +- 配置 `xxx=com.iot.proxy.aopframework.ProxyFactoryBean` 输出为: @@ -245,7 +223,7 @@ clear before at 0 clear cost total 0 ``` -- 配置`xxx=java.util.ArrayList` +- 配置`xxx=java.util.ArrayList` 输出为: @@ -253,11 +231,8 @@ clear cost total 0 java.util.ArrayList ``` +**可以看出,只改变配置文件,就可改变代码的运行结果,从而达到灵活的效果** -可以看出,只改变配置文件,就可改变代码的运行结果,从而达到灵活的效果 - - - ------- +--- -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\344\274\240\347\273\237\345\244\232\347\272\277\347\250\213.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\344\274\240\347\273\237\345\244\232\347\272\277\347\250\213.md" index d058278..87b9a42 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\344\274\240\347\273\237\345\244\232\347\272\277\347\250\213.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\344\274\240\347\273\237\345\244\232\347\272\277\347\250\213.md" @@ -6,42 +6,37 @@ **Contents** -- [java基础巩固笔记(5)-多线程之传统多线程](#java基础巩固笔记5-多线程之传统多线程) -- [传统线程技术](#传统线程技术) - - [传统创建线程方式](#传统创建线程方式) - - [传统定时器技术](#传统定时器技术) - - [互斥](#互斥) - - [同步](#同步) - - +- [java基础巩固笔记(5)-多线程之传统多线程](#java基础巩固笔记5-多线程之传统多线程) +- [传统线程技术](#传统线程技术) + - [传统创建线程方式](#传统创建线程方式) + - [传统定时器技术](#传统定时器技术) + - [互斥](#互斥) + - [同步](#同步) --- - - # 传统线程技术 - ## 传统创建线程方式 -1.继承Thread类,覆盖run方法 +1. 继承Thread类,覆盖run方法 -```java -Thread t = new Thread(); -t.start(); -``` + ```java + Thread t = new Thread(); + t.start(); + ``` -2.实现Runnable接口 +2. 实现Runnable接口 -Runnable不是线程,是线程要运行的代码的宿主。 + Runnable不是线程,是线程要运行的代码的宿主。 -1.看看Thread类源码,捋清Runnable,target,run,start关系 +## 看看Thread类源码,捋清Runnable,target,run,start关系 -- `Runnable`是一个接口 -- `target`是`Thread`类中类型为`Runnable`,名为`target`的属性 -- `run`是`Thread`类实现了`Runnable`的接口,重写的方法。 -- `start`是启动线程的方法 -- **在`Thread`类中,调用关系为:`start`->`start0`->`run`->`target.run`** +- `Runnable`是一个接口 +- `target`是`Thread`类中类型为`Runnable`,名为`target`的属性 +- `run`是`Thread`类实现了`Runnable`的接口,重写的方法。 +- `start`是启动线程的方法 +- **在`Thread`类中,调用关系为:`start`->`start0`->`run`->`target.run`** `Thread`类的`run`方法源码 @@ -56,24 +51,18 @@ public void run() { `Thread`类的`target`属性 ```java -/* What will be run. */ private Runnable target; ``` `target`属性由`private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc)`方法初始化。`init`方法在`Thread`类的构造方法里被调用 - - - -2.匿名内部类对象的构造方法如何调用父类的非默认构造方法 - - +## 匿名内部类对象的构造方法如何调用父类的非默认构造方法 ## 传统定时器技术 API: ->[java.util:Class Timer](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Timer.html) +> [java.util:Class Timer](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Timer.html) 例子:一个定时器实现交替2秒、3秒打印 @@ -94,25 +83,22 @@ public static void main(String[] args) { } ``` -可以使用`quarlz`开源工具 - - - +可以使用 `quarlz` 开源工具 ## 互斥 关键字:`synchronized`,检查锁对象 -- `synchronized(this)` -- `synchronized void function(){}` -- `synchronized(A.class)` +- `synchronized(this)` +- `synchronized void function(){}` +- `synchronized(A.class)` ## 同步 经验: ->* 要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计体现了高聚类和程序的健壮性。 ->* 同步互斥不是在线程上实现,而是在线程访问的资源上实现,线程调用资源。 +> * 要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计体现了高聚类和程序的健壮性。 +> * 同步互斥不是在线程上实现,而是在线程访问的资源上实现,线程调用资源。 例子: 子线程循环5次,主线程循环10次,如此交替50次 @@ -123,9 +109,6 @@ public static void main(String[] args) { 代码: ```java -/** - * Created by brian on 2016/2/4. - */ public class TraditionalThreadCommunication { public static void main(String[] args) { Business business = new Business(); @@ -183,7 +166,6 @@ class Business{ 判断条件时,while与if的区别:while防止伪唤醒 +--- ------------------- - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\345\205\261\344\272\253\346\225\260\346\215\256.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\345\205\261\344\272\253\346\225\260\346\215\256.md" index 75bbaa0..2f635e6 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\345\205\261\344\272\253\346\225\260\346\215\256.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\345\205\261\344\272\253\346\225\260\346\215\256.md" @@ -6,19 +6,18 @@ **Contents** -- [java基础巩固笔记(5)-多线程之共享数据](#java基础巩固笔记5-多线程之共享数据) - - [线程范围内共享数据](#线程范围内共享数据) - - [ThreadLocal类](#threadlocal类) - - [多线程访问共享数据](#多线程访问共享数据) - - [几种方式](#几种方式) - - +- [java基础巩固笔记(5)-多线程之共享数据](#java基础巩固笔记5-多线程之共享数据) + - [线程范围内共享数据](#线程范围内共享数据) + - [ThreadLocal类](#threadlocal类) + - [多线程访问共享数据](#多线程访问共享数据) + - [几种方式](#几种方式) --- +本文主要总结线程共享数据的相关知识,主要包括两方面: -本文主要总结线程共享数据的相关知识,主要包括两方面:一是某个线程内如何共享数据,保证各个线程的数据不交叉;一是多个线程间如何共享数据,保证数据的一致性。 - +- 一是某个线程内如何共享数据,保证各个线程的数据不交叉; +- 一是多个线程间如何共享数据,保证数据的一致性。 ## 线程范围内共享数据 @@ -33,46 +32,40 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; -/** - * Created by brian on 2016/2/4. - */ public class ThreadScopeShareData { //准备一个哈希表,为每个线程准备数据 - private static Map threadData = new HashMap<>(); + private static Map threadData = new HashMap<>(); public static void main(String[] args) { for(int i=0;i<2;i++){ new Thread( new Runnable() { - @Override - public void run() { - int data = new Random().nextInt(); - threadData.put(Thread.currentThread(),data); - System.out.println(Thread.currentThread()+" put data:"+data); - new A().get(); - new B().get(); - } - }).start(); + @Override + public void run() { + int data = new Random().nextInt(); + threadData.put(Thread.currentThread(),data); + System.out.println(Thread.currentThread()+" put data:"+data); + new A().get(); + new B().get(); + } + }).start(); } } - static class A{ + static class A{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("A from "+Thread.currentThread()+" get data "+data); } } - static class B{ + static class B{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("B from "+Thread.currentThread()+" get data "+data); } } } - - ``` - 上述代码偶尔会报异常: ``` @@ -80,133 +73,122 @@ Exception in thread "Thread-0" java.lang.NullPointerException at com.iot.thread.ThreadScopeShareData$A.get(ThreadScopeShareData.java:29) at com.iot.thread.ThreadScopeShareData$1.run(ThreadScopeShareData.java:21) at java.lang.Thread.run(Thread.java:745) - ``` 具体原因还不知道 +。。。。。。因为你特么还没有 put 啊……GET 不到啊哥哥。 ### ThreadLocal类 API: -> [`java.lang:Class ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/ThreadLocal.html) +> [`java.lang:Class ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/ThreadLocal.html) -- 单变量 +- 单变量 -使用`ThreadLocal`类型的对象代替上面的`Map`即可 + 使用`ThreadLocal`类型的对象代替上面的`Map`即可 -- 多变量 +- 多变量 -定义一个对象来封装多个变量,然后在ThreadLocal中存储整个对象 + 定义一个对象来封装多个变量,然后在ThreadLocal中存储整个对象 -多变量时,最好将ThreadLocal类放在数据类的内部,数据类采用单例模式,这样,新建对象和获取对象都会更方便,同时封装性更强。 + 多变量时,最好将ThreadLocal类放在数据类的内部,数据类采用单例模式,这样,新建对象和获取对象都会更方便,同时封装性更强。 -示例代码: + 示例代码: -```java -package com.iot.thread; + ```java + package com.iot.thread; -import java.util.Random; + import java.util.Random; -/** - * Created by brian on 2016/2/4. - */ -public class ThreadLocalTest { - private static ThreadLocal threadInger = new ThreadLocal<>(); - public static void main(String[] args) { - for(int i=0;i<2;i++){ - new Thread(new Runnable() { - @Override - public void run() { - int data = new Random().nextInt(100); - threadInger.set(data); - System.out.println(Thread.currentThread()+" put data:"+data); - MyThreadScopeData.getThreadInstance().setName(Thread.currentThread().toString()); - MyThreadScopeData.getThreadInstance().setAge(data%10); - new A().get(); - new B().get(); - } - }).start(); + public class ThreadLocalTest { + private static ThreadLocal threadInger = new ThreadLocal<>(); + public static void main(String[] args) { + for(int i=0;i<2;i++){ + new Thread(new Runnable() { + @Override + public void run() { + int data = new Random().nextInt(100); + threadInger.set(data); + System.out.println(Thread.currentThread()+" put data:"+data); + MyThreadScopeData.getThreadInstance().setName(Thread.currentThread().toString()); + MyThreadScopeData.getThreadInstance().setAge(data%10); + new A().get(); + new B().get(); + } + }).start(); + } } - } - static class A{ - public void get(){ - int data = threadInger.get(); - System.out.println("A from "+Thread.currentThread()+" get data "+data); - MyThreadScopeData myThreadScopeData = MyThreadScopeData.getThreadInstance(); - System.out.println("A from "+myThreadScopeData); - + static class A{ + public void get(){ + int data = threadInger.get(); + System.out.println("A from "+Thread.currentThread()+" get data "+data); + MyThreadScopeData myThreadScopeData = MyThreadScopeData.getThreadInstance(); + System.out.println("A from "+myThreadScopeData); + + } } - } - static class B{ - public void get(){ - int data = threadInger.get(); - System.out.println("B from "+Thread.currentThread()+" get data "+data); - MyThreadScopeData myThreadScopeData = MyThreadScopeData.getThreadInstance(); - System.out.println("B from "+myThreadScopeData); + static class B{ + public void get(){ + int data = threadInger.get(); + System.out.println("B from "+Thread.currentThread()+" get data "+data); + MyThreadScopeData myThreadScopeData = MyThreadScopeData.getThreadInstance(); + System.out.println("B from "+myThreadScopeData); + } } } -} -/** - * 将多变量封装起来的数据类 - * 单例模式,内置ThreadLocal类型变量 - */ -class MyThreadScopeData{ + class MyThreadScopeData{ - private MyThreadScopeData(){} + private MyThreadScopeData(){} - private static ThreadLocal data = new ThreadLocal<>(); + private static ThreadLocal data = new ThreadLocal<>(); - public static MyThreadScopeData getThreadInstance(){ - MyThreadScopeData instance = data.get(); - if(instance == null){ - instance = new MyThreadScopeData(); - data.set(instance); + public static MyThreadScopeData getThreadInstance(){ + MyThreadScopeData instance = data.get(); + if(instance == null){ + instance = new MyThreadScopeData(); + data.set(instance); + } + return instance; } - return instance; - } + private String name; + private int age; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } - private String name; - private int age; - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } + public int getAge() { + return age; + } - public void setAge(int age) { - this.age = age; - } + public void setAge(int age) { + this.age = age; + } - @Override - public String toString() { - String reVal = super.toString()+"-{name,age}"+":{"+getName()+","+getAge()+"}"; - return reVal; + @Override + public String toString() { + String reVal = super.toString()+"-{name,age}"+":{"+getName()+","+getAge()+"}"; + return reVal; + } } -} -``` - + ``` ## 多线程访问共享数据 ### 几种方式 -- 线程执行代码相同,使用同一Runnable对象,Runnable对象中有共享数据 -- 线程执行代码不同,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),将这个对象逐一传递给各个Runnable对象。[**本质:共享数据的对象作为参数传入Runnable对象**] -- 线程执行代码不同,将Runnable对象作为某一个类的内部类,共享数据作为这个外部类的成员变量(操作数据的方法放在外部类)。[**本质:不同内部类共享外部类数据**] -- 结合上两种方式,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),该对象作为这个外部类的成员变量,将Runnable对象作为内部类 - +- 线程执行代码相同,使用同一Runnable对象,Runnable对象中有共享数据 +- 线程执行代码不同,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),将这个对象逐一传递给各个Runnable对象。[**本质:共享数据的对象作为参数传入Runnable对象**] +- 线程执行代码不同,将Runnable对象作为某一个类的内部类,共享数据作为这个外部类的成员变量(操作数据的方法放在外部类)。[**本质:不同内部类共享外部类数据**] +- 结合上两种方式,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),该对象作为这个外部类的成员变量,将Runnable对象作为内部类 最后一种方式的示例: @@ -271,14 +253,6 @@ class MutiShareData{ } ``` +--- ------ - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) - - - - - - - +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\347\272\277\347\250\213\345\271\266\345\217\221\345\272\223.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\347\272\277\347\250\213\345\271\266\345\217\221\345\272\223.md" index a897a8f..c770261 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\347\272\277\347\250\213\345\271\266\345\217\221\345\272\223.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(5)-\345\244\232\347\272\277\347\250\213\344\271\213\347\272\277\347\250\213\345\271\266\345\217\221\345\272\223.md" @@ -6,24 +6,22 @@ **Contents** -- [java基础巩固笔记(5)-多线程之线程并发库](#java基础巩固笔记5-多线程之线程并发库) - - [原子性操作类](#原子性操作类) - - [线程池](#线程池) - - [常用线程池](#常用线程池) - - [Callable&Future](#callablefuture) - - [Lock&Condition](#lockcondition) - - [Lock](#lock) - - [Condition](#condition) - - [同步工具](#同步工具) - - [参考资料](#参考资料) - - +- [java基础巩固笔记(5)-多线程之线程并发库](#java基础巩固笔记5-多线程之线程并发库) + - [原子性操作类](#原子性操作类) + - [线程池](#线程池) + - [常用线程池](#常用线程池) + - [Callable&Future](#callablefuture) + - [Lock&Condition](#lockcondition) + - [Lock](#lock) + - [Condition](#condition) + - [同步工具](#同步工具) + - [参考资料](#参考资料) --- 本文主要概述`java.util.concurrent`包下的相关类和使用方法 -> [Package java.util.concurrent](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html) +> [Package java.util.concurrent](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html) ## 原子性操作类 @@ -235,9 +233,6 @@ class BoundedBuffer { >* [深入浅出 Java Concurrency (29): 线程池 part 2 Executor 以及Executors](http://www.blogjava.net/xylz/archive/2010/12/21/341281.html) >* [《深入浅出 Java Concurrency》目录](http://www.blogjava.net/xylz/archive/2010/07/08/325587.html) +---- - ------- - - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(6)-\346\263\250\350\247\243.md" "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(6)-\346\263\250\350\247\243.md" index 0d070dd..0b6a964 100644 --- "a/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(6)-\346\263\250\350\247\243.md" +++ "b/blogs/javase/java\345\237\272\347\241\200\345\267\251\345\233\272\347\254\224\350\256\260(6)-\346\263\250\350\247\243.md" @@ -6,23 +6,20 @@ **Contents** - - [注解的应用结构图](#注解的应用结构图) - - [元注解](#元注解) - - [自定义注解](#自定义注解) - - [示例代码](#示例代码) - - [参考资料](#参考资料) - - +- [注解的应用结构图](#注解的应用结构图) +- [元注解](#元注解) +- [自定义注解](#自定义注解) +- [示例代码](#示例代码) +- [参考资料](#参考资料) --- - -注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 - +注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性, +与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 API -> [Package java.lang.annotation](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/annotation/package-summary.html) +> [Package java.lang.annotation](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/annotation/package-summary.html) ## 注解的应用结构图 @@ -56,64 +53,59 @@ Class C{ } ``` -## 元注解 +## **元注解** 元注解的作用就是负责注解其他注解。四个元注解分别是:`@Target,@Retention,@Documented,@Inherited` -- `@Retention` +- `@Retention` -表示在什么级别保存该注解信息。可选的参数值在枚举类型 `RetentionPolicy`中,包括`RetentionPolicy.SOURCE`,`RetentionPolicy.CLASS`(默认),`RetentionPolicy.RUNTIME`分别对应:java源文件-->class文件-->内存中的字节码 + 表示在什么级别保存该注解信息。可选的参数值在枚举类型 `RetentionPolicy`中,包括`RetentionPolicy.SOURCE`,`RetentionPolicy.CLASS`(默认),`RetentionPolicy.RUNTIME`分别对应:java源文件-->class文件-->内存中的字节码 -``` -RetentionPolicy.SOURCE 注解将被编译器丢弃 -RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃 -RetentionPolicy.RUNTIME VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息。 -``` + ``` + RetentionPolicy.SOURCE 注解将被编译器丢弃 + RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃 + RetentionPolicy.RUNTIME VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息。 + ``` -- `@Target` +- `@Target` -表示该注解用于什么地方,可能的值在枚举类`ElemenetType`中,包括 + 表示该注解用于什么地方,可能的值在枚举类`ElemenetType`中,包括 -``` -ElemenetType.CONSTRUCTOR 构造器声明 -ElemenetType.FIELD 域声明(包括 enum 实例) -ElemenetType.LOCAL_VARIABLE 局部变量声明 -ElemenetType.METHOD 方法声明 -ElemenetType.PACKAGE 包声明 -ElemenetType.PARAMETER 参数声明 -ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 -``` - -- `@Documented` - -将此注解包含在javadoc中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当于`@see,@param`等 + ``` + ElemenetType.CONSTRUCTOR 构造器声明 + ElemenetType.FIELD 域声明(包括 enum 实例) + ElemenetType.LOCAL_VARIABLE 局部变量声明 + ElemenetType.METHOD 方法声明 + ElemenetType.PACKAGE 包声明 + ElemenetType.PARAMETER 参数声明 + ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 + ``` +- `@Documented` + 将此注解包含在javadoc中, + 它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当于`@see,@param`等 -- `@Inherited` - -允许子类继承父类中的注解 +- `@Inherited` + 允许子类继承父类中的注解 ## 自定义注解 **使用`@interface`自定义注解时,自动继承了`java.lang.annotation.Annotation`接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。`@interface`用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。** - 定义注解格式: `public @interface 注解名 {定义体}` 注解参数的可支持数据类型: -1.所有基本数据类型(int,float,boolean,byte,double,char,long,short) -2.String类型 -3.Class类型 -4.enum类型 -5.Annotation类型 -6.以上所有类型的数组 - - +1. 所有基本数据类型(int,float,boolean,byte,double,char,long,short) +2. String类型 +3. Class类型 +4. enum类型 +5. Annotation类型 +6. 以上所有类型的数组 ## 示例代码 @@ -121,164 +113,147 @@ ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 下面的示例,是上文提到的**A<--B<--C**的扩充版本。自定义了一个注解`@A`,然后在B类中使用了注解`@A`,最后在类C中利用反射读取`@A`中的信息 -- `A.java` +- `A.java` -```java -package com.iot.annotation; - -import java.lang.annotation.*; - -/** - * Created by brian on 2016/2/20. - */ -@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR}) -@Retention(RetentionPolicy.RUNTIME) -public @interface A { - String name(); - int id() default 0; - Class gid(); -} -``` + ```java + package com.iot.annotation; -- `B.java` + import java.lang.annotation.*; -```java -package com.iot.annotation; + @Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR}) + @Retention(RetentionPolicy.RUNTIME) + public @interface A { + String name(); + int id() default 0; + Class gid(); + } + ``` -import java.util.HashMap; -import java.util.Map; +- `B.java` -/** - * Created by brian on 2016/2/20. - */ -@A(name="type",gid=Long.class)//类注解 -public class B { - @A(name="param",id=1,gid=Long.class) //类成员注解 - private Integer age; + ```java + package com.iot.annotation; - @A(name="construct",id=2,gid=Long.class) //构造方法注解 - public B(){} + import java.util.HashMap; + import java.util.Map; - @A(name="public method",id=3,gid=Long.class) //类方法注解 - public void a(){ + @A(name="type",gid=Long.class)//类注解 + public class B { + @A(name="param",id=1,gid=Long.class) //类成员注解 + private Integer age; - } + @A(name="construct",id=2,gid=Long.class) //构造方法注解 + public B(){} - @A(name="protected method",id=4,gid=Long.class) //类方法注解 - protected void b(){ - Map m = new HashMap(0); - } + @A(name="public method",id=3,gid=Long.class) //类方法注解 + public void a(){ + } - @A(name="private method",id=5,gid=Long.class) //类方法注解 - private void c(){ - Map m = new HashMap(0); - } + @A(name="protected method",id=4,gid=Long.class) //类方法注解 + protected void b(){ + Map m = new HashMap(0); + } + + @A(name="private method",id=5,gid=Long.class) //类方法注解 + private void c(){ + Map m = new HashMap(0); + } - public void b(Integer a){ + public void b(Integer a){ + } } -} + ``` -``` +- `C.java` -- `C.java` + ```java + package com.iot.annotation; -```java -package com.iot.annotation; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -/** - * Created by brian on 2016/2/20. - */ -public class C { - - /** - * 简单打印出B类中所使用到的类注解 - * 该方法只打印了 Type 类型的注解 - * @throws ClassNotFoundException - */ - public static void parseTypeAnnotation() throws ClassNotFoundException{ - Class clazz = Class.forName("com.iot.annotation.B"); - - Annotation[] annotations = clazz.getAnnotations(); - for(Annotation annotation :annotations){ - A a = (A)annotation; - System.out.println("id = "+a.id()+" ;name = "+a.name()+" ;gid = "+a.gid()); - } + import java.lang.annotation.Annotation; + import java.lang.reflect.Constructor; + import java.lang.reflect.Method; - } + public class C { - /** - * 简单打印出B类中所使用到的方法注解 - * 该方法只打印了 Method 类型的注解 - */ - public static void parseMethodAnnotation() { - Method[] methods = B.class.getDeclaredMethods(); - for (Method method : methods) { - /* - * 判断方法中是否有指定注解类型的注解 - */ - boolean hasAnnotation = method.isAnnotationPresent(A.class); - if (hasAnnotation) { - /* - * 根据注解类型返回方法的指定类型注解 - */ - A annotation = method.getAnnotation(A.class); - System.out.println("method = " + method.getName() - + " ; id = " + annotation.id() + " ; description = " - + annotation.name() + "; gid= " + annotation.gid()); + /** + * 简单打印出B类中所使用到的类注解 + * 该方法只打印了 Type 类型的注解 + * @throws ClassNotFoundException + */ + public static void parseTypeAnnotation() throws ClassNotFoundException{ + Class clazz = Class.forName("com.iot.annotation.B"); + + Annotation[] annotations = clazz.getAnnotations(); + for(Annotation annotation :annotations){ + A a = (A)annotation; + System.out.println("id = "+a.id()+" ;name = "+a.name()+" ;gid = "+a.gid()); } + } - } - /** - * 简单打印出B类中所使用到的方法注解 - * 该方法只打印了 Method 类型的注解 - */ - public static void parseConstructAnnotation(){ - Constructor[] constructors = B.class.getConstructors(); - for (Constructor constructor : constructors) { - /* - * 判断构造方法中是否有指定注解类型的注解 - */ - boolean hasAnnotation = constructor.isAnnotationPresent(A.class); - if (hasAnnotation) { + /** + * 简单打印出B类中所使用到的方法注解 + * 该方法只打印了 Method 类型的注解 + */ + public static void parseMethodAnnotation() { + Method[] methods = B.class.getDeclaredMethods(); + for (Method method : methods) { /* - * 根据注解类型返回方法的指定类型注解 - */ - A annotation =(A) constructor.getAnnotation(A.class); - System.out.println("constructor = " + constructor.getName() - + " ; id = " + annotation.id() + " ; description = " - + annotation.name() + "; gid= "+annotation.gid()); + * 判断方法中是否有指定注解类型的注解 + */ + boolean hasAnnotation = method.isAnnotationPresent(A.class); + if (hasAnnotation) { + /* + * 根据注解类型返回方法的指定类型注解 + */ + A annotation = method.getAnnotation(A.class); + System.out.println("method = " + method.getName() + + " ; id = " + annotation.id() + " ; description = " + + annotation.name() + "; gid= " + annotation.gid()); + } } } - } - public static void main(String[] args) throws ClassNotFoundException { - parseTypeAnnotation(); - parseMethodAnnotation(); - parseConstructAnnotation(); - } + /** + * 简单打印出B类中所使用到的方法注解 + * 该方法只打印了 Method 类型的注解 + */ + public static void parseConstructAnnotation(){ + Constructor[] constructors = B.class.getConstructors(); + for (Constructor constructor : constructors) { + /* + * 判断构造方法中是否有指定注解类型的注解 + */ + boolean hasAnnotation = constructor.isAnnotationPresent(A.class); + if (hasAnnotation) { + /* + * 根据注解类型返回方法的指定类型注解 + */ + A annotation =(A) constructor.getAnnotation(A.class); + System.out.println("constructor = " + constructor.getName() + + " ; id = " + annotation.id() + " ; description = " + + annotation.name() + "; gid= "+annotation.gid()); + } + } + } -} + public static void main(String[] args) throws ClassNotFoundException { + parseTypeAnnotation(); + parseMethodAnnotation(); + parseConstructAnnotation(); + } -``` + } + ``` ## 参考资料 ->* [java 注解的几大作用及使用方法详解(完)](http://blog.csdn.net/tigerdsh/article/details/8848890) ->* [另类的package-info.java文件探讨](http://strong-life-126-com.iteye.com/blog/806246) ->* [深入理解Java:注解(Annotation)自定义注解入门](http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html) +> * [java 注解的几大作用及使用方法详解(完)](http://blog.csdn.net/tigerdsh/article/details/8848890) +> * [另类的package-info.java文件探讨](http://strong-life-126-com.iteye.com/blog/806246) +> * [深入理解Java:注解(Annotation)自定义注解入门](http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html) +--- - - ------------- - - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) - +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(1)-Tomcat.md" "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(1)-Tomcat.md" index cf97372..2de3251 100644 --- "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(1)-Tomcat.md" +++ "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(1)-Tomcat.md" @@ -6,37 +6,31 @@ **Contents** -- [javaweb入门笔记(1)-Tomcat](#javaweb入门笔记1-tomcat) - - [Tomcat目录层次结构](#tomcat目录层次结构) - - [启动Tomcat](#启动tomcat) - - [官当配置文档](#官当配置文档) - - [web应用](#web应用) - - [Tomcat体系结构](#tomcat体系结构) - - [相关小知识](#相关小知识) - - [参考链接](#参考链接) - - +- [javaweb入门笔记(1)-Tomcat](#javaweb入门笔记1-tomcat) + - [Tomcat目录层次结构](#tomcat目录层次结构) + - [启动Tomcat](#启动tomcat) + - [官当配置文档](#官当配置文档) + - [web应用](#web应用) + - [Tomcat体系结构](#tomcat体系结构) + - [相关小知识](#相关小知识) + - [参考链接](#参考链接) ---- - - - 下载链接 ->* [Apache Jakarta Project](http://jakarta.apache.org) ->* [Tomcat官网](http://tomcat.apache.org/) - +> * [Apache Jakarta Project](http://jakarta.apache.org) +> * [Tomcat官网](http://tomcat.apache.org/) ## Tomcat目录层次结构 -- bin:存放启动和关闭Tomcat的脚本文件 -- conf:存放Tomcat服务器的配置文件 -- lib:存放Tomcat服务器的支撑jar包 -- logs:存放Tomcat的日志文件 -- temp:存放Tomcat运行时产生的临时文件 -- webapps:web应用所在的目录,即供外接访问的web资源的存放目录 -- work:Tomcat的工作目录 +- bin:存放启动和关闭Tomcat的脚本文件 +- conf:存放Tomcat服务器的配置文件 +- lib:存放Tomcat服务器的支撑jar包 +- logs:存放Tomcat的日志文件 +- temp:存放Tomcat运行时产生的临时文件 +- webapps:web应用所在的目录,即供外接访问的web资源的存放目录 +- work:Tomcat的工作目录 上面的内容直接可在[Tomcat Doc-Directories and Files](http://tomcat.apache.org/tomcat-8.0-doc/introduction.html#Terminology)找到答案 @@ -53,83 +47,75 @@ - Catalina_home环境变量的设置问题 ## 官当配置文档 + 多种配置方式 -- `/META-INF/context.xml` -- `$CATALINA_BASE/conf/[enginename]/[hostname]/` -- `conf/server.xml` +- `/META-INF/context.xml` +- `$CATALINA_BASE/conf/[enginename]/[hostname]/` +- `conf/server.xml` -> 具体参考[Context配置](http://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context) +> 具体参考[Context配置](http://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context) ## web应用 -1.web应用与web应用所在的目录 -一个**web应用**由多个静态web资源和动态web资源组成;组成web应用的这些文件会由一个目录组织起来,这个目录称为**web应用所在目录** +1. web应用与web应用所在的目录 + 一个**web应用**由多个静态web资源和动态web资源组成;组成web应用的这些文件会由一个目录组织起来,这个目录称为**web应用所在目录** -2.虚拟目录的映射 -把主机上的资源映射到服务器对外提供的访问路径上 +2. 虚拟目录的映射 -3.例子 + 把主机上的资源映射到服务器对外提供的访问路径上 -tomcat的`conf/server.xml`:``元素->``,一个``对应一个web应用。 +3. 例子 -``,重启web服务器 + tomcat的`conf/server.xml`:``元素->``,一个``对应一个web应用。 -4.web应用的组成结构 + ``,重启web服务器 -``` -mail---------------------------Web应用所在目录 - |----html、jsp、css、js等文件,根目录下的文件外界可以直接访问 - |----WEB-INF目录 - |---------classes目录(java类) - |---------lib目录(java类运行所需的jar包) - |---------web.xml(web应用的配置文件) - WEB-INF 这个目录下的文件外界无法直接访问,由web服务器负责调用 -``` +4. web应用的组成结构 + ``` + mail---------------------------Web应用所在目录 + |----html、jsp、css、js等文件,根目录下的文件外界可以直接访问 + |----WEB-INF目录 + |---------classes目录(java类) + |---------lib目录(java类运行所需的jar包) + |---------web.xml(web应用的配置文件) + WEB-INF 这个目录下的文件外界无法直接访问,由web服务器负责调用 + ``` ## Tomcat体系结构 ![Tomcat体系结构](http://7xph6d.com1.z0.glb.clouddn.com/javaweb_tomcat%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84.png) +- tomcat的https连接器 + `keytool -genkey alias tomcat -keyalg RSA`得到`.keystore`文件 -- tomcat的https连接器 - -`keytool -genkey alias tomcat -keyalg RSA`得到`.keystore`文件 - - -- Tomcat管理平台 -主页->Tomcat Manager - -相关权限和用户配置在`conf/tomcat-users.xml` - +- Tomcat管理平台 + 主页->Tomcat Manager + 相关权限和用户配置在`conf/tomcat-users.xml` ## 相关小知识 -1.域名和主机名的区别 +1. 域名和主机名的区别 -| 域名 | sina.com | -| -------: | :----: | :----: | -| 主机名 | www.sina.com | + | 域名 | sina.com | + | -------: | :----: | :----: | + | 主机名 | www.sina.com | +2. url中主机名的作用: -2.url中主机名的作用: - -- 用于访问DNS服务器获取IP -- 用于告诉代理服务器要访问哪个主机名 - + - 用于访问DNS服务器获取IP + - 用于告诉代理服务器要访问哪个主机名 ## 参考链接 -> [Tomcat安装、配置、优化及负载均衡详解 +> [Tomcat安装、配置、优化及负载均衡详解 ](http://www.cnblogs.com/rocomp/p/4802396.html) +--- ------ - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) - +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(2)-http\345\205\245\351\227\250.md" "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(2)-http\345\205\245\351\227\250.md" index 86cce6a..7a9933d 100644 --- "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(2)-http\345\205\245\351\227\250.md" +++ "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(2)-http\345\205\245\351\227\250.md" @@ -6,41 +6,37 @@ **Contents** -- [javaweb入门笔记(2)-http入门](#javaweb入门笔记2-http入门) - - [请求(Request)](#请求request) - - [请求头字段](#请求头字段) - - [响应(Response)](#响应response) - - [响应状态行](#响应状态行) - - [响应头字段](#响应头字段) +- [javaweb入门笔记(2)-http入门](#javaweb入门笔记2-http入门) + - [请求(Request)](#请求request) + - [请求头字段](#请求头字段) + - [响应(Response)](#响应response) + - [响应状态行](#响应状态行) + - [响应头字段](#响应头字段) - - ----- +--- 对HTTP协议早有了解,最近在看javaweb,视频中讲到了这部分,就把视频的内容整理归纳下 - - ## 请求(Request) 一个完整的HTTP请求包括:一个请求行、若干请求头、以及实体内容 ### 请求头字段 -- Accept:用于告诉服务器,客户机支持的数据类型 -- Accept-Charset:用于告诉服务器,客户机采用的编码 -- Accept-Encoding:用于告诉服务器,客户机支持数据压缩格式 -- Accept-Language:客户机的语言环境 -- Host:客户机通过这个头告诉服务器,想访问的主机名 -- If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间 -- Refer:客户机通过这个头告诉服务器,它是从哪个资源访问服务器的(防盗链) -- User-Agent:客户机通过这个头告诉服务器,客户机的软件环境 -- Cookie:客户机通过这个头向服务器带数据 -- Connection:这个请求完了,是保持连接还是关闭 -- Range:断点下载 - - `bytes=n1-n2`,传输范围n1到n2字节 - - `bytes=n-`,传输web资源中第n个字节以后的所有内容 - - `bytes=n`,传输最后n个字节 +- Accept:用于告诉服务器,客户机支持的数据类型 + - Accept-Charset:用于告诉服务器,客户机采用的编码 + - Accept-Encoding:用于告诉服务器,客户机支持数据压缩格式 + - Accept-Language:客户机的语言环境 +- Host:客户机通过这个头告诉服务器,想访问的主机名 +- If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间 +- Refer:客户机通过这个头告诉服务器,它是从哪个资源访问服务器的(防盗链) +- User-Agent:客户机通过这个头告诉服务器,客户机的软件环境 +- Cookie:客户机通过这个头向服务器带数据 +- Connection:这个请求完了,是保持连接还是关闭 +- Range:断点下载 + - `bytes=n1-n2`,传输范围n1到n2字节 + - `bytes=n-`,传输web资源中第n个字节以后的所有内容 + - `bytes=n`,传输最后n个字节 ## 响应(Response) @@ -52,31 +48,28 @@ 详情可参考 -> [HTTP 状态消息](http://www.w3school.com.cn/tags/html_ref_httpmessages.asp) +> [HTTP 状态消息](http://www.w3school.com.cn/tags/html_ref_httpmessages.asp) ### 响应头字段 -- Location:这个头配合302状态码使用,用于告诉客户机找谁(location和302实现请求重定向) -- Server:服务器通过这个头,告诉浏览器服务器的类型 -- Content-Encoding:服务器通过这个头,数据的压缩格式 - (相关java知识:`GZIPOutputStream`,包装流/底层流) -- Content-Length:服务器通过这个头,告诉浏览器回送数据的长度 -- Content-Type:服务器通过这个头,告诉浏览器回送数据的类型 -- Last-Modified:服务器通过这个头,告诉浏览器当前资源的缓存时间 -- Refresh:服务器通过这个头,告诉浏览器隔多长时间刷新一次 -- Content-Disposition:服务器通过这个头,告诉浏览器以下载方式打开 -- Transfer-Encoding:服务器通过这个头,告诉浏览器数据的传送格式 -- Etag:缓存相关的头部,用于实时性要求高的系统 -- Expires:服务器通过这个头,告诉浏览器把回送的资源缓存多长时间,-1或0则不缓存 -- Cache-Control和Pragma:no-cache,服务器通过这两个头,也是控制浏览器不要缓存数据 -- Connection:断开连接/保持连接 -- Date:当前时间 -- Accept-Ranges:用来说明web服务器是否支持range。支持返回bytes;不支持返回none -- Content-Range:制定了返回web资源的字节范围,格式:`n1-n2/n_total` - - - ------ - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) - +- Location:这个头配合302状态码使用,用于告诉客户机找谁(location和302实现请求重定向) +- Server:服务器通过这个头,告诉浏览器服务器的类型 +- Content-Encoding:服务器通过这个头,数据的压缩格式 + (相关java知识:`GZIPOutputStream`,包装流/底层流) +- Content-Length:服务器通过这个头,告诉浏览器回送数据的长度 +- Content-Type:服务器通过这个头,告诉浏览器回送数据的类型 +- Last-Modified:服务器通过这个头,告诉浏览器当前资源的缓存时间 +- Refresh:服务器通过这个头,告诉浏览器隔多长时间刷新一次 +- Content-Disposition:服务器通过这个头,告诉浏览器以下载方式打开 +- Transfer-Encoding:服务器通过这个头,告诉浏览器数据的传送格式 +- Etag:缓存相关的头部,用于实时性要求高的系统 +- Expires:服务器通过这个头,告诉浏览器把回送的资源缓存多长时间,-1或0则不缓存 +- Cache-Control和Pragma:no-cache,服务器通过这两个头,也是控制浏览器不要缓存数据 +- Connection:断开连接/保持连接 +- Date:当前时间 +- Accept-Ranges:用来说明web服务器是否支持range。支持返回bytes;不支持返回none +- Content-Range:制定了返回web资源的字节范围,格式:`n1-n2/n_total` + +--- + +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(3)-Servlet.md" "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(3)-Servlet.md" index 06c051f..0821275 100644 --- "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(3)-Servlet.md" +++ "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(3)-Servlet.md" @@ -2,68 +2,63 @@ 标签: javaweb ----- +--- **Contents** -- [javaweb入门笔记(3)-Servlet](#javaweb入门笔记3-servlet) - - [servlet入门](#servlet入门) - - [手动编写第一个servlet](#手动编写第一个servlet) - - [servlet的调用过程和生命周期](#servlet的调用过程和生命周期) - - [servlet开发的一些细节](#servlet开发的一些细节) - - [ServletContext](#servletcontext) - - [参考链接](#参考链接) +- [javaweb入门笔记(3)-Servlet](#javaweb入门笔记3-servlet) + - [servlet入门](#servlet入门) + - [手动编写第一个servlet](#手动编写第一个servlet) + - [servlet的调用过程和生命周期](#servlet的调用过程和生命周期) + - [servlet开发的一些细节](#servlet开发的一些细节) + - [ServletContext](#servletcontext) + - [参考链接](#参考链接) - - ----- +--- ## servlet入门 开发步骤: -- 编写一个java类,实现servlet接口 -- 把开发好的java类部署到web服务器 +- 编写一个java类,实现servlet接口 +- 把开发好的java类部署到web服务器 API文档 -> [Servlet API Documentation](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html) - +> [Servlet API Documentation](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html) 生命周期相关方法(life-cycle methods) -Servlet的生命周期通过`java.servlet.Servlet`接口中的`init()`、`service()`、和`destroy()`方法表示。Servlet的生命周期有四个阶段:加载并实例化、初始化、请求处理、销毁。(见文末【参考链接】) - - - +Servlet的生命周期通过`java.servlet.Servlet`接口中的`init()`、`service()`、和`destroy()`方法表示。 +Servlet的生命周期有四个阶段:加载并实例化、初始化、请求处理、销毁。(见文末【参考链接】) +## 手动编写第一个servlet +1. 在tomcat中新建一个web应用`hello`,在web应用中新建一个`WEB-INF/classes`目录 +2. 在`classes`目录新建一个`FirstServlet` -## 手动编写第一个servlet -1.在tomcat中新建一个web应用`hello`,在web应用中新建一个`WEB-INF/classes`目录 + ```java + package org.iot; -2.在`classes`目录新建一个`FirstServlet` + import java.io.*; + import javax.servlet.*; -```java -package org.iot; + public class FirstServlet extends GenericServlet{ + public void service(ServletRequest req,ServletResponse res)throws ServletException,java.io.IOException{ + OutputStream out = res.getOutputStream(); + out.write("hello servlet!!!".getBytes()); + } + } + ``` -import java.io.*; -import javax.servlet.*; +3. 编译,`javac -cp %CATALINA_HOME%/lib/servlet-api.jar -d . FirstServlet.java`, -public class FirstServlet extends GenericServlet{ - public void service(ServletRequest req,ServletResponse res)throws ServletException,java.io.IOException{ - OutputStream out = res.getOutputStream(); - out.write("hello servlet!!!".getBytes()); - } -} -``` + 命令行手动编译参考[这里](http://www.iitshare.com/under-the-cmd-compile-the-java.html) -3.编译,`javac -cp %CATALINA_HOME%/lib/servlet-api.jar -d . FirstServlet.java`,命令行手动编译参考[这里](http://www.iitshare.com/under-the-cmd-compile-the-java.html) +4. 在`WEB-INF`目录中新建一个`web.xml`文件,配置servlet的对外访问路径 -4.在`WEB-INF`目录中新建一个`web.xml`文件,配置servlet的对外访问路径 - -5.启动tomcat访问 +5. 启动tomcat访问 ## servlet的调用过程和生命周期 @@ -71,25 +66,21 @@ public class FirstServlet extends GenericServlet{ ![servlet的调用过程和生命周期](http://7xph6d.com1.z0.glb.clouddn.com/javaweb_servlet-lifecycle.png) - ## servlet开发的一些细节 -- **标签**:``包含``和``;``包含``和`` -- **映射**:`web.xml`中一个``可对应多个`` -- **通配符**:``的``可以使用通配符,两种固定格式:`*.扩展名`;以`/`开头,以`/*`结尾 - +- **标签**:``包含``和``;``包含``和`` +- **映射**:`web.xml`中一个``可对应多个`` +- **通配符**:``的``可以使用通配符,两种固定格式:`*.扩展名`;以`/`开头,以`/*`结尾 ![javaweb_servlet-url匹配.png](http://7xph6d.com1.z0.glb.clouddn.com/javaweb_servlet-url%E5%8C%B9%E9%85%8D.png) -- **对象**:servlet由servlet引擎调用,不能独立运行。客户端多次请求,服务器只创建一个servlet实例,之后驻留内存中继续服务直至web容器退出才销毁它。 -- **请求**:服务器针对客户端的每一次请求都会创建新的`request`和`response`对象(它们的生命周期很短),传给`service`方法。 -- **加载**:servlet实例的创建和`init`方法的调用是在第一次请求时,而非服务器启动时,除非在``标签配置``,数字越小优先级越高 -- **缺省**:映射路径为正斜杠`/`,则为当前web应用的缺省servlet,不匹配的都交给缺省 -- **线程安全**:访问同一资源会引发线程安全问题; `SingleThreadModel`标记接口(已弃用) -- **ServletConfig**:在``标签配置``,通过`getServletConfig`方法获得配置。可配置输出字符集,读哪个配置文件等等。 -- **ServletContext**:代表当前web应用,含有一些web应用全局性方法,实现web资源共享、servlet转发等。通过`ServletConfig.getServletContext`方法获得,在``标签配置。 - - +- **对象**:servlet由servlet引擎调用,不能独立运行。客户端多次请求,服务器只创建一个servlet实例,之后驻留内存中继续服务直至web容器退出才销毁它。 +- **请求**:服务器针对客户端的每一次请求都会创建新的`request`和`response`对象(它们的生命周期很短),传给`service`方法。 +- **加载**:servlet实例的创建和`init`方法的调用是在第一次请求时,而非服务器启动时,除非在``标签配置``,数字越小优先级越高 +- **缺省**:映射路径为正斜杠`/`,则为当前web应用的缺省servlet,不匹配的都交给缺省 +- **线程安全**:访问同一资源会引发线程安全问题; `SingleThreadModel`标记接口(已弃用) +- **ServletConfig**:在``标签配置``,通过`getServletConfig`方法获得配置。可配置输出字符集,读哪个配置文件等等。 +- **ServletContext**:代表当前web应用,含有一些web应用全局性方法,实现web资源共享、servlet转发等。通过`ServletConfig.getServletContext`方法获得,在``标签配置。 ## ServletContext @@ -109,41 +100,35 @@ ServletContext域: 作用 -- 获取web应用的初始化参数 -- 实现servlet转发 -- 利用ServletContext对象读取资源文件 - - 获得文件路径 - - 读取资源文件的三种方式 - - .properties文件(属性文件) - +- 获取web应用的初始化参数 +- 实现servlet转发 +- 利用ServletContext对象读取资源文件 + - 获得文件路径 + - 读取资源文件的三种方式 + - .properties文件(属性文件) 配置文件:properties文件和xml文件;数据有关系使用xml文件,没有关系则使用properties文件。 -1.通过`ServletContext`的`getResourceAsStream`方法,读取properties文件 +1. 通过`ServletContext`的`getResourceAsStream`方法,读取properties文件 -模板代码(注意文件位置不同写路径会不同): + 模板代码(注意文件位置不同写路径会不同): -```java -InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/org/iot/servlet/db.properties"); -Properties properties = new Properties();//map -properties.load(in); -``` + ```java + InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/org/iot/servlet/db.properties"); + Properties properties = new Properties();//map + properties.load(in); + ``` -2.通过`servletContext`的`getRealPath`方法得到资源的绝对路径,再通过传统方式(`FileInputStream`)读取 +2. 通过`servletContext`的`getRealPath`方法得到资源的绝对路径,再通过传统方式(`FileInputStream`)读取 -3.通过类装载器去读,`ClassLoader`的`getResourceAsStream`(如果读取资源文件的程序不是servlet),文件不能太大。**只装载一次**,所以如要读到更新后的数据,通过类装载的方式得到资源文件的位置,再通过传统方式读取资源文件的数据(用`getResource`得到path,再用`FileInputStream`) +3. 通过类装载器去读,`ClassLoader`的`getResourceAsStream`(如果读取资源文件的程序不是servlet),文件不能太大。 + **只装载一次**,所以如要读到更新后的数据,通过类装载的方式得到资源文件的位置,再通过传统方式读取资源文件的数据(用`getResource`得到path,再用`FileInputStream`) ## 参考链接 -> [servlet和Jsp生命周期解读](http://blog.csdn.net/evankaka/article/details/46673051) - - - - - - ------ +> [servlet和Jsp生命周期解读](http://blog.csdn.net/evankaka/article/details/46673051) -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +--- +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(4)-request\345\222\214response.md" "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(4)-request\345\222\214response.md" index 1f5ce8b..5442315 100644 --- "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(4)-request\345\222\214response.md" +++ "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(4)-request\345\222\214response.md" @@ -6,28 +6,25 @@ **Contents** -- [javaweb入门笔记(4)-request和response](#javaweb入门笔记4-request和response) - - [response](#response) - - [输出数据](#输出数据) - - [文件下载](#文件下载) - - [随机图片](#随机图片) - - [刷新和缓存](#刷新和缓存) - - [请求重定向](#请求重定向) - - [request](#request) - - [中文乱码](#中文乱码) - - [请求转发](#请求转发) - - [地址的写法](#地址的写法) - - [防盗链](#防盗链) - - - ----- +- [javaweb入门笔记(4)-request和response](#javaweb入门笔记4-request和response) + - [response](#response) + - [输出数据](#输出数据) + - [文件下载](#文件下载) + - [随机图片](#随机图片) + - [刷新和缓存](#刷新和缓存) + - [请求重定向](#请求重定向) + - [request](#request) + - [中文乱码](#中文乱码) + - [请求转发](#请求转发) + - [地址的写法](#地址的写法) + - [防盗链](#防盗链) + +--- API: ->* [Interface HttpServletResponse](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html?javax/servlet/http/HttpServletResponse.html) ->* [Interface HttpServletRequest](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html?javax/servlet/http/HttpServletRequest.html) - +> * [Interface HttpServletResponse](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html?javax/servlet/http/HttpServletResponse.html) +> * [Interface HttpServletRequest](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html?javax/servlet/http/HttpServletRequest.html) ## response @@ -35,14 +32,14 @@ API: 程序以什么码表输出,就一定要控制浏览器以什么码表打开。可有如下两种写法: -- `response.setHeader("Content-type","text/html;charset=UTF-8")` -- `response.setContentType("text/html;charset=UTF-8")`(默认调用`setHeader`和`setCharacterEncoding`) +- `response.setHeader("Content-type","text/html;charset=UTF-8")` +- `response.setContentType("text/html;charset=UTF-8")`(默认调用`setHeader`和`setCharacterEncoding`) 把分号`;`错写成逗号`,`,浏览器会提示下载 用html技术的``标签可以模拟一个http响应头,` ` -response可用`setCharacterEncoding`方法设置码表。字符流输出:`PrintWritet->response->浏览器`,`response->浏览器`默认使用`iso-8859`编码 +response可用`setCharacterEncoding`方法设置码表。字符流输出:`PrintWriter->response->浏览器`,`response->浏览器`默认使用`iso-8859`编码 ### 文件下载 @@ -50,7 +47,6 @@ response可用`setCharacterEncoding`方法设置码表。字符流输出:`Prin 如果下载文件是中文名为中文,则文件名需要经过url编码`URLEncoder.encode` - ### 随机图片 使用[`BufferedImage`](https://docs.oracle.com/javase/8/docs/api/index.html?java/awt/image/BufferedImage.html)在内存生成图片,再使用[`ImageIO`](https://docs.oracle.com/javase/8/docs/api/index.html?javax/imageio/ImageIO.html)输出。 @@ -61,8 +57,8 @@ response可用`setCharacterEncoding`方法设置码表。字符流输出:`Prin ### 刷新和缓存 -- 刷新:一般不在servlet里加`refresh`头,而是在jsp加入``头模拟。 -- 缓存:加入`expires`头,当前时间+要缓存的时长 +- 刷新:一般不在servlet里加`refresh`头,而是在jsp加入``头模拟。 +- 缓存:加入`expires`头,当前时间+要缓存的时长 ### 请求重定向 @@ -72,61 +68,60 @@ response可用`setCharacterEncoding`方法设置码表。字符流输出:`Prin 一些细节: -- `getOutputStream`和`getWriter`方法跟别用于输出二进制数据、输出文本数据的`ServletOutputStream`、`Printwriter`对象,这两个方法相互排斥,只能调用其中一个,否则抛`IllegalStateException`异常。 -- response的输出流会自己关闭。`Servlet`的`service`方法结束后,Servlet引擎会检查并调用`close`方法关闭该输出流对象。 - +- `getOutputStream`和`getWriter`方法跟别用于输出二进制数据、输出文本数据的`ServletOutputStream`、`Printwriter`对象,这两个方法相互排斥,只能调用其中一个,否则抛`IllegalStateException`异常。 +- response的输出流会自己关闭。`Servlet`的`service`方法结束后,Servlet引擎会检查并调用`close`方法关闭该输出流对象。 ## request -- URI:标识某个资源 -- URL:标识互联网上某个资源 +- URI:标识某个资源 +- URL:标识互联网上某个资源 一些方法 -- `getRequestURI`用于权限拦截,访问统计 -- `getRemoteAddr`用于得到客户机IP地址 -- `getMethod`得到客户机请求方式 +- `getRequestURI`用于权限拦截,访问统计 +- `getRemoteAddr`用于得到客户机IP地址 +- `getMethod`得到客户机请求方式 requst对象获取数据的四种方式 -- `getParameter` -- `getParameterNames` -- `getParameterValues` -- `getParameterMap`(可结合JavaBean使用) +- `getParameter` +- `getParameterNames` +- `getParameterValues` +- `getParameterMap`(可结合JavaBean使用) (`getInputStream`用于文件上传) - ### 中文乱码 + url后面如果有中文数据,需要编码后再提交 表单提交的数据使用的码表和该页面的码表一致,而`getParameter`方法默认使用`ISO-8859`码表。 解决: -- 对于post提交的数据,在获取数据前要使用`request`对象的`setCharacterEncoding`设置码表。 -- 对于get提交的数据,只能手工解决。先对数据调用`getBytes("ISO-8859-1")`获取二进制字节,再用特定码表构建字符串。 -- 超链提交的中文,解决办法同get提交的数据。 +- 对于post提交的数据,在获取数据前要使用`request`对象的`setCharacterEncoding`设置码表。 +- 对于get提交的数据,只能手工解决。先对数据调用`getBytes("ISO-8859-1")`获取二进制字节,再用特定码表构建字符串。 +- 超链提交的中文,解决办法同get提交的数据。 *也可以通过改服务器配置来解决乱码问题,但一般**不建议**使用。* -- `URIEncoding`:改tomcat的配置文件`conf/server.xml`的连接器``中的`URIEncoding`属性 -- `useBodyEncodingForURI`:将`conf/server.xml`的连接器``中的`useBodyEncodingForURI`置为`true` +- `URIEncoding`:改tomcat的配置文件`conf/server.xml`的连接器``中的`URIEncoding`属性 +- `useBodyEncodingForURI`:将`conf/server.xml`的连接器``中的`useBodyEncodingForURI`置为`true` ### 请求转发 应用场景:MVC设计模式 -- model : javabean; -- view : jsp; -- controller : servlet +- model : javabean; +- view : jsp; +- controller : servlet 使用request域对象把数据带给转发资源。调用`request`对象的`getRequestDispatcher`方法,再调用`forward`方法。一次请求,浏览器地址栏不变。 `forward`一些细节 -- 不能在关闭输出流后再调用转发,也不能调用两次,否则会抛出异常。 -- 跳转之前会清空response中的数据。即数据只是写入到缓冲区而没真正输出到客户端,则可调用`forward`方法,原来写入到缓冲区的内容被清空,但响应头字段信息保持。 +- 不能在关闭输出流后再调用转发,也不能调用两次,否则会抛出异常。 +- 跳转之前会清空response中的数据。即数据只是写入到缓冲区而没真正输出到客户端,则可调用`forward`方法,原来写入到缓冲区的内容被清空,但响应头字段信息保持。 `include`方法可以用于包含一些公共页面(一般不在servlet中包含) @@ -145,12 +140,12 @@ mail---------------------------Web应用所在目录 |---------web.xml ``` -1. `request.getRequestDispatcher("/form1.html")` -2. `response.sendRedirect("mail/form1.html")` -3. `this.getServletContext().getRealPath("/form1.html")` -4. `this.getServletContext().getResourceAsStream("/form1.html")` -5. `` -6. `
` +1. `request.getRequestDispatcher("/form1.html")` +2. `response.sendRedirect("mail/form1.html")` +3. `this.getServletContext().getRealPath("/form1.html")` +4. `this.getServletContext().getResourceAsStream("/form1.html")` +5. `` +6. `` 其中,1,3,4是给服务器用;2,5,6是浏览器用 @@ -158,7 +153,6 @@ mail---------------------------Web应用所在目录 读取`referer`请求头,不合要求则重定向。 ------ - -> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) +--- +> 作者[@brianway](http://brianway.github.io/)更多文章:[个人网站](http://brianway.github.io/) | [CSDN](http://blog.csdn.net/h3243212/) | [oschina](http://my.oschina.net/brianway) \ No newline at end of file diff --git "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(6)-JSP\346\212\200\346\234\257.md" "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(6)-JSP\346\212\200\346\234\257.md" index 13ffe13..b847c42 100644 --- "a/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(6)-JSP\346\212\200\346\234\257.md" +++ "b/blogs/javaweb/javaweb\345\205\245\351\227\250\347\254\224\350\256\260(6)-JSP\346\212\200\346\234\257.md" @@ -15,9 +15,7 @@ - [jsp映射和查错](#jsp映射和查错) - [jsp与JavaBean](#jsp与javabean) - - ----- +--- JSP:Java Server Pages,一种动态web资源的开发技术 diff --git a/java-base/src/main/java/com/brianway/learning/java/base/constructor/FatherClass.java b/java-base/src/main/java/com/brianway/learning/java/base/constructor/FatherClass.java index 4ccca61..23395b3 100644 --- a/java-base/src/main/java/com/brianway/learning/java/base/constructor/FatherClass.java +++ b/java-base/src/main/java/com/brianway/learning/java/base/constructor/FatherClass.java @@ -1,5 +1,7 @@ package com.brianway.learning.java.base.constructor; +import java.util.ArrayList; + /** * Created by Brian on 2016/4/14. */ diff --git a/java-base/src/main/java/com/brianway/learning/java/base/generics/Demo.java b/java-base/src/main/java/com/brianway/learning/java/base/generics/Demo.java new file mode 100644 index 0000000..e76d260 --- /dev/null +++ b/java-base/src/main/java/com/brianway/learning/java/base/generics/Demo.java @@ -0,0 +1,60 @@ +package com.brianway.learning.java.base.generics; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +public class Demo { + //准备一个哈希表,为每个线程准备数据 + private static Map threadData = new HashMap<>(); + private static Set threads = new HashSet<>(); + public static void main(String[] args) { + for(int i=0;i<200;i++){ + new Thread( + new Runnable() { + @Override + public void run() { + Thread thread = Thread.currentThread(); + int data = new Random().nextInt(); + threadData.put(thread,data); +// System.out.println(thread+" put data:"+data); + new A().get(); + new B().get(); + } + }).start(); + } + } + static class A{ + public void get(){ + Thread thread = null; + try { + int data = threadData.get(thread = Thread.currentThread()); +// System.out.println("A from "+Thread.currentThread()+" get data "+data); + } catch (Exception e) { + if (!threads.contains(thread)) { + System.err.println("the thread is: " + thread); + } else { + System.err.println("ooooooooooooooooooops"); + } + } + } + } + + static class B{ + public void get(){ + Thread thread = null; + try { + int data = threadData.get(thread = Thread.currentThread()); +// System.out.println("B from "+Thread.currentThread()+" get data "+data); + } catch (Exception e) { + if (!threads.contains(thread)) { + System.err.println("the thread is: " + thread); + } else { + System.err.println("ooooooooooooooooooops"); + } + } + } + } +} diff --git a/java-base/src/main/java/com/brianway/learning/java/base/generics/GenericDao.java b/java-base/src/main/java/com/brianway/learning/java/base/generics/GenericDao.java new file mode 100644 index 0000000..3e23325 --- /dev/null +++ b/java-base/src/main/java/com/brianway/learning/java/base/generics/GenericDao.java @@ -0,0 +1,84 @@ +package com.brianway.learning.java.base.generics; + +import jdk.internal.org.objectweb.asm.commons.AdviceAdapter; +import jdk.nashorn.internal.objects.annotations.Constructor; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Map; +import java.util.Set; + +public class GenericDao{ + public void add(T x){ + } + + public T findById(int id){ + return null; + } + + public void delete(T obj){ + } + + public void delete(int id){ + } + + public void update(T obj){ + } + + public T findByUserName(String name){ + return null; + } + + public static Set findByConditions(String where){ + return null; + } + + public static Set findByConditions(T2 where){ + return null; + } + + public static void main(String[] args) { + GenericDao dao = new GenericDao(); + Set cond = GenericDao.findByConditions(0.3); + + if(new int[5] instanceof Object) { + System.out.println("true"); + } else { + System.out.println("false"); + } + + + } + + public static class GenericTest { + + /*利用反射获取方法参数的实际参数类型*/ + public static void getParamType() throws NoSuchMethodException{ + Method method = GenericTest.class.getMethod("applyMap", Map.class); + //获取方法的泛型参数的类型 + Type[] types = method.getGenericParameterTypes(); + System.out.println(types[0]); + //参数化的类型 + ParameterizedType pType = (ParameterizedType)types[0]; + //原始类型 + System.out.println(pType.getRawType()); + //实际类型参数 + System.out.println(pType.getActualTypeArguments()[0]); + System.out.println(pType.getActualTypeArguments()[1]); + Class clazz = GenericTest.class; + clazz.getDeclaredMethods(); + clazz.getMethods(); + + java.lang.reflect.Constructor[] constructors = clazz.getConstructors(); + } + + /*供测试参数类型的方法*/ + public static void applyMap(Map map){ + + } + + } + +}