//新建一个Person类 package ReflectionTest; public class Person { private String name; public int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } private Person(String name) { this.name = name; this.age = age; } 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; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public void show(){ System.out.println("这是一个人"); } private String showNation(String nation){ System.out.println("我的国籍是"+nation); return nation; } }
import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionTest { //反射之前对于Person类的操作 @Test public void test1(){ //1、创建Person类的对象 Person p1 = new Person("Tom",12); //2、通过对象调用内部的属性、方法 p1.age = 10;//age是 public 修饰的 System.out.println(p1.toString()); p1.show(); //在Person外部不可以通过Person类的对象,调用其私有的结构 //如 name、showNation() 以及私有的构造器 } //反射之后,对于Person的操作 @Test public void test2() throws Exception { Class class1 = Person.class; //通过反射,创建 Person 的类的对象 Constructor cons = class1.getConstructor(String.class, int.class); Object obj = cons.newInstance("Tom", 12); Person p = (Person) obj; System.out.println(obj.toString());//调用的是 Person 类的toString() //2、通过反射,调用对象指定的属性、方法 //调属性 Field age = class1.getDeclaredField("age"); age.set(p,10); System.out.println(p.toString()); //调方法 Method show = class1.getDeclaredMethod("show"); show.invoke(p); System.out.println("*****************************************************"); //通过反射,可以调用 Person 的私有结构。比如:私有构造器、方法、属性 Constructor cons1 = class1.getDeclaredConstructor(String.class); cons1.setAccessible(true); Person p1 = (Person) cons1.newInstance("Jerry"); System.out.println(p1);//Person{name='Jerry', age=0} //调用私有的属性和方法 Field name = class1.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"Jack"); System.out.println(p1.toString());//Person{name='Jack', age=0} //调用私有的方法 Method showNation = class1.getDeclaredMethod("showNation", String.class);//String.class 是 showNation 的参数 showNation.setAccessible(true); String nation = (String)showNation.invoke(p1, "中国");//invoke() 是一个调用功能,相当于 p1.showNation("中国"); //我的国籍是中国 System.out.println(nation);//获取 showNation 的返回值 //中国 } }
疑问:通过直接 new 的方式或反射的方式都可以调用公共的结构,开发中到底用那个? 建议直接 new 的方式 什么时候会使用反射的方式:反射的特征:动态性 疑问:反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术? 不矛盾。封装性是建议不用私有的,而反射机制是解决能不能用私有的问题
关于java.lang.Class 类的理解 1、类的加载过程: 程序在经过 javac.exe 命令后,会生成一个或多个字节码文件(.class 结尾),接着我们使用 java.exe 命令对某个字节码文件进行解释运行。 相当于将某个字节码文件加载到内存中。此过程称为类的加载。 加载到内存中的类,我们就称为运行时类,此运行时类就作为 Class 的一个实例。 2、换句话说,Class 的实例化就对应着一个运行时类。 3、加载到内存中的运行时类,会缓存一段时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。
//获取 Class 的实例的方式 @Test public void test3() throws ClassNotFoundException { //方式一:调用运行时类本身 : .class // Class<Person> class1 = Person.class; Class class1 = Person.class; System.out.println(class1);//class ReflectionTest.Person 输出当前类本身 //********************************************************************* //方式二:通过运行时类的对象获取,调用 getClass() 方法 Person p1 = new Person(); Class class2 = p1.getClass(); System.out.println(class2);//class ReflectionTest.Person //********************************************************************* //方式三:调用 Class 的静态方法 : forName(String classPath) Class class3 = Class.forName("ReflectionTest.Person");//类的全类名(包含包下的完整路径) // Class class3 = Class.forName("java.lang.String");//class java.lang.String System.out.println(class3);//class ReflectionTest.Person System.out.println(class1 == class2);//true System.out.println(class1 == class3);//true //获取的都是内存中同一个运行时类,只是获取的方式不同,运行时类唯一存在,不会重新加载多个,相当于单例模式 //前三种方法需要掌握 //********************************************************************* //方式四:使用类的加载器:ClassLoader (当前类为ReflectionTest)(了解) ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class class4 = classLoader.loadClass("ReflectionTest.Person"); System.out.println(class4);//class ReflectionTest.Person System.out.println(class1 == class4);//true }
//Class 实例可以时哪些结构的说明: @Test public void test(){ Class c1 = Object.class; Class c2 = Comparable.class; Class c3 = String[].class; Class c4 = int[][].class; Class 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(); // 只要元素类型与维度一样,就是同一个Class System.out.println(c10 == c11); }
import org.junit.Test; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; /** 了解类的加载器 */ public class ClassLoaderTest { @Test public void test1(){ //对于自定义类,使用系统类加载器进行加载 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();//获取到当前自定义类的类的加载器 System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2 系统类加载器 //调用系统类加载器的方法 getParent() 方法,可以获取扩展类加载器 ClassLoader parent = classLoader.getParent();//获取到当前类的加载器的上一层 System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@279f2327 //调用扩展类加载器的方法 getParent() 方法,无法获取引导类加载器 //引导类加载器主要负责加载java的核心类库,无法加载自定义类的。 ClassLoader parentParent = parent.getParent(); System.out.println(parentParent);//null //获取不到再上层的加载器 //String 是引导类加载器加载的,但是我们无法获取到引导类加载器 ClassLoader classLoaderStr = String.class.getClassLoader(); System.out.println(classLoaderStr);//null } /* Properties : 用来读取配置文件。 在当前 module 下新建一个 jdbc.properties 文件,在文件中写入 user=userName password=password */ @Test public void test2() throws Exception { Properties pros = new Properties(); //此时的文件(jdbc.properties)默认在当前的 module 下 //读取配置文件的方式一: FileInputStream fis = new FileInputStream("jdbc.properties"); pros.load(fis); //读取配置文件的方式二:使用ClassLoader //配置文件(jdbc1.properties)默认识别为当前 module 的 src 下 // ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); // InputStream is = classLoader.getResourceAsStream("jdbc1.properties"); // pros.load(is); String user = pros.getProperty("user"); String password = pros.getProperty("password"); System.out.println("user"+user+" "+"password"+password); } }
class.newInstance();//调用了运行时类的空参构造器
具体举例如下:
import org.junit.Test; /** 通过反射创建对应的运行时类对象 */ public class NewInstanceTest { @Test public void test1() throws IllegalAccessException, InstantiationException { // Class<Person> class1 = Person.class; /* newInstance() : 调用此方法,创建对应的运行时类的对象,内部调用了运行时类的空参构造器。 要想此方法正常创建运行时类的对象,要求: 1、运行时类必须提供空参构造器。 2、空参构造器的访问权限得够调用。通常设置为 public 。 在javabean中要求提供一个 public 的空参构造器,原有: 1、便于通过反射,创建运行时类的对象 2、便于子类继承此运行时类时,默认调用 super() 时,保证父类有此构造器。 */ Person p = (Person) class1.newInstance();//调用 Person 的空参构造器 System.out.println(p);//Person{name='null', age=0} 创建的是 Person 类的对象 } }
通过 newInstance() 方法,动态调用类的空参构造器,来创建类的对象,实现动态创建类,需要创建某个类的对象时,提供该类的全类名,即可创建该类的对象。
//体会反射的动态性 @Test public void test2(){ int num = new Random().nextInt(3);//0,1,2 String classPath=""; switch (num){ case 0: classPath = "java.util.Date"; break; case 1: // classPath = "java.sql.Date";//java.lang.InstantiationException: java.sql.Date 没有空参构造器 classPath = "java.lang.Object"; break; case 2: classPath = "ReflectionTest.Person"; break; } try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } /* 创建一个指定类的对象 classPath : 指定类的全类名 */ public Object getInstance(String classPath) throws Exception { Class class1 = Class.forName(classPath); return class1.newInstance(); }
package ReflectionTest2; import java.io.Serializable; /** 创建一个Person的父类Creature */ public class Creature<T> implements Serializable {//可序列化 private char gender; public double weight; private void breath(){ System.out.println("生物,呼吸"); } public void eat(){ System.out.println("生物,吃东西"); } }
package ReflectionTest2; /** 创建一个接口MyInterface 由Person实现 */ public interface MyInterface { void info(); }
package ReflectionTest2; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; /** 创建一个自定义的注解结构,并使用在Person类上 */ @Target({TYPE,FIELD,METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default "Hello"; }
package ReflectionTest2; /** 创建一个丰富的Person类 */ @MyAnnotation(value = "hi") public class Person extends Creature<String> implements Comparable<String>,MyInterface { private String name; int age; public int id; public Person(){} @MyAnnotation(value = "123") private Person(String name){ this.name=name; } Person(String name,int age){ this.name=name; this.age=age; } @MyAnnotation private String show(String nation){ System.out.println("我的国籍是"+nation); return nation; } public String display(String interests){ return interests; } @Override public void info() { System.out.println("这是一个人"); } @Override public int compareTo(String o) { return 0; } private static void showDesc(){ System.out.println("这是一个静态方法"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; } }
package ReflectionTest3; import ReflectionTest2.Person; import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** 获取当前运行时类的属性结构 */ public class FieldTest { @Test public void test1() throws Exception { Class class1 = Class.forName("ReflectionTest2.Person"); //获取属性结构 //getFields() : 获取当前运行时类及其父类种声明为 public 访问权限1的属性 Field[] fields = class1.getFields(); for (Field f: fields) { System.out.println(f); } System.out.println("********************************************"); //getDeclaredFields() : 取当前运行时类中声明的所有属性。(不包含父类中声明的属性) Field[] declaredFields = class1.getDeclaredFields(); for (Field f: declaredFields) { System.out.println(f); } } //权限修饰符 数据类型 变量名 这些都可以单独获取拿到 @Test public void test2(){ Class class1 = Person.class; Field[] declaredFields = class1.getDeclaredFields();//获取当前所有的属性,构成一个数组 for (Field f: declaredFields) { //1、获取 权限修饰符 int modifiers = f.getModifiers();//返回值是int类型的 System.out.print(Modifier.toString(modifiers)+"\t");//将 modifiers 翻译回权限修饰符 //2、获取 数据类型 Class type = f.getType(); System.out.print(type.getName()+"\t");//type.getName 获取当前class的名字 //3、获取 变量名 String fName = f.getName();//变量名直接getName() 即可 System.out.println(fName); } } }
package ReflectionTest3; import ReflectionTest2.Person; import org.junit.Test; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** 获取运行时类的方法结构 */ public class MethodTest { @Test public void test1(){ Class class1 = Person.class; //获取 所有的方法 构成的数组 //getMethods() : 获取当前运行时类及其所有父类声明为public的方法 Method[] methods = class1.getMethods(); for (Method m : methods) { System.out.println(m); } System.out.println("*********************************************"); //getDeclaredMethods() : 获取当前运行时类中声明的所有方法(不包含父类中声明的方法) Method[] declaredMethods = class1.getDeclaredMethods(); for (Method m : declaredMethods) { System.out.println(m); } } /* @Xxx 权限修饰符 返回值类型 方法名(参数类型1 形参名1 , ....) throws XxxException{} */ @Test public void test2(){ Class class1 = Person.class; Method[] declaredMethods = class1.getDeclaredMethods(); for (Method m : declaredMethods) { //1、获取方法声明的注解 Annotation[] annos = m.getAnnotations(); for (Annotation a:annos) { System.out.print(a+"\t");//@ReflectionTest2.MyAnnotation(value=Hello) } //2、获取方法的权限修饰符 System.out.print(Modifier.toString(m.getModifiers())+"\t"); // System.out.println(); //3、获取方法的返回值类型 System.out.print(m.getReturnType()+"\t"); //4、获取方法的方法名 System.out.print(m.getName()); System.out.print("("); //5、形参列表 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(")"); //6、抛出的异常 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]); break; } System.out.print(exceptionTypes[i] + ","); } } System.out.println(); } } }
/* 获取构造器结构 */ @Test public void test1(){ //获取当前运行时类当中,声明为 public 的构造器 Class class1 = Person.class; Constructor[] constructors = class1.getConstructors(); for (Constructor c: constructors) { System.out.println(c); } System.out.println("*************************"); //getDeclaredConstructors(): 获取当前运行时类声明的所有构造器 Constructor[] declaredConstructors = class1.getDeclaredConstructors(); for (Constructor c : declaredConstructors) { System.out.println(c); } }
/* 获取运行时类的父类 */ @Test public void test2(){ Class class1 = Person.class; Class superclass = class1.getSuperclass(); System.out.println(superclass);//class ReflectionTest2.Creature } /* 获取运行时类带泛型的父类 */ @Test public void test3(){ Class class1 = Person.class; Type genericSuperclass = class1.getGenericSuperclass(); System.out.println(genericSuperclass);//ReflectionTest2.Creature<java.lang.String> } /* 获取运行时类带泛型的父类的泛型 代码:逻辑性代码 vs 功能性代码 */ @Test public void test4(){ Class class1 = Person.class; // Type genericSuperclass = class1.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType)genericSuperclass; //获取泛型类型 Type[] actualTypeArguments = paramType.getActualTypeArguments(); // System.out.println(actualTypeArguments[0].getTypeName());//java.lang.String System.out.println(((Class)actualTypeArguments[0]).getName()); }
获取接口在动态代理的时候会使用到
/* 获取运行时类实现的接口 */ @Test public void test5(){ Class class1 = Person.class; Class[] interfaces = class1.getInterfaces(); for (Class c: interfaces) { System.out.println(c); } System.out.println("*********************"); //获取运行时类父类实现的接口 Class superclass = class1.getSuperclass(); Class[] interfaces1 = superclass.getInterfaces(); for (Class c: interfaces1) { System.out.println(c); } } /* 获取运行时类所在的包 */ @Test public void test6(){ Class class1 = Person.class; Package aPackage = class1.getPackage(); System.out.println(aPackage);//package ReflectionTest2 } /* 获取运行时类声明的注解 */ @Test public void test7(){ Class class1 = Person.class; Annotation[] annotations = class1.getAnnotations(); for (Annotation a: annotations) { System.out.println(a); } }
/* getFiled() : 获取指定的属性:要求运行时类中属性声明为 public 通常不采用此方法,对于属性的要求太高,可以不需要掌握 */ @Test public void testField() throws Exception { Class class1 = Person.class; //创建运行时类的对象 Person p = (Person) class1.newInstance(); //getField(String filedName) Field id = class1.getField("id");//权限为public // class1.getField("age");//权限为默认权限,此时报异常 /* 设置当前属性的值 set() : 参数1:指明设置哪个对象的属性 参数2:将此属性设置为多少 */ id.set(p,1001); /* 获取当前属性值 get() : 参数1:获取哪个对象当前的属性值 */ int pId = (int)id.get(p); System.out.println(pId);//1001 }
/* 如何操作运行时类中的指定的属性---需要掌握 getDeclaredField(String filedName) */ @Test public void testField1() throws Exception { Class class1 = Person.class; //创建运行时类的对象 Person p = (Person) class1.newInstance(); //1、getDeclaredField(String filedName) : 获取指定名的属性 Field name = class1.getDeclaredField("name"); //2、保证当前属性是可以访问的 name.setAccessible(true); //3、获取、设置指定对象的此属性值 name.set(p,"Tom"); System.out.println(name.get(p)); } }
/* 如何操作运行时类中指定的方法 ---需要掌握 */ @Test public void testMethod() throws Exception { Class class1 =Person.class; //创建运行时类的对象 Person p = (Person)class1.newInstance(); /* 1、获取指定的某个方法 getDeclaredMethod() : 参数1:指明获取方法的名称 参数2 : 指明获取方法的形参列表 */ Method show = class1.getDeclaredMethod("show", String.class); //2、保证当前方法是可访问的 show.setAccessible(true); /* 3、调用 invoke() 方法 invoke() : 参数1:方法的调用者 参数2:给方法形参赋值的实参 invoke() 方法的返回值,即使对应类中调用的方法的返回值,若对应的方法没有返回值,则返回 null */ Object returnValue = show.invoke(p, "CHN");//String nation = p.show(); System.out.println(returnValue);//CHN System.out.println("*********************************************"); //如何调用静态方法 //private static void showDesc() Method showDesc = class1.getDeclaredMethod("showDesc"); showDesc.setAccessible(true); showDesc.invoke(Person.class); }
/* 如何调用运行时类中指定的构造器 */ @Test public void testConstructor() throws Exception { Class class1 =Person.class; //private Person(String name) /* 1、获取指定的构造器 getDeclaredConstructor() : 参数:指明构造器的参数列表 */ Constructor constructor = class1.getDeclaredConstructor(String.class); //2、保证此构造器是可访问的 constructor.setAccessible(true); //3、调用此构造器创建运行时类的对象 Person p = (Person) constructor.newInstance("Tom"); System.out.println(p);//Person{name='Tom', age=0, id=0} }
静态代理
/** 静态代理举例 特点:代理类和被代理类在编译期间,就确定下来了 */ interface ClothFactory{ void produceCloth(); } class proxyClothFactory implements ClothFactory{ private ClothFactory factory;//用被代理类对象进行实例化 public proxyClothFactory(ClothFactory factory){ this.factory=factory; } @Override public void produceCloth() { System.out.println("代理工厂做一些准备工作"); factory.produceCloth(); System.out.println("代理工厂做一些后续的收尾工作"); } } //被代理类 class NikeClothFactory implements ClothFactory{ @Override public void produceCloth() { System.out.println("Nike工厂生产一批运动服"); } } public class StaticProxyTest{ public static void main(String[] args) { //创建被代理类对象 NikeClothFactory nike = new NikeClothFactory(); //创建代理类对象 proxyClothFactory proxyClothFactory = new proxyClothFactory(nike); proxyClothFactory.produceCloth(); } }
动态代理
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** 动态代理举例 */ interface Human{ String getBelief(); void eat(String food); } //被代理类 class SuperMan implements Human{ @Override public String getBelief() { return "I believe I can fly!"; } @Override public void eat(String food) { System.out.println("喜欢吃"+food); } } /* 要想实现动态代理:需要解决的问题: 问题一:如何根据加载到内存中的被代理类,动态创建代理类及其对象 问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。 */ class ProxyFactory{ //调用此方法,返回一个代理类的对象,解决问题一 public static Object getProxyInstance(Object obj){//obj :被代理类的对象 MyInvocationHandler handler = new MyInvocationHandler(); handler.bind(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler); } } class MyInvocationHandler implements InvocationHandler { private Object obj;//需要哦使用被代理类的对象进行赋值 public void bind(Object obj){ this.obj=obj; } //当我们通过代理类的对象,第哦啊有方法 a 时,就会自动的调用如下方法:invoke() //将被代理类要执行的方法 a 的功能就声明在 invoke() 中 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法 //obj:被代理类对象 Object returnValue = method.invoke(obj,args); //上述方法的返回值就作为当前类中invoke()的返回值 return returnValue; } } public class ProxyTest { public static void main(String[] args) { SuperMan superMan=new SuperMan(); //proxyInstance : 代理类的对象 Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); //当通过代理类对象调用方法时,会自动调用被代理类中同名的方法 System.out.println(proxyInstance.getBelief()); proxyInstance.eat("糖果"); System.out.println("*************************"); NikeClothFactory nikeClothFactory = new NikeClothFactory(); ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory); proxyClothFactory.produceCloth(); } }