Java反射机制
java反射机制概述
- Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API(反射接口)取得任何类的内部信息,并能直接操作任何对象的内部属性及方法
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称为:反射。
动态语言 VS 静态语言
- 动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行代码可以根据某些条件改变自身结构
主要静态语言:Object-C、C#、JavaScript、PHP、Python、Erlang
- 静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++
- Java
Java不是动态语言,但Java可以称之为”准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活
Java反射机制研究及应用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
Java反射相关的主要API
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
- ……
Java反射之前,类的实例化
Person类,封装了一些方法和构造器
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
| package com.atguigu.java;
public class Person { private String name; public int age; public Person() {} @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public Person(String name, int age) { this.name = name; this.age = age; } private Person(String name){ this.name=name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } public void show(){ System.out.println("我是一个人"); } private void showNation(String nation){ System.out.println("我的国籍是"+nation); return; } }
|
RefilectionTest类,调用Person类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.java;
import org.junit.Test;
public class RefilectionTest { @Test public void test1(){ Person p1 = new Person("Tom",12); p1.age=10; System.out.println(p1.toString()); p1.show(); } }
|
Java反射之后
Person类,封装了一些公有私有的属性,公有私有的方法
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
| package com.atguigu.java;
public class Person { private String name; public int age; public Person() {} @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public Person(String name, int age) { this.name = name; this.age = age; } private Person(String name){ this.name=name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; } public void show(){ System.out.println("我是一个人"); } private void showNation(String nation){ System.out.println("我的国籍是"+nation); return; } }
|
RefilectionTest类,通过反射调用其中的属性和方法
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
| @Test public void test2() throws Exception { Class clazz = Person.class; Constructor cons =clazz.getConstructor(String.class,int.class); Object obj=cons.newInstance("Tom",12); Person p = (Person) obj;
Field age =clazz.getDeclaredField("age"); age.set(p,10); Method shows=clazz.getDeclaredMethod("show"); shows.invoke(p); System.out.println("***************************************"); Constructor cons1=clazz.getDeclaredConstructor(String.class); cons1.setAccessible(true); Person p1=(Person) cons1.newInstance("Jerry");
Field name=clazz.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"huangyufeng"); System.out.println(p1);
Method nation=clazz.getDeclaredMethod("showNation", String.class); nation.setAccessible(true); nation.invoke(p1,"中国"); }
|
Java反射-Class类的理解
获取Class实例的四种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| } @Test public void test3() throws ClassNotFoundException { Class clazz1 = Person.class; System.out.println(clazz1);
Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2);
Class clazz3=Class.forName("com.atguigu.java.Person"); System.out.println(clazz3);
ClassLoader classLoader=RefilectionTest.class.getClassLoader(); Class clazz4=classLoader.loadClass("com.atguigu.java.Person"); System.out.println(clazz4);
|
class实例对应的结构说明
- class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- interface:接口
- []:接口
- enum:枚举
- annotation:注解@interface
- primitive type:基本数据类型
- void
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Test public void test4(){ Class c1 = Object.class; Class c2 = Comparable.class; Class c3 = String[].class; Class c4 = int[][].class; Class<ElementType> c5 = ElementType.class; Class c6 = Override.class; Class c7 = int.class; Class c8 = void.class; Class c9 = Class.class;
int[] a = new int[10]; int[] b = new int[100]; Class c10 = a.getClass(); Class c11 = b.getClass(); System.out.println(c10==c11);
|
理解类的加载过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化
类的加载与ClassLoader的理解
类加载器的作用:
- 类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
- 类缓存:标准的JavaSE类加载器可以按照要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象
ClassLoder:
类加载器的作用是用来把类(class)装载进内存的,JVM规范定义如下类似类的加载器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.java;
import org.junit.Test;
public class ClassLoderTest { @Test public void test1(){ ClassLoader classLoader=ClassLoderTest.class.getClassLoader(); System.out.println(classLoader); ClassLoader parent=classLoader.getParent(); System.out.println(parent); ClassLoader classLoader1=parent.getParent(); System.out.println(classLoader1); } }
|
使用ClassLoader加载配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@Test public void test2() throws IOException { Properties properties = new Properties(); FileInputStream fis = new FileInputStream("D:\\Documents\\java\\javaweb\\jdbc\\src\\jdbc.properties"); properties.load(fis);
InputStream is = ClassLoderTest.class.getClassLoader().getResourceAsStream("jdbc.properties"); properties.load(is);
String user=properties.getProperty("user"); String password=properties.getProperty("password"); System.out.println(user+","+password); }
|
创建运行时类的实例化对象
通过反射创建对应的运行时类的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public class NewInstanceTest { @Test public void test1() throws Exception { Class clazz = Person.class;
Person obj = (Person) clazz.newInstance(); System.out.println(obj); obj.show();
}
|
举例体会反射的动态性
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
| @Test public void test2(){
for(int i = 0;i < 100;i++){ int num = new Random().nextInt(3); String classPath = ""; switch(num){ case 0: classPath = "java.util.Date"; break; case 1: classPath = "java.lang.Object"; break; case 2: classPath = "com.atguigu.java.Person"; break; }
try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } }
}
public Object getInstance(String classPath) throws Exception { Class clazz = Class.forName(classPath); return clazz.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 30 31 32 33 34 35 36 37 38 39 40 41
| public class FieldTest { @Test public void test1() throws InstantiationException, IllegalAccessException { Class clazz = Person.class; Person p1 = (Person) clazz.newInstance(); System.out.println(clazz); System.out.println(p1);
Field[] fields = clazz.getFields(); for (Field f : fields) { System.out.println(f); } System.out.println("*********************************");
Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields) { System.out.println(f); } }
@Test public void test2() { Class clazz = Person.class; Field[] declaredFields = clazz.getDeclaredFields(); for (Field f : declaredFields) { System.out.println(f); int modifiers=f.getModifiers(); System.out.println(modifiers); System.out.println(Modifier.toString(modifiers)); Class type=f.getType(); System.out.println(type+"\t"); String name = f.getName(); System.out.println(name); } }
|
获取运行时类的方法结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class MethodTest { @Test public void test1(){ Class clazz = Person.class;
Method[] method =clazz.getMethods(); for (Method m:method){ System.out.println(m); } System.out.println("********************");
Method[] method2=clazz.getDeclaredMethods(); for (Method method1:method2){ System.out.println(method1); } } }
|
获取方法的权限修饰符,返回值类型,方法名(参数类型1 形参名1,……)throws
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 54 55 56 57 58 59 60 61
|
@Test public void test2(){ Class clazz = Person.class; Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method m : declaredMethods){ Annotation[] annos = m.getAnnotations(); for(Annotation a : annos){ System.out.println(a); }
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
System.out.print(m.getReturnType().getName() + "\t");
System.out.print(m.getName()); System.out.print("("); Class[] parameterTypes = m.getParameterTypes(); if(!(parameterTypes == null && parameterTypes.length == 0)){ for(int i = 0;i < parameterTypes.length;i++){
if(i == parameterTypes.length - 1){ System.out.print(parameterTypes[i].getName() + " args_" + i); break; }
System.out.print(parameterTypes[i].getName() + " args_" + i + ","); } }
System.out.print(")");
Class[] exceptionTypes = m.getExceptionTypes(); if(exceptionTypes.length > 0){ System.out.print("throws "); for(int i = 0;i < exceptionTypes.length;i++){ if(i == exceptionTypes.length - 1){ System.out.print(exceptionTypes[i].getName()); break; }
System.out.print(exceptionTypes[i].getName() + ","); } }
System.out.println(); }
}
|
获取运行时类的构造器结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class OtherTest {
@Test public void test1(){ Class clazz = Person.class; Constructor[] constructors1 =clazz.getConstructors(); for (Constructor c:constructors1){ System.out.println(c); } System.out.println("***********************");
Constructor[] constructors2=clazz.getDeclaredConstructors(); for (Constructor constructor:constructors2){ System.out.println(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
| public class OtherTest {
@Test public void test2(){ Class clazz = Person.class; Class superclass=clazz.getSuperclass(); System.out.println(superclass); }
@Test public void test3(){ Class clazz = Person.class; Type superclass =clazz.getGenericSuperclass(); System.out.println(superclass); }
@Test public void test4(){ Class clazz = Person.class; Type superclass =clazz.getGenericSuperclass(); ParameterizedType parameterizedType = (ParameterizedType)superclass; Type[] actualTypeArguments= parameterizedType.getActualTypeArguments(); System.out.println(actualTypeArguments[0].getTypeName()); } }
|
获取运行时类的接口,所在包,注解等
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
|
@Test public void test5(){ Class clazz = Person.class; Class[] classinter=clazz.getInterfaces(); for (Class c :classinter){ System.out.println(c); } System.out.println("*******************"); Class[] interfaces1=clazz.getSuperclass().getInterfaces(); for (Class c1:interfaces1){ System.out.println(c1); } }
@Test public void test6(){ Class clazz = Person.class; Package pack=clazz.getPackage(); System.out.println(pack); }
@Test public void test7(){ Class clazz = Person.class; Annotation[] clazzAnnotations =clazz.getAnnotations(); for (Annotation a:clazzAnnotations){ System.out.println(a); } }
|
调用运行时类的指定结构
调用运行时类中的指定属性
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
|
public class ReflectionTest { @Test public void testField() throws Exception { Class clazz = Person.class;
Person p = (Person) clazz.newInstance();
Field id =clazz.getField("id");
id.set(p,1001);
int pId=(int)id.get(p); System.out.println(pId); }
@Test public void testField1() throws Exception{ Class clazz = Person.class;
Person p = (Person) clazz.newInstance();
Field name=clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p,"Tom"); String pName=(String) name.get(p); System.out.println(pName); } }
|
调用运行时类中的指定方法
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
|
@Test public void testMethod() throws Exception{ Class clazz = Person.class;
Person p=(Person) clazz.newInstance();
Method show =clazz.getDeclaredMethod("show",String.class);
show.setAccessible(true);
show.invoke(p,"CHN"); Object returnValue=show.invoke(p,"CHN"); System.out.println(returnValue);
System.out.println("***************如何调用静态方法****************"); Method showDesc=clazz.getDeclaredMethod("showDesc"); showDesc.setAccessible(true); showDesc.invoke(Person.class.newInstance()); Object returnVal = showDesc.invoke(Person.class.newInstance()); System.out.println(returnVal);
} }
|
调用运行时类的指定构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@Test public void testConstructor()throws Exception{ Class clazz = Person.class;
Constructor constructor =clazz.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Person per = (Person) constructor.newInstance("Tom",12); System.out.println(per); } }
|
代理模式
代理设计模式的原理