反射

类加载器

类加载

当程序要使用某个类时,如果该类还没有加载到内存中,则系统会通过类的加载、类的连接、类的初始化这三个步骤来对类进行初始化。如果不出现意外情况,JVM将连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或类初始化。

类的加载器的作用
  • 就是指将class文件读入内存,并为之创建一个java.lang.Class对象
  • 任何类被使用时,系统都会为之建立一个java.lang.Class对象

JVM的类加载机制
  • 全盘负责:
  • 父类委托:
  • 缓存机制:

类的连接
  • 验证阶段:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
  • 准备阶段:负责为类的类变量分配内存,并设置默认初始化值
  • 解析阶段:将的类的二进制数据中的符号引用替换为直接引用

类的初始化
  • 在该阶段,主要就是对类变量进行初始化

类初始化的步骤

  • 假如类还未被加载和连接,则程序先加载并连接该类
  • 假如该类的直接父类还未被初始化,则先初始化其直接父类
  • 假如该类有初始化语句,则系统依次执行这些初始化语句

需要注意的是:在执行第二个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3

类的初始化时机/什么时候会触发类初始化

  • 创建类的实例
  • 调用类的类方法
  • 访问类或者接口的类变量,或者为该类变量赋值
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

反射类

反射类的构造方法

反射类的字段

反射类的方法

JSON

JSON是一种数据格式,本质上是一个字符串。JSON是JavaScript对象的字符串表现形式,在JS中对象是用{}表示,数组使用[]表示。

  1. let student = {
  2. age: 18,
  3. name: 'zs'
  4. }
  5. let fruits = ['apple', 'tomato', 'banana']

使用JSON-lib解析JSON

JSON 转对象
  1. String json = "{age:18,name:'zs'}";
  2. JSONObject jsonObject = new JSONObject(json);
  3. int age = jsonObject.getInt("age");
  4. String name = jsonObject.getString("zs");
  5. Student student = new Student(age, name);
  6. System.out.println(student);

JSON转复杂对象
  1. public static void main(String[] args) throws JSONException {
  2. String json = "{age:19,name:'ls',score:{java:10,php:20,database:40,c:58}}";
  3. JSONObject jsonObject = new JSONObject(json);
  4. int age = jsonObject.getInt("age");
  5. String name = jsonObject.getString("name");
  6. JSONObject score1 = jsonObject.getJSONObject("score");
  7. int java = score1.getInt("java");
  8. int php = score1.getInt("php");
  9. int database = score1.getInt("database");
  10. int c = score1.getInt("c");
  11. Score score = new Score(java, php, database, c);
  12. Student student = new Student(age, name, score);
  13. System.out.println(student);
  14. }

JSON转数组
  1. public static void main(String[] args) throws JSONException {
  2. String json = "[{java:2,php:3,database:5,c:22},{java:3,php:5,database:6,c:26}]";
  3. JSONArray jsonArray = new JSONArray(json);
  4. List<Score> scoreList = new ArrayList<>();
  5. for (int i = 0; i < jsonArray.length(); i++) {
  6. JSONObject jsonObject = jsonArray.getJSONObject(i);
  7. int java = jsonObject.getInt("java");
  8. int php = jsonObject.getInt("php");
  9. int database = jsonObject.getInt("database");
  10. int c = jsonObject.getInt("c");
  11. scoreList.add(new Score(java, php, database, c));
  12. }
  13. System.out.println(scoreList);
  14. }

JSON转复杂数组对象
  1. public static void main(String[] args) throws JSONException {
  2. String json = "[{age:2,name:'zs',score:{java:2,php:3,database:5,c:22}},{age:19,name:'ls',score:{java:3,php:5,database:6,c:26}}]";
  3. List<Student> studentList = new ArrayList<>();
  4. JSONArray jsonArray = new JSONArray(json);
  5. for (int i = 0; i < jsonArray.length(); i++) {
  6. JSONObject jsonObject = jsonArray.getJSONObject(i);
  7. int age = jsonObject.getInt("age");
  8. String name = jsonObject.getString("name");
  9. JSONObject scoreJsonObject = jsonObject.getJSONObject("score");
  10. int java = scoreJsonObject.getInt("java");
  11. int php = scoreJsonObject.getInt("php");
  12. int database = scoreJsonObject.getInt("database");
  13. int c = scoreJsonObject.getInt("c");
  14. studentList.add(new Student(age, name, new Score(java, php, database, c)));
  15. }
  16. System.out.println(studentList);
  17. }

