·
耦合度:多个模块之间的关联或者依赖关系(低耦合)
解析类:用于找到字节码对象以产生实例对象的过程----反射 字节码文件就是.class
Class---代表类的类,把类抽取成一个对象,代表的也就是.class的类
Field --------代表属性的类
Method-------代表方法的类
Construct-----代表构造方法的类
Annotation----代表注解的类
Package------代表包的类
类加载器
类加载器负责将.class文件(可能在磁盘上,也可能在网络上)加载到内存种,并为之生成对应的
java.;ang.Class对象。
获取字节码对象的方式
//1.类型.class //获取String的字节码对象 Class<String>clz=String.class; System.out.println(clz); //class java.lang.String //接口的字节码对象 Class<List>clc=List.class; System.out.println(clc); //interface java.util.List //基本类型的字节码对象 Class cla=int.class; System.out.println(cla);//int String str="abc";
//2对象.class 返回的是对象实际创建类的字节码对象 Class<String>clb=(Class<String>) str.getClass();//class java.lang.String System.out.println(clb); Integer i=1; Class<Integer> cld=(Class<Integer>) i.getClass();//class java.lang.Integer System.out.println(cld);
//3.没有类没有对象获取对应的字节码对象 ----Class.forName(全路径名); Class clh=Class.forName("java.utils.Math"); //class java.lang.String //class java.lang.Integer System.out.println(clh);
通过构造器创建实例对象
public class ClassDemo2 { public static void main(String[] args) throws ReflectiveOperationException, IllegalAccessException { //先获取Stirng的字节码对象 Class<String> clz=String.class; //获取实例对象 //newInstance()---默认调用类的无参构造 //String str=clz.newInstance(); //str="abc"; //System.out.println(str); //通过字节码对象调用到String类的有参构造 Constructor c=clz.getConstructor(char[].class);//传入构造方法参数类型的字节码对象,获取到一个构造方法 Constructor c1=clz.getConstructor(String.class); //获取到的有参构造调用newInstance()传入实际参数构造实例对象 String str=(String) c.newInstance(new char[] {'1','4','a'}); String str1=(String)c1.newInstance("dbsb"); System.out.println(str); System.out.println(str1); //根据Integer创建一个对象 //通过Class.forname获取字节码对象 Class<Integer> clz3=(Class<Integer>) Class.forName("java.lang.Integer"); //获取有参构造方法new Integer(int) Constructor c2=clz3.getConstructor(int.class); Integer str2=(Integer) c2.newInstance(123); System.out.println(str2); } }
获取私有或者默认的构造方法
public class ClassDemo3 { public static void main(String[] args) throws ReflectiveOperationException, SecurityException { //获取字节码对象 Class<String> clz=String.class; //获取指定构造方法,忽略访问权限修饰符 //getDeclaredConstructor 和getConstructor区别,前者可以忽略掉构造方法的访问修饰符,尽量都用前者 Constructor c1=clz.getDeclaredConstructor(char[].class,boolean.class); c1.setAccessible(true);//为true就是暴力破解---将原来的构造方法破解成我们可以直接赋值的构造方法 //传参--构建实例对象; String str=(String) c1.newInstance(new char[] {'1','2','3'},true);//直接赋值时不行的,因为访问修饰符你 //不能传值进去,要通过反射的暴力破解特殊的构造方法 } }
获取全部的构造方法
public static void main(String[] args) { Class<String>clz=String.class; //获取字符数组的所有的构造方法 Constructor[] cs=clz.getDeclaredConstructors(); System.out.println(Arrays.toString(cs)); }
获取属性
public class ClassDemo5 { public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { //String 字节码对象 Class<String> clz=String.class; //获取指定属性 Field f=clz.getDeclaredField("hash");//hash属性是私有的 //暴力破解 f.setAccessible(true); //给字符串对象 属性赋值 String str="abc"; //给对象属性赋值 ---给Str对象的hash属性赋值123 f.set(str, 123); //取值 ----获取str对象hash属性的值 System.out.println(f.get(str));//123 //获取String对象所有的属性 Field[] fs=clz.getDeclaredFields(); } }
获取普通方法
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ClassDemo6 { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //获取字节码对象 Class<String>clz=String.class; //获取指定方法 Method m=clz.getDeclaredMethod("charAt",int.class); String string="ndsjknajk"; //调用方法 ---s.charAt(3) char c=(char) m.invoke(string, 3); System.out.println(c);//j //获取全部的方法 Method[] m2=clz.getDeclaredMethods(); } }
反射的缺点:
1.打破了封装原则
2跳过泛型的类型检测
反射跳过泛型检查 @Test public void method() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //创建集合 ArrayList<Integer> list = new ArrayList<>(); //通过对象获取字节码对象 Class<? extends ArrayList> aClass = list.getClass(); //反射获取add () Method method = aClass.getMethod("add", Object.class); method.invoke(list,"mlj"); method.invoke(list, "qq"); method.invoke(list, 'h'); System.out.println(list); //输出 [mlj, qq, h] // 分析:反射直接跳过了泛型Integer,list存储String类型值; // 结论:泛型只是给编译器看的,实际的单列集合,双列集合可以交叉存储任意引用值 }
反射案例: 实现克隆案例
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; //通过反射实现克隆 public class ClassClone { public static void main(String[] args) throws InstantiationException, IllegalAccessException { Person p1=new Person(10,"徐旺骑"); Person p2=(Person) clone(p1); System.out.println(p2.age+p2.name); } //实现Clone方法 public static Object clone(Object obj) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //1.获取字节码对象 Class<Object> clz=(Class<Object>) obj.getClass(); //2.获取实例对象 ---新对象 //2.1获取构造方法---保证一定能拿到构造方法 Constructor c=clz.getDeclaredConstructors()[0]; //返回拿到的这个构造方法上所有的参数类型的字节码对象 Class[] cs =c.getParameterTypes(); //Object的数组,这个是为了给构造方法给值 Object[]os=new Object[cs.length]; //遍历参数数组 for(int i=0;i<cs.length;i++) { //判断参数是否是基本类型 if(cs[i].isPrimitive()) { if(cs[i]==byte.class||cs[i]==short.class||cs[i]==int.class) { os[i]=0; } if(cs[i]==char.class) { os[i]='u0000'; } if(cs[i]==float.class) { os[i]=0.0f; } if(cs[i]==double.class) { os[i]=0.0d; } if(cs[i]==boolean.class) { os[i]=false; } } else { os[i]=null; } } //传值--构造实例对象--新对象 Object o1=c.newInstance(os); //3.获取原对象的所有属性 Field[] fs=clz.getDeclaredFields(); //4.把原对象的属性给新对象 for(Field f:fs) { //暴力破解 f.setAccessible(true); //获取原对象的属性 Object o2=f.get(obj); //原对象的每个属性 //所有属性赋值给新对象 f.set(o1, o2); } //5.返回新对象 return o1; } } class Person{ int age; String name; public Person(int age,String name) { this.age=age; this.name=name; } }
package cn.tedu.reflect; public class ClassDemo6 { public static void main(String[] args) { //枚举类的字节码对象 /* Class<Demo> clz=Demo.class; //返回枚举常量 Demo[] ds=clz.getEnumConstants(); for (Demo demo : ds) { System.out.println(demo); //ABCD }*/ // Class<String> clz=String.class; //没有枚举常量是返回一个null String[] ss=clz.getEnumConstants(); //返回的是实现的接口 Class[] cs=clz.getInterfaces(); for (Class class1 : cs) { System.out.println(class1); //interface java.io.Serializable //interface java.lang.Comparable //interface java.lang.CharSequence } //字节码对象对应类全路径名 System.out.println(clz.getName());//MethodDemo.java //返回字节码对象对应类的包的信息 System.out.println(clz.getPackage());//package java.lang, Java Platform API Specification, version 1.8 //字节码对象对应类的类名 System.out.println(clz.getSimpleName());//String //得到父类的字节码对象 System.out.println(clz.getSuperclass());//class java.lang.Object } } // enum Demo{ A,B,C,D;//枚举常量---对象 }
//获取字节码对象 Class<String> clz=String.class; //可以获取指定属性 Field f=clz.getDeclaredField("serialVersionUID"); //返回属性的数据类型 System.out.println(f.getType()); //long
public class MethodDemo { public static void main(String[] args) throws NoSuchMethodException, SecurityException { // Class<String> clz=String.class; //获取指定方法 /*Method m=clz.getDeclaredMethod ("getBytes", String.class);*/ Method m=clz.getDeclaredMethod ("getBytes", Charset.class); /*//返回的是编译时异常 Class[] cs=m.getExceptionTypes(); for (Class class1 : cs) { System.out.println(class1); }*/ //获取参数类型的字节码放到一个数组 Class[] cs=m.getParameterTypes(); for (Class class1 : cs) { System.out.println(class1); } } }