反射机制
反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件。
优点类似于黑客。(可以读和修改字节码文件。)
通过反射机制可以操作代码片段。(class文件。)
反射机制的相关类在哪个包下?
java.lang.reflect.*;
反射机制相关的重要的类有哪些?
java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
ava.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法
java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class User{ int no;
public User(){ } public User(int no){ this.no = no; }
public void setNo(int no){ this.no = no; } public int getNo(){ return no; } }
|
获取java.lang.Class实例
要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例?
三种方式
第一种:Class c = Class.forName(“完整类名带包名”);
第二种:Class c = 对象.getClass();
第三种:Class c = 任何类型.class;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import java.util.Date;
public class ReflectTest01 { public static void main(String[] args) {
Class c1 = null; Class c2 = null; try { c1 = Class.forName("java.lang.String"); c2 = Class.forName("java.util.Date"); Class c3 = Class.forName("java.lang.Integer"); Class c4 = Class.forName("java.lang.System"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
String s = "abc"; Class x = s.getClass(); System.out.println(c1 == x);
Date time = new Date(); Class y = time.getClass(); System.out.println(c2 == y);
Class z = String.class; Class k = Date.class; Class f = int.class; Class e = double.class;
System.out.println(x == z);
} }
|
字节码内存图:
获取到Class,能干什么?
通过Class的newInstance()方法来实例化对象。
注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import com.bjpowernode.java.bean.User111; import com.bjpowernode.java.bean.User111;
public class ReflectTest02 { public static void main(String[] args) {
User111 user111 = new User111(); System.out.println(user111);
try { Class c = Class.forName("com.bjpowernode.java.bean.User111");
Object obj = c.newInstance();
System.out.println(obj); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } }
|
验证反射机制的灵活性。
java代码写一遍,再不改变java源代码的基础之上,可以做到不同对象的实例化。
非常之灵活。(符合OCP开闭原则:对扩展开放,对修改关闭。)
后期要学习的是高级框架,而工作过程中,也都是使用高级框架,
包括: ssh ssm
Spring SpringMVC MyBatis
Spring Struts Hibernate
…
这些高级框架底层实现原理:都采用了反射机制。所以反射机制还是重要的。
学会了反射机制有利于你理解剖析框架底层的源代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import java.io.FileReader; import java.util.Properties;
public class ReflectTest03 { public static void main(String[] args) throws Exception{
FileReader reader = new FileReader("chapter25/classinfo2.properties"); Properties pro = new Properties(); pro.load(reader); reader.close();
String className = pro.getProperty("className");
Class c = Class.forName(className); Object obj = c.newInstance(); System.out.println(obj); } }
|
研究一下:Class.forName()发生了什么?
记住,重点:
如果你只是希望一个类的静态代码块执行,其它代码一律不执行,
你可以使用:
Class.forName(“完整类名”);
这个方法的执行会导致类加载,类加载时,静态代码块执行。
提示:
后面JDBC技术的时候我们还需要。
1 2 3 4 5 6 7 8 9 10
| public class ReflectTest04 { public static void main(String[] args) { try { Class.forName("com.bjpowernode.java.reflect.MyClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
|
资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用以下这种方式的时候,属性配置文件xxx.properties必须放到类路径下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.util.ResourceBundle;
public class ResourceBundleTest { public static void main(String[] args) {
ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/java/bean/db");
String className = bundle.getString("className"); System.out.println(className);
} }
|
获取Field(了解即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import java.lang.reflect.Field; import java.lang.reflect.Modifier;
public class ReflectTest05 { public static void main(String[] args) throws Exception {
Class studentClass = Class.forName("com.bjpowernode.java.bean.Student111");
String className = studentClass.getName(); System.out.println("完整类名:" + className);
String simpleName = studentClass.getSimpleName(); System.out.println("简类名:" + simpleName);
Field[] fields = studentClass.getFields(); System.out.println(fields.length); Field f = fields[0]; String fieldName = f.getName(); System.out.println(fieldName);
Field[] fs = studentClass.getDeclaredFields(); System.out.println(fs.length);
System.out.println("=================================="); for (Field field : fs) { int i = field.getModifiers(); System.out.println(i); String modifierString = Modifier.toString(i); System.out.println(modifierString); Class fieldType = field.getType(); String fName = fieldType.getSimpleName(); System.out.println(fName); System.out.println(field.getName()); } } }
|
通过反射机制,反编译一个类的属性Field:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class ReflectTest06 { public static void main(String[] args) throws Exception{
StringBuilder s = new StringBuilder();
Class studentClass = Class.forName("java.lang.Thread");
s.append(Modifier.toString(studentClass.getModifiers()) + " class " + studentClass.getSimpleName() + " {\n");
Field[] fields = studentClass.getDeclaredFields(); for(Field field : fields){ s.append("\t"); s.append(Modifier.toString(field.getModifiers())); s.append(" "); s.append(field.getType().getSimpleName()); s.append(" "); s.append(field.getName()); s.append(";\n"); }
s.append("}"); System.out.println(s);
} }
|
反射Method/反编译Method(了解即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import java.lang.reflect.Method; import java.lang.reflect.Modifier;
public class ReflectTest08 { public static void main(String[] args) throws Exception{
Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
Method[] methods = userServiceClass.getDeclaredMethods();
for(Method method : methods){ System.out.println(Modifier.toString(method.getModifiers())); System.out.println(method.getReturnType().getSimpleName()); System.out.println(method.getName()); Class[] parameterTypes = method.getParameterTypes(); for(Class parameterType : parameterTypes){ System.out.println(parameterType.getSimpleName()); } } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import java.lang.reflect.Method; import java.lang.reflect.Modifier;
public class ReflectTest09 { public static void main(String[] args) throws Exception{ StringBuilder s = new StringBuilder(); Class userServiceClass = Class.forName("java.lang.String"); s.append(Modifier.toString(userServiceClass.getModifiers()) + " class "+userServiceClass.getSimpleName()+" {\n");
Method[] methods = userServiceClass.getDeclaredMethods(); for(Method method : methods){ s.append("\t"); s.append(Modifier.toString(method.getModifiers())); s.append(" "); s.append(method.getReturnType().getSimpleName()); s.append(" "); s.append(method.getName()); s.append("("); Class[] parameterTypes = method.getParameterTypes(); for(Class parameterType : parameterTypes){ s.append(parameterType.getSimpleName()); s.append(","); } s.deleteCharAt(s.length() - 1); s.append("){}\n"); }
s.append("}"); System.out.println(s); } }
|
通过反射机制怎么调用一个对象的方法(重点)!
反射机制,让代码很具有通用性,可变化的内容都是写到配置文件当中,
将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,
但是java代码不需要做任何改动。这就是反射机制的魅力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.lang.reflect.Method;
public class ReflectTest10 { public static void main(String[] args) throws Exception{ UserService userService = new UserService();
boolean loginSuccess = userService.login("admin","123"); System.out.println(loginSuccess ? "登录成功" : "登录失败");
Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService"); Object obj = userServiceClass.newInstance(); Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
Object retValue = loginMethod.invoke(obj, "admin","123123"); System.out.println(retValue); } }
|
Constructor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import java.lang.reflect.Constructor; import java.lang.reflect.Modifier;
public class ReflectTest11 { public static void main(String[] args) throws Exception{ StringBuilder s = new StringBuilder(); Class vipClass = Class.forName("java.lang.String"); s.append(Modifier.toString(vipClass.getModifiers())); s.append(" class "); s.append(vipClass.getSimpleName()); s.append("{\n");
Constructor[] constructors = vipClass.getDeclaredConstructors(); for(Constructor constructor : constructors){ s.append("\t"); s.append(Modifier.toString(constructor.getModifiers())); s.append(" "); s.append(vipClass.getSimpleName()); s.append("("); Class[] parameterTypes = constructor.getParameterTypes(); for(Class parameterType : parameterTypes){ s.append(parameterType.getSimpleName()); s.append(","); } if(parameterTypes.length > 0){ s.deleteCharAt(s.length() - 1); } s.append("){}\n"); }
s.append("}"); System.out.println(s); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import com.bjpowernode.java.bean.Vip;
import java.lang.reflect.Constructor;
public class ReflectTest12 { public static void main(String[] args) throws Exception{ Vip v1 = new Vip(); Vip v2 = new Vip(110, "zhangsan", "2001-10-11", true);
Class c = Class.forName("com.bjpowernode.java.bean.Vip"); Object obj = c.newInstance(); System.out.println(obj);
Constructor con = c.getDeclaredConstructor(int.class, String.class, String.class,boolean.class); Object newObj = con.newInstance(110, "jackson", "1990-10-11", true); System.out.println(newObj);
Constructor con2 = c.getDeclaredConstructor(); Object newObj2 = con2.newInstance(); System.out.println(newObj2); } }
|
类加载器
什么是类加载器?
专门负责加载类的命令/工具。
ClassLoader
JDK中自带了3个类加载器
启动类加载器:rt.jar
扩展类加载器:ext/*.jar
应用类加载器:classpath
假设有这样一段代码:
String s = “abc”;
代码在开始执行之前,会将所需要类全部加载到JVM当中。
通过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载,那么是怎么进行加载的呢?
首先通过“启动类加载器”加载。
注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar
rt.jar中都是JDK最核心的类库。
如果通过“启动类加载器”加载不到的时候,
会通过”扩展类加载器”加载。
注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext*.jar
如果“扩展类加载器”没有加载到,那么会通过“应用类加载器”加载。
注意:应用类加载器专门加载:classpath中的类。
双亲委派机制
java中为了保证类加载的安全,使用了双亲委派机制。
优先从启动类加载器中加载,这个称为“父”
“父”无法加载到,再从扩展类加载器中加载,
这个称为“母”。双亲委派。如果都加载不到,
才会考虑从应用类加载器中加载。直到加载到为止。
通过反射机制访问一个java对象的属性
给属性赋值set
获取属性的值get
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import java.lang.reflect.Field;
public class ReflectTest07 { public static void main(String[] args) throws Exception{
Student111 s = new Student111();
s.no = 1111;
System.out.println(s.no);
Class studentClass = Class.forName("com.bjpowernode.java.bean.Student"); Object obj = studentClass.newInstance();
Field noFiled = studentClass.getDeclaredField("no");
noFiled.set(obj, 22222);
System.out.println(noFiled.get(obj));
Field nameField = studentClass.getDeclaredField("name"); nameField.setAccessible(true);
nameField.set(obj, "jackson"); System.out.println(nameField.get(obj)); } }
|
可变长参数
int… args 这就是可变长度参数
语法是:类型… (注意:一定是3个点。)
1、可变长度参数要求的参数个数是:0~N个。
2、可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个。
3、可变长度参数可以当做一个数组来看待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class ArgsTest { public static void main(String[] args) { m(); m(10); m(10, 20);
m2(100); m2(200, "abc"); m2(200, "abc", "def"); m2(200, "abc", "def", "xyz");
m3("ab", "de", "kk", "ff");
String[] strs = {"a","b","c"}; m3(strs);
m3(new String[]{"我","是","中","国", "人"});
m3("我","是","中","国", "人"); }
public static void m(int... args){ System.out.println("m方法执行了!"); }
public static void m2(int a, String... args1){
}
public static void m3(String... args){ for(int i = 0; i < args.length; i++){ System.out.println(args[i]); } }
}
|
获取父类和父接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class ReflectTest13 { public static void main(String[] args) throws Exception{
Class stringClass = Class.forName("java.lang.String");
Class superClass = stringClass.getSuperclass(); System.out.println(superClass.getName());
Class[] interfaces = stringClass.getInterfaces(); for(Class in : interfaces){ System.out.println(in.getName()); } } }
|