对象转JSON
  1. public static void main(String[] args) {
  2. Student student = new Student(19, "zs");
  3. JSONObject jsonObject = new JSONObject(student);
  4. System.out.println(jsonObject.toString());
  5. }

数组转JSON
  1. public static void main(String[] args) {
  2. List<Student> studentList = new ArrayList<>();
  3. studentList.add(new Student(19, "za", new Score(1, 2, 3, 45)));
  4. studentList.add(new Student(12, "zc", new Score(12, 32, 23, 15)));
  5. studentList.add(new Student(13, "zg", new Score(13, 22, 23, 25)));
  6. studentList.add(new Student(15, "zc", new Score(15, 25, 23, 35)));
  7. JSONArray jsonArray = new JSONArray(studentList);
  8. System.out.println(jsonArray.toString());
  9. }

使用fastjson

  1. public static void main(String[] args) {
  2. // 1. json -> 对象
  3. String json = "{age:18,name:'zs'}";
  4. Student student = JSON.parseObject(json, Student.class);
  5. System.out.println(student);
  6. // 2. json -> 对象
  7. String json1 = "{age:19,name:'ls',score:{java:10,php:20,database:40,c:58}}";
  8. Student student1 = JSON.parseObject(json1, Student.class);
  9. System.out.println(student1);
  10. // 3. json -> 对象数组
  11. String json2 = "[{java:2,php:3,database:5,c:22},{java:3,php:5,database:6,c:26}]";
  12. List student2 = JSON.parseArray(json2, Student.class);
  13. for (int i = 0; i < student2.size(); i++) {
  14. Object o = student2.get(i);
  15. System.out.println(o);
  16. }
  17. // 4. json -> 泛型对象数组
  18. String json3 = "[{age:2,name:'zs',score:{java:2,php:3,database:5,c:22}},{age:19,name:'ls',score:{java:3,php:5,database:6,c:26}}]";
  19. // Type typeToken = new TypeToken<ArrayList<Student>>(){}.getType();
  20. List<Student> studentList = JSON.parseArray(json3, Student.class);
  21. for (int i = 0; i < studentList.size(); i++) {
  22. System.out.println(studentList.get(i));
  23. }
  24. // 5. 普通对象 -> json
  25. Student o = new Student(19, "zs");
  26. System.out.println(JSON.toJSONString(o));
  27. // 6. 数组对象 -> json
  28. List<Student> s1 = new ArrayList<>();
  29. s1.add(new Student(19, "za", new Score(1, 2, 3, 45)));
  30. s1.add(new Student(12, "zc", new Score(12, 32, 23, 15)));
  31. s1.add(new Student(13, "zg", new Score(13, 22, 23, 25)));
  32. s1.add(new Student(15, "zc", new Score(15, 25, 23, 35)));
  33. System.out.println(JSON.toJSONString(s1));
  34. }

使用gson

  1. public static void main(String[] args) {
  2. // 1. json -> 对象
  3. String json = "{age:18,name:'zs'}";
  4. Gson gson = new Gson();
  5. Student student = gson.fromJson(json, Student.class);
  6. System.out.println(student);
  7. // 2. json -> 对象
  8. String json1 = "{age:19,name:'ls',score:{java:10,php:20,database:40,c:58}}";
  9. Student student1 = gson.fromJson(json1, Student.class);
  10. System.out.println(student1);
  11. // 3. json -> 对象数组
  12. String json2 = "[{java:2,php:3,database:5,c:22},{java:3,php:5,database:6,c:26}]";
  13. List student2 = gson.fromJson(json2, ArrayList.class);
  14. for (int i = 0; i < student2.size(); i++) {
  15. Object o = student2.get(i);
  16. System.out.println(o);
  17. }
  18. // 4. json -> 泛型对象数组
  19. String json3 = "[{age:2,name:'zs',score:{java:2,php:3,database:5,c:22}},{age:19,name:'ls',score:{java:3,php:5,database:6,c:26}}]";
  20. Type typeToken = new TypeToken<ArrayList<Student>>(){}.getType();
  21. List<Student> studentList = gson.fromJson(json3, typeToken);
  22. for (int i = 0; i < studentList.size(); i++) {
  23. System.out.println(studentList.get(i));
  24. }
  25. // 5. 普通对象 -> json
  26. Student o = new Student(19, "zs");
  27. System.out.println(gson.toJson(o));
  28. // 6. 数组对象 -> json
  29. List<Student> s1 = new ArrayList<>();
  30. s1.add(new Student(19, "za", new Score(1, 2, 3, 45)));
  31. s1.add(new Student(12, "zc", new Score(12, 32, 23, 15)));
  32. s1.add(new Student(13, "zg", new Score(13, 22, 23, 25)));
  33. s1.add(new Student(15, "zc", new Score(15, 25, 23, 35)));
  34. System.out.println(gson.toJson(s1));
  35. }

