一、 概述
- 集群 : 一组完成同一功能的服务器。
- 解耦: 降低两个功能 不同的模块之间的依赖性
- 高内聚,低耦合: 提高模块内的利用率 , 降低模块之间的依赖性 。
- Class : 一个代表字节码的类 。每个类编译之后都会有相应的字节码 , 所以也叫代表类的类 。
- Package : 代表包的类 。
- Field : 代表属性的类 。
- Method : 代表方法的类 。
- Constructor : 一个代表构造方法的类
- Annotation : 代表注解的类
- 反射: 作用就是剖析一个类 , 分析这个类的字节码 ,产生对应的字节码对象以及实例对象 。
二、应用
获取一个Class对象
- 通过对象的getClass() 方式获取对象的字节码 。
- 通过 类名.class 来获取类对应的字节码 。
- 通过Class.forName(“name”); 获取这个类的字节码对象 , 传入的类名必须是全类名 。
代码:
//获取一个Class对象 。 public class Test_01 { public static void main(String[] args) throws ClassNotFoundException { //只有java虚拟机才有权调用他的构造函数 。 //为什么要把Class的构造函数私有化? //Class -- 代表类的类 , 每一个Class对象应该表示一个具体的类 // Class c = Class();//报错 //获取一个Class对象 //第一种 // 表示获取“abc”所对应的类的字节码 //c代表的就是String类的字节码 Class c = "abc".getClass(); System.out.println(c); //第二种 //c表示Integer类的字节码 Class c1 = Integer.class;//获取类的字节码 Class c2 = List.class;//获取接口的字节码 Class c3 = int[].class;//获取数组的字节码 数组本质上也是一个类 Class c4 = int.class;//获取基本数据类型的字节码 //在java中所有的数据类型都有对应的字节码文件 。 System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); //第三种 //传入类名 , 获取对应的字节码 .因为java中可能存在同名类 , 所以传入的类名必须是全类名 Class c5 = Class.forName("java.util.List"); System.out.println(c5); } } //第三种方式实现解耦 public class Test_02 { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { //解耦 Properties p = new Properties(); p.load(new FileInputStream("config.properties")); Class c = Class.forName(p.getProperty("classname")); } }
java是一门完全面向对象的语言 — 万物皆对象 即使是基本数据类型 , 底层的字节码文件 , 也是一个对象 。
获取一个类的实例对象
//获取一个类的实例对象 public class Test_03 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { //如果添加泛型 , 则表示后续的字节码代表的是泛型的子类或本身 //c 代表的是Object类或Object的子类的字节码对象 Class<Object> c = (Class<Object>) Class.forName("java.lang.Object"); //如何产生一个c所对应的类的实例对象? --- 如何创建一个字符串呢 ? Object o = c.newInstance();//自动调用对应类的构造函数来创建一个实例对象 System.out.println(0); //要求对应的类中必须提供了对应的无参构造 。 // Class c1 = Integer.class; // Integer i = (Integer) c.newInstance(); // System.out.println(i);//报错 //获取构造函数 //获取这个类的构造函数对象 Class<Integer> c1 = Integer.class; //执行这个构造函数 , 传入对应的构造函数 , 产生一个Integer有参对象 Constructor<Integer> con = c1.getConstructor(String.class); Integer oo = con.newInstance("123"); System.out.println(oo); } }
获取指定的构造函数
public class Test_04 { public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<String> c = String.class; //获取对应形式的公共构造函数 Constructor<String> con = c.getConstructor(byte[].class); //执行构造函数 , 创建String实例 String ni = con.newInstance(new byte[]{'a','c','f','f',}); System.out.println(ni); //获取String类中所有的构造函数 //只能获取public 修饰的构造函数 。 Constructor[] cons = c.getConstructors(); for(Constructor conn : cons){ System.out.println(conn); } //获取指定的构造函数 // Constructor<String> con1 = c.getConstructor(char[].class , boolean.class);//报错 这种方法只能获取公有的 , 而这个方法不是公有的函数 //无论共有还是非共有的 , 都能获取到 。 Constructor<String> dcon = c.getDeclaredConstructor(char[].class , boolean.class); //暴力破解 强制执行没有对应权限的方法 dcon.setAccessible(true); //如果没有暴力破解则会报错 非法获取异常 这个方法不是public修饰的而是default修饰 , 没有对应的权限 。 String str = dcon.newInstance(new char[]{'a','b','c'} , true); System.out.println(str); } }
获取成员方法
//获取方法 public class Test_05 { public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class c = String.class; Constructor con = c.getConstructor(String.class); String str = (String) con.newInstance("sdfgdf"); //获取方法 Method m = c.getMethod("charAt", int.class); //执行方法 //第一个参数:执行方法的对象 //第二个参数: 需要执行的方法需要的参数 char cc = (char) m.invoke(str, 0); System.out.println(cc); //获取私有的方法 // str.lastIndexOfSupplementary(1,3);//报错 , 因为该方法是私有的 Method m2 = c.getDeclaredMethod("lastIndexOfSupplementary", int.class,int.class); //私有方法的执行 需要提前暴力破解 m2.setAccessible(true); //执行方法 int i = (int) m2.invoke(str, 2,4); System.out.println(i); //获取方法的返回值类型 Class rc = m.getReturnType(); System.out.println(rc); //获取方法的参数列表 Class[] pt = m.getParameterTypes(); for(Object o :pt){ System.out.println(o); } //获取方法抛出的异常 Class[] et = m.getExceptionTypes(); for(Object o :et){ System.out.println(o); } //判断是否有可变参数 System.out.println(m.isVarArgs()); //获取方法名 System.out.println(m.getName()); } }
获取属性 , 设置属性
//获取属性 , 设置属性 public class Test_06 { public static void main(String[] args) throws Exception { Class c = String.class; //获取指定属性 Field df = c.getDeclaredField("hash"); System.out.println(df); //获取属性的值 String str = "sdf"; //暴力破解 df.setAccessible(true); System.out.println(df.get(str)); //设置属性的值 df.set(str, 234); System.out.println(df.get(str)); //获取声明类型 System.out.println(df.getType()); } }
获取类的信息
//获取这个类的信息 public class Test_07 { @SuppressWarnings({ "unchecked", "rawtypes" }) public static void main(String[] args) { Class<String> c = String.class; //获取所有实现接口 Class<String>[] interfaces = (Class<String>[]) c.getInterfaces(); for(Class cc : interfaces){ System.out.println(cc); } //获取类的全路径名 --- 包名+类名 //toString() 底层 getClass().getName+"@"+hashcode() System.out.println(c.getName()); //[获取所在包 System.out.println(c.getPackage()); //只获取类名 System.out.println(c.getSimpleName()); //获取父类 System.out.println(c.getSuperclass()); //判断是否是一个注解类型 System.out.println(c.isAnnotation()); //判断是否是一个匿名内部类 System.out.println(c.isAnonymousClass()); //判断是否是一个数组 System.out.println(c.isArray()); //判断是否是一个枚举 System.out.println(c.isEnum()); //判断传入的对象类型是否是本字节码对象的实例 System.out.println(c.isInstance("afdsfd")); //判断是否是一个接口 System.out.println(c.isInterface()); //判断是否是一个方法内部类 System.out.println(c.isLocalClass()); //判断是否是一个成员内部类 System.out.println(c.isMemberClass()); //判断是否是一个基本类型 System.out.println(c.isPrimitive()); //判断参数类型是否是本字节码对象的子类|接口 System.out.println(c.isAssignableFrom(String.class)); } }
练习 : 实现数据与代码解耦
//练习 /* * 接口Person 接口中方法: eat()吃 , work()工作 , tax()缴税 * 医生类实现Person 属性:名字name 、 年龄age 、 性别gender 、 工资salary 、 入职日期date * 方法:所有属性的get、set方法 、 eat(){name + 在手术室吃饭} , work(){治病救人} , tax(){工资*0.5} * 教师类 实现Person 属性: 名字name 、 年龄age 、 性别gender 、 工资salary 、 入职日期date * 方法: 所有属性的get、set方法 、 eat(){name + 在教室吃饭} , work(){教书育人} , tax(){工资*0.5} * config.properties文件中: * classname = 教师|医生 * attrname = name/age/gender/entry * attrvalue = Amy/50/\u5973/2010-10-10 * mothename = work * */ public class Test_08 { @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { //读取配置文件 Properties p = new Properties(); p.load(new FileInputStream("src/com/tj/tedufanshe/config.properties")); String classname = p.getProperty("classname"); String attrname = p.getProperty("attrname"); String attrvalue = p.getProperty("attrvalue"); String methodname = p.getProperty("methodname"); //创建类的字节码对象 Class<Person> clz = (Class<Person>) Class.forName(classname); //创建字节码对象对应的实例对象 Person per = clz.newInstance(); //获取要操作的属性名 String[] attrnames = attrname.split("/"); //获取属性值 String[] attrvalues = attrvalue.split("/"); //遍历属性名数组 for(int i = 0 ; i<attrnames.length ;i++){ //获取属性名对应的属性 Field f = clz.getDeclaredField(attrnames[i]); //获取属性的省名类型 Class<?> ft = f.getType(); //获取属性对应的set方法的名 String name = "set"+attrnames[i].substring(0,1).toUpperCase()+attrnames[i].substring(1,attrnames[i].length()); //获取对应的set方法 Method m = clz.getMethod(name, ft); //判断属性值的类型, 然后转化为对应的类型 System.out.println(attrvalues[i]); if(ft == int.class ||ft.equals(Integer.class)){ m.invoke(per, Integer.parseInt(attrvalues[i].trim())); }else if(ft == char.class || ft.equals(Character.class)){ m.invoke(per, attrvalues[i].toCharArray()[0]); }else if(ft == Date.class ){ m.invoke(per, new SimpleDateFormat("yyyy-MM-dd").parse(attrvalues[i].trim())); }else{ m.invoke(per, attrvalues[i] ); } } //执行指定的方法 Method m2 = clz.getMethod(methodname); m2.invoke(per); } } interface Person{ void eat(); void work(); void tax(); } class Teacher implements Person{ private String name ; private int age; private char gender; private int salary; private Date entry; @Override public void eat() { System.out.println(name+"老师正在教师吃粉笔"); } @Override public void work() { System.out.println("教书育人"); } @Override public void tax() { System.out.println("缴税"+salary*0.5); } public Teacher() { } public Teacher(String name, int age, char gender, int salary, Date entry) { super(); this.name = name; this.age = age; this.gender = gender; this.salary = salary; this.entry = entry; } 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 char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public Date getEntry() { return entry; } public void setEntry(Date entry) { this.entry = entry; } } class Dectory implements Person{ private String name ; private int age; private char gender; private int salary; private Date entry; @Override public void eat() { System.out.println(name+"医生正在手术室吃大腿"); } @Override public void work() { System.out.println("治病救人"); } @Override public void tax() { System.out.println("缴税"+salary*0.5); } public Dectory() { } public Dectory(String name, int age, char gender, int salary, Date entry) { super(); this.name = name; this.age = age; this.gender = gender; this.salary = salary; this.entry = entry; } 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 char getGender() { return gender; } public void setGender(char gender) { this.gender = gender; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public Date getEntry() { return entry; } public void setEntry(Date entry) { this.entry = entry; } }