一、Class对象
在Object类中定义了以下的方法,此方法将被所有子类继承:
public final Class getClass()
@Test public void test3() { Person person = new Person(); Class clazz = person.getClass(); System.out.println(clazz); }
结果
得到完整的“包类”名称
class com.aidata.clazz.Person
以上的getClass()方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
创建一个类,通过编译(javac.exe),生成对应的.class文件,之后使用java.exe加载(JVM的类加载器)。此.class文件加载到内存以后,就是一个运行时类,存到缓存区中。这个运行时类本身就是一个Class的实例。
每一个运行时类只加载一次
有了Class的实例以后,可以进行如下操作:
- 创建对应的运行时类对象
- 获取对应的运行时类的完整结构(属性、方法、构造器、父类、所在的包、异常、注解......)
- 调用对应的运行时类的指定的结构(属性、方法、构造器)
- 反射的应用:动态代理
获取Class的实例
1)前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
实例:Class clazz = “www.atguigu.com”.getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName(“java.lang.String”);
4)其他方式(不做要求)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
//如何获取Class的实例(3种) @Test public void test4() throws ClassNotFoundException{ //1.调用运行时类本身的.class属性 Class clazz1 = Person.class; System.out.println(clazz1.getName()); Class clazz2 = String.class; System.out.println(clazz2.getName()); //2.通过运行时类的对象获取 Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz3.getName()); //3.通过Class的静态方法获取.通过此方式,体会一下,反射的动态性。 String className = "com.atguigu.java.Person"; Class clazz4 = Class.forName(className); // clazz4.newInstance(); System.out.println(clazz4.getName()); //4.(了解)通过类的加载器 ClassLoader classLoader = this.getClass().getClassLoader(); Class clazz5 = classLoader.loadClass(className); System.out.println(clazz5.getName()); System.out.println(clazz1 == clazz3);//true System.out.println(clazz1 == clazz4);//true System.out.println(clazz1 == clazz5);//true }
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。
类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构 ,如下图所示:
// 1.获取一个系统类加载器 ClassLoader classloader = ClassLoader.getSystemClassLoader(); System.out.println(classloader); // sun.misc.Launcher$AppClassLoader@45ee12a7 // 2.获取系统类加载器的父类加载器,即扩展类加载器 classloader = classloader.getParent(); System.out.println(classloader); // sun.misc.Launcher$ExtClassLoader@6ae40994 // 3.获取扩展类加载器的父类加载器,即引导类加载器 classloader = classloader.getParent(); System.out.println(classloader); // null,无法获取引导类加载器 // 4.测试当前类由哪个类加载器进行加载 classloader = Class.forName("com.aidata.clazz.TestReflection").getClassLoader(); System.out.println(classloader); // sun.misc.Launcher$AppClassLoader@45ee12a7 // 5.测试JDK提供的Object类由哪个类加载器加载 classloader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classloader); // null // 6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流 InputStream in = null; in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties"); System.out.println(in);
二、反射
Reflection是动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
数据库操作会用到反射:
数据库中有customer、student两张表
转为Java对象才能用Java进行操作,前提是创建Java对象
因为我们操作是不确定的,可能只操作customer,也可能只操作student,也可能两者都操作
很自然的想法就是在真正操作对应表格的时候创建对应对象
我们不想为每一个表都创建一个方法,想实现一个通用的方法,可以对任何表进行处理
该方法会根据是cusomer还是student表创建不同的对象,创建的对象没有在源代码中写死
Class类与java.lang.reflect类库一起对反射的概念进行了支持:
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法
- ...
// 在有反射之前,创建一个类的对象,并调用其中的方法、属性 @Test public void test1() { Person person = new Person(); person.setAge(10); person.setName("Tom"); System.out.println(person); person.show(); person.display("US"); } // 有了反射可以使用反射创建一个类的对象,并调用其中的结构 @Test public void test2() throws Exception { Class clazz = Person.class; // 1.创建clazz对应的运行时类Person类的对象 Person person = (Person) clazz.newInstance(); // 使用泛型可以不用强转 // Class<Person> clazz = Person.class; // Person person = clazz.newInstance(); System.out.println(person); // 2.调用属性 Field f1 = clazz.getField("name"); f1.set(person, "Jack"); System.out.println(person); // 修改private属性 Field f2 = clazz.getDeclaredField("age"); f2.setAccessible(true); f2.set(person, 20); System.out.println(person); // 3.通过反射调用运行时类的指定方法 Method m1 = clazz.getMethod("show"); m1.invoke(person); Method m2 = clazz.getMethod("display", String.class); m2.invoke(person, "CN"); }
2.1 创建运行时类对象
调用Class对象的newInstance()方法
要 求: 1)类必须有一个无参数的构造器。
2)类的构造器的访问权限需要足够。
难道没有无参的构造器就不能创建对象了吗?
不是!只要在操作的时候明确的调用类中的构造方法,并将参数传递进去之后,才可以实例化操作。步骤如下:
1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
public class TestConstructor { @Test public void test1() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); //创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。 //要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。 Object obj = clazz.newInstance(); Person p = (Person)obj; System.out.println(p); } @Test public void test2() throws ClassNotFoundException{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); Constructor[] cons = clazz.getDeclaredConstructors(); for(Constructor c : cons){ System.out.println(c); } } //调用指定的构造器,创建运行时类的对象 @Test public void test3() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); Constructor cons = clazz.getDeclaredConstructor(String.class,int.class); cons.setAccessible(true); Person p = (Person)cons.newInstance("罗伟",20); System.out.println(p); } }
//1.根据全类名获取对应的Class对象 String name = “atguigu.java.Person"; Class clazz = null; clazz = Class.forName(name); //2.调用指定参数结构的构造器,生成Constructor的实例 Constructor con = clazz.getConstructor(String.class,Integer.class); //3.通过Constructor的实例创建对应类的对象,并初始化类属性 Person p2 = (Person)con.newInstance("Peter",20); System.out.println(p2);
2.2 调用类的完整结构
Field、Method、Constructor、Superclass、Interface、Annotation
- 实现的全部接口
- 所继承的父类
- 全部的构造器
- 全部的方法
- 全部的Field
使用反射可以取得:
1.实现的全部接口
public Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
2.所继承的父类
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
3.全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。
Constructor类中:
取得修饰符: public int getModifiers();
取得方法名称: public String getName();
取得参数的类型:public Class<?>[] getParameterTypes();
public class TestConstructor { @Test public void test1() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); //创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。 //要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。 Object obj = clazz.newInstance(); Person p = (Person)obj; System.out.println(p); } @Test public void test2() throws ClassNotFoundException{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); Constructor[] cons = clazz.getDeclaredConstructors(); for(Constructor c : cons){ System.out.println(c); } } //调用指定的构造器,创建运行时类的对象 @Test public void test3() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); Constructor cons = clazz.getDeclaredConstructor(String.class,int.class); cons.setAccessible(true); Person p = (Person)cons.newInstance("罗伟",20); System.out.println(p); } }
4.全部的方法
public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此Class对象所表示的类或接口的public的方法
Method类中:
public Class<?> getReturnType()取得返回值类型
public Class<?>[] getParameterTypes()取得全部的参数
public int getModifiers()取得修饰符
public Class<?>[] getExceptionTypes()取得异常信息
//1.获取运行时类的方法 @Test public void test1(){ Class clazz = Person.class; //1.getMethods():获取运行时类及其父类中所有的声明为public的方法 Method[] m1 = clazz.getMethods(); for(Method m : m1){ System.out.println(m); } System.out.println(); //2.getDeclaredMethods():获取运行时类本身声明的所有的方法 Method[] m2 = clazz.getDeclaredMethods(); for(Method m : m2){ System.out.println(m); } } //注解 权限修饰符 返回值类型 方法名 形参列表 异常 @Test public void test2(){ Class clazz = Person.class; Method[] m2 = clazz.getDeclaredMethods(); for(Method m : m2){ //1.注解 Annotation[] ann = m.getAnnotations(); for(Annotation a : ann){ System.out.println(a); } //2.权限修饰符 String str = Modifier.toString(m.getModifiers()); System.out.print(str + " "); //3.返回值类型 Class returnType = m.getReturnType(); System.out.print(returnType.getName() + " "); //4.方法名 System.out.print(m.getName() + " "); //5.形参列表 System.out.print("("); Class[] params = m.getParameterTypes(); for(int i = 0;i < params.length;i++){ System.out.print(params[i].getName() + " args-" + i + " "); } System.out.print(")"); //6.异常类型 Class[] exps = m.getExceptionTypes(); if(exps.length != 0){ System.out.print("throws "); } for(int i = 0;i < exps.length;i++){ System.out.print(exps[i].getName() + " "); } System.out.println(); } }
5.全部的Field
public Field[] getFields()
返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields()
返回此Class对象所表示的类或接口的全部Field。
Field方法中:
public int getModifiers() 以整数形式返回此Field的修饰符
public Class<?> getType() 得到Field的属性类型
public String getName() 返回Field的名称。
//获取对应的运行时类的属性 @Test public void test1(){ Class clazz = Person.class; //1.getFields():只能获取到运行时类中及其父类中声明为public的属性 Field[] fields = clazz.getFields(); for(int i = 0;i < fields.length;i++){ System.out.println(fields[i]); } System.out.println(); //2.getDeclaredFields():获取运行时类本身声明的所有的属性 Field[] fields1 = clazz.getDeclaredFields(); for(Field f : fields1){ System.out.println(f.getName()); } } //权限修饰符 变量类型 变量名 //获取属性的各个部分的内容 @Test public void test2(){ Class clazz = Person.class; Field[] fields1 = clazz.getDeclaredFields(); for(Field f : fields1){ //1.获取每个属性的权限修饰符 int i = f.getModifiers(); String str1 = Modifier.toString(i); System.out.print(str1 + " "); //2.获取属性的类型 Class type = f.getType(); System.out.print(type.getName() + " "); //3.获取属性名 System.out.print(f.getName()); System.out.println(); } }
6. Annotation相关
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()
7.泛型相关
获取父类泛型类型:Type getGenericSuperclass()
泛型类型:ParameterizedType
获取实际的泛型类型参数数组:getActualTypeArguments()
8.类所在的包 Package getPackage()
public class TestOthers { //6.获取注解 @Test public void test6(){ Class clazz = Person.class; Annotation[] anns = clazz.getAnnotations(); for(Annotation a : anns){ System.out.println(a); } } //5.获取所在的包 @Test public void test5(){ Class clazz = Person.class; Package pack = clazz.getPackage(); System.out.println(pack); } //4.获取实现的接口 @Test public void test4(){ Class clazz = Person.class; Class[] interfaces = clazz.getInterfaces(); for(Class i : interfaces){ System.out.println(i); } } //3*.获取父类的泛型 @Test public void test3(){ Class clazz = Person.class; Type type1 = clazz.getGenericSuperclass(); ParameterizedType param = (ParameterizedType)type1; Type[] ars = param.getActualTypeArguments(); System.out.println(((Class)ars[0]).getName()); } //2.获取带泛型的父类 @Test public void test2(){ Class clazz = Person.class; Type type1 = clazz.getGenericSuperclass(); System.out.println(type1); } //1.获取运行时类的父类 @Test public void test1(){ Class clazz = Person.class; Class superClass = clazz.getSuperclass(); System.out.println(superClass); } }
2.3 通过反射调用类中的指定方法、指定属性
调用指定方法
通过反射,调用类中的方法,通过Method类完成。步骤:
1.通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。
2.之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。
Object invoke(Object obj, Object … args)
说明:
1.Object 对应原方法的返回值,若原方法无返回值,此时返回null
2.若原方法若为静态方法,此时形参Object obj可为null
3.若原方法形参列表为空,则Object[] args为null
4.若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
//调用运行时类中指定的方法 @Test public void test3() throws Exception{ Class clazz = Person.class; //getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法 Method m1 = clazz.getMethod("show"); Person p = (Person)clazz.newInstance(); //调用指定的方法:Object invoke(Object obj,Object ... obj) Object returnVal = m1.invoke(p);//我是一个人 System.out.println(returnVal);//null Method m2 = clazz.getMethod("toString"); Object returnVal1 = m2.invoke(p); System.out.println(returnVal1);//Person [name=null, age=0] //对于运行时类中静态方法的调用 Method m3 = clazz.getMethod("info"); m3.invoke(Person.class); //getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法 Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class); m4.setAccessible(true); Object value = m4.invoke(p,"CHN",10);//我的国籍是:CHN System.out.println(value);//10 }
调用指定的属性
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。
在Field中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
//调用运行时类中指定的属性 @Test public void test3() throws Exception{ Class clazz = Person.class; //1.获取指定的属性 //getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性 Field name = clazz.getField("name"); //2.创建运行时类的对象 Person p = (Person)clazz.newInstance(); System.out.println(p); //3.将运行时类的指定的属性赋值 name.set(p,"Jerry"); System.out.println(p); System.out.println("%"+name.get(p)); System.out.println(); //getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性 Field age = clazz.getDeclaredField("age"); //由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。 age.setAccessible(true); age.set(p,10); System.out.println(p); // Field id = clazz.getField("id"); }
注:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。
public void setAccessible(true)访问私有属性时,让这个属性可见。
三、动态代理
静态代理
//静态代理模式 //接口 interface ClothFactory{ void productCloth(); } //被代理类 class NikeClothFactory implements ClothFactory{ @Override public void productCloth() { System.out.println("Nike工厂生产一批衣服"); } } //代理类 class ProxyFactory implements ClothFactory{ ClothFactory cf; //创建代理类的对象时,实际传入一个被代理类的对象 public ProxyFactory(ClothFactory cf){ this.cf = cf; } @Override public void productCloth() { System.out.println("代理类开始执行,收代理费$1000"); cf.productCloth(); } } public class TestClothProduct { public static void main(String[] args) { NikeClothFactory nike = new NikeClothFactory();//创建被代理类的对象 ProxyFactory proxy = new ProxyFactory(nike);//创建代理类的对象 proxy.productCloth(); } }
静态代理代理类和接口是配对的,来一个新的接口需要重新创建代理类
动态创建代理类
interface Subject { void action(); } class RealSubject implements Subject { @Override public void action() { System.out.println("我是被代理类"); } } class MyInvocationHandler implements InvocationHandler { Object obj; // 实现了接口的被代理类的对象的声明 // 给被代理类的对象实例化 // 返回一个代理类的对象 public Object blind(Object obj) { this.obj = obj; // this是实现了InvocationHandler接口的对象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); } // 当通过代理类的对象发起对被重写的方法的调用时,都会转为对如下的invoke方法的调用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // method方法的返回值是returnVal Object returnVal = method.invoke(obj, args); return returnVal; } } public class TestProxy { public static void main(String[] args) { // 1.被代理类的对象 RealSubject real = new RealSubject(); // 2.创建了一个实现了InvacationHandler接口的类的对象 MyInvocationHandler handler = new MyInvocationHandler(); // 3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象 Object obj = handler.blind(real); Subject sub = (Subject) obj; // 此时sub就是代理类的对象 sub.action(); // 转到对InvacationHandler接口的实现类的invoke()方法的调用 NikeClothFactory nike = new NikeClothFactory(); ClothFactory proxyCloth = (ClothFactory) handler.blind(nike); // proxyCloth即为代理类对象 proxyCloth.productCloth(); } }
源码分析