实现一个简单的JSON解析工具

  1. package com.shaw.json;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.Objects;
  5. public class RabbitJSON {
  6. /* key-value 映射 key:属性 value:值 */
  7. private Map<String, String> map;
  8. /* 调式 */
  9. public Map<String, String> getMap() {
  10. return map;
  11. }
  12. public RabbitJSON() {
  13. this.map = new HashMap<>();
  14. }
  15. /**
  16. *
  17. * @param JSONString JSON字符串
  18. */
  19. public RabbitJSON(String JSONString) {
  20. this(new JSONCharParser(JSONString));
  21. }
  22. /**
  23. *
  24. * @param jsonCharParser JSON字符解析器 com.shaw.json.JSONCharParser
  25. */
  26. public RabbitJSON(JSONCharParser jsonCharParser) {
  27. this();
  28. // JSON对象字符串不是以'{'开头
  29. if (jsonCharParser.next() != '{') {
  30. throw new JSONSyntaxException("JSON对象字符串不是以 { 开头");
  31. }
  32. while (true) {
  33. char c = jsonCharParser.nextClean();
  34. // a
  35. // System.out.println(c);
  36. switch (c) {
  37. case '\u0000': // \u0000 Unicode 空白字符
  38. throw new JSONSyntaxException("JSON对象格式不正确,包含空格");
  39. case '}': // }:JSON语法结束标记
  40. return;
  41. default:
  42. // 回退
  43. jsonCharParser.back();
  44. // 读取对象的key
  45. String key = jsonCharParser.nextValue().toString();
  46. System.out.println("key = " + key);
  47. // :
  48. c = jsonCharParser.nextClean();
  49. System.out.println("c = " + c);
  50. if (c != ':') {
  51. throw new JSONSyntaxException("JSON 语法错误,在附近" + key + c);
  52. }
  53. // 读取对象的value
  54. this.map.put(key, jsonCharParser.nextValue().toString());
  55. switch (jsonCharParser.nextClean()) {
  56. case ',':
  57. case ';':
  58. if (jsonCharParser.nextClean() == '}') {
  59. return;
  60. }
  61. jsonCharParser.back();
  62. break;
  63. case '}':
  64. return;
  65. default:
  66. throw new JSONSyntaxException("JSON语法错误");
  67. }
  68. }
  69. }
  70. }
  71. /**
  72. * JSON语法错误异常
  73. * @author Shaw
  74. */
  75. private static class JSONSyntaxException extends IllegalArgumentException {
  76. public JSONSyntaxException() {
  77. super();
  78. }
  79. public JSONSyntaxException(String s) {
  80. super(s);
  81. }
  82. public JSONSyntaxException(String message, Throwable cause) {
  83. super(message, cause);
  84. }
  85. public JSONSyntaxException(Throwable cause) {
  86. super(cause);
  87. }
  88. }
  89. public Object get(String key) {
  90. Object value = this.map.get(key);
  91. return Objects.requireNonNull(value, "value 为 null");
  92. }
  93. public boolean getBoolean(String key) {
  94. Object value = this.get(key);
  95. if (value.equals(Boolean.TRUE) || ((value instanceof String) && ((String) value).equalsIgnoreCase("true"))) {
  96. return true;
  97. } else if (value.equals(Boolean.FALSE) || ((value instanceof String) && ((String) value).equalsIgnoreCase(
  98. "false"))) {
  99. return false;
  100. } else {
  101. throw new JSONSyntaxException("值解析失败" + value);
  102. }
  103. // 不等于 Boolean.FALSE 并且也不是 String类型 或者 强转成String类型忽略大小写匹配不等于false
  104. // if (!value.equals(Boolean.FALSE) && (!(value instanceof String) || !((String) value).equalsIgnoreCase("false"))) {
  105. // if (!value.equals(Boolean.TRUE) && (!(value instanceof String) || !((String) value).equalsIgnoreCase("true"))) {
  106. // throw new JSONSyntaxException("值解析失败:" + value);
  107. // } else {
  108. // return false;
  109. // }
  110. // } else {
  111. // return false;
  112. // }
  113. }
  114. public double getDouble(String key) throws ClassCastException {
  115. Object value = this.get(key);
  116. return value instanceof Number ? ((Number) value).doubleValue() : Double.parseDouble((String) value);
  117. }
  118. public int getInt(String key) {
  119. Object value = this.get(key);
  120. return value instanceof Number ? ((Number) value).intValue() : Integer.parseInt((String) value);
  121. }
  122. public String getString(String key){
  123. return this.get(key).toString();
  124. }
  125. }
  1. package com.shaw.json;
  2. import java.io.IOException;
  3. import java.io.Reader;
  4. import java.io.StringReader;
  5. public class JSONCharParser {
  6. /* 字符读取器 */
  7. private Reader reader;
  8. /* 是否到达结尾 */
  9. private boolean eof;
  10. /* 字符数量 */
  11. private int charCount;
  12. /* 行数 */
  13. private int lineCount;
  14. /* 索引 */
  15. private int index;
  16. /* 上一个字符 */
  17. private char previous;
  18. /* 是否有上一个字符 */
  19. private boolean hasPrevious;
  20. public JSONCharParser(String JSONString) {
  21. this(new StringReader(JSONString));
  22. this.eof = false;
  23. this.charCount = 0;
  24. this.lineCount = 0;
  25. this.index = 0;
  26. this.previous = 0;
  27. this.hasPrevious = false;
  28. }
  29. public JSONCharParser(Reader reader) {
  30. this.reader = reader;
  31. }
  32. /**
  33. * 获取JSON字符串中的下一个字符
  34. *
  35. * @return 下一个字符 如果没有将返回 ASCII 对应的0 也就是空白字符
  36. */
  37. public char next() {
  38. int c = -1;
  39. if (this.hasPrevious) {
  40. this.hasPrevious = false;
  41. c = this.previous;
  42. } else {
  43. try {
  44. // 读取下一个字符
  45. c = this.reader.read();
  46. } catch (IOException e) {
  47. e.printStackTrace();
  48. }
  49. // 到达文件结尾
  50. if (c < 0) {
  51. this.eof = true;
  52. c = 0;
  53. }
  54. }
  55. // 记录索引+1
  56. this.index++;
  57. // 换行符
  58. /*
  59. * ASCII:
  60. * 0 空字符
  61. * 1 标题开始
  62. * 10 换行键
  63. * */
  64. if (c == '\r') {
  65. // 记录行数+1
  66. this.lineCount++;
  67. this.charCount = c == 10 ? 0 : 1;
  68. } else if (c == 10) {
  69. this.lineCount++;
  70. this.charCount = 0;
  71. } else {
  72. this.charCount++;
  73. }
  74. this.previous = (char) c;
  75. return this.previous;
  76. }
  77. /**
  78. * 获取非空白字符的下一个字符 不包括
  79. * 1. 空白字符
  80. * 2. 换行字符
  81. *
  82. * @return 字符
  83. */
  84. public char nextClean() {
  85. char c;
  86. do {
  87. c = this.next();
  88. } while (c != 0 && c <= ' ');
  89. return c;
  90. }
  91. /**
  92. * 回退
  93. */
  94. public void back() {
  95. // if (this.hasPrevious && this.index > 0) {
  96. if (this.index > 0) {
  97. this.charCount--;
  98. this.index--;
  99. this.hasPrevious = true;
  100. this.eof = true;
  101. } else {
  102. throw new JSONException();
  103. }
  104. }
  105. private static class JSONException extends IllegalArgumentException {
  106. public JSONException() {
  107. super();
  108. }
  109. public JSONException(String s) {
  110. super(s);
  111. }
  112. public JSONException(String message, Throwable cause) {
  113. super(message, cause);
  114. }
  115. public JSONException(Throwable cause) {
  116. super(cause);
  117. }
  118. }
  119. /**
  120. * 返回JSON字符串的key或者value
  121. *
  122. * @return 字符串的value 或者 对象的value
  123. */
  124. public Object nextValue() {
  125. int c = this.nextClean();
  126. switch (c) {
  127. // key 已 " 或 '包含,例 'age'
  128. case '"':
  129. case '\'':
  130. // \'
  131. return this.nextString((char) c);
  132. // 对象
  133. case '{':
  134. this.back();
  135. // return new Object();
  136. break;
  137. // 其他情况 比如 {age:10} 不已 ' 或 " 包含
  138. default:
  139. StringBuilder sb = new StringBuilder();
  140. // :}]" 表示结束
  141. // ,;=# 表示非法字符
  142. // System.out.println("(char)c = " + (char) c);
  143. for (; c >= ' ' && ",:]}\\\";=#".indexOf(c) < 0; c = this.next()) {
  144. sb.append((char) c);
  145. }
  146. // System.out.println("sb.toString() = " + sb.toString());
  147. this.back();
  148. String s = sb.toString().trim();
  149. // System.out.println("s = " + s);
  150. if ("".equals(s)) {
  151. throw new JSONException("JSON语法错误");
  152. } else {
  153. // stringToValue
  154. return s;
  155. }
  156. // break;
  157. }
  158. return null;
  159. }
  160. /**
  161. * @param quote \'
  162. * @return key
  163. */
  164. public String nextString(char quote) {
  165. StringBuilder sb = new StringBuilder();
  166. while (true) {
  167. // a
  168. char c = this.next();
  169. switch (c) {
  170. // 包含 空格、换行
  171. // Windows : \r\n
  172. // Linux: \r
  173. // Mac: \n
  174. case '\u0000':
  175. case '\r':
  176. case '\n':
  177. throw new JSONException("json格式错误");
  178. // 匹配转义字符
  179. // \r
  180. // \t
  181. // \\
  182. case '\\':
  183. c = this.next();
  184. switch (c) {
  185. // 转义符
  186. case '\'':
  187. case '"':
  188. case '\\':
  189. case '/':
  190. sb.append(c);
  191. continue;
  192. // 匹配回车 换行 制表符....
  193. // \b \f \n \r \t
  194. case 'b':
  195. sb.append('\b');
  196. continue;
  197. case 'f':
  198. sb.append('\f');
  199. continue;
  200. case 'n':
  201. sb.append('\n');
  202. continue;
  203. case 'r':
  204. sb.append('\r');
  205. continue;
  206. case 't':
  207. sb.append('\t');
  208. continue;
  209. default:
  210. throw new JSONException("非法转义字符 \\" + c);
  211. }
  212. default:
  213. if (c == quote) {
  214. return sb.toString();
  215. }
  216. sb.append(c);
  217. }
  218. }
  219. }
  220. }

注解

注释,解释是代码级别的说明,增强代码的作用性,对于反射,只能反射RUNNTIME注解。

原注解

作用在注解上的注解

@Target

指示注解类型适用的上下文。注解类型可能适用的声明上下文和类型上下文。

EelementType

这个枚举常量提供了Java程序中可能出现注解语法位置的简单分类,用于Target元注解,以指定写入给定类型注释的合法位置。

  • ANNOTATION_TYPE:注解类型声明
  • CONSTRUCTOR:构造函数声明
  • FIELD:字段声明包括枚举常数
  • METHOD:方法声明
  • MODULE:模块声明
  • PACKAGE:包装声明
  • PARAMETER:参数声明
  • TYPE:类、接口(包括注解类型)或枚举声明
  • TYPE_PARAMETER:键入参数声明
  • TYPE_USE:使用类型

@Retention

指示要注释具有注解类型的注解保留时间。如果注解类型声明中没有保留注解,则保留策略默认为RetentionPolicy.CLASS。保留原注注解仅在原注解类型直接用于注解时才起作用。如果原注解类型用作另一注解类型的成员类型,则它不起作用。

Retention Policy

  • CLASS:注解将由编译器记录在类文件中,但VM不需要在运行时保留。
  • SOURCE:注解将由编译器丢弃。
  • RUNTIME:注解将被编译器记录在类文件中,并由VM在运行时保留,因此可以反射获取。