一、反射 动态获取信息以及动态调用对象的方法的功能。能够对任意一个类,获取类的所有属性和方法
三种获取字节码对象方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package 反射联系; public class Main { public static void main(String[] args) throws ClassNotFoundException { //1. Class的方法forName Class clazz1=Class.forName("反射联系.Main"); //需要包.类名 //2. 为类的静态方法 Class clazz2=Main.class; //3. 创建对象调用方法getClass方法 Main m=new Main(); Class clazz3=m.getClass(); System.out.println(clazz1==clazz2);//判断三个是不是相等 System.out.println(clazz3==clazz2); //结果都是true } }
反射(Class.forName(“包.类名”))
榨汁机榨汁的案例 分别有 水果(Fruit) 苹果(Apple) 香蕉(Banana) 桔子(Orange) 榨汁(squeeze)
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 public class Main { public static void main(String[] args) throws Exception { Juicer j=new Juicer();//购买榨汁机 j.run(new Apple()); //榨汁机炸苹果 //j.run(new Orange()x);//Apple a=new Orange(); 类型不匹配 j.run(new Orange()); } } class Apple { public void squeeze() { System.out.println("榨出苹果汁儿"); } } class Orange { public void squeeze() { System.out.println("榨出橘子汁儿"); } } //榨汁机负责榨水果 class Juicer{ public void run(Apple a)//榨苹果 { a.squeeze(); } public void run(Orange o)//榨橘子 { o.squeeze(); } }
但是这种问题就是如果有很多水果就不停的要建立水果类,然后不停的在Juicer类中写出榨水果的run方法比较麻烦,所以我们要考虑使用多态 的方法Fruit实现squeeze()榨汁。
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 public class Main { public static void main(String[] args) throws Exception { Fruit f=new Apple();//多态 -----左父右子 f.squeeze(); } } interface Fruit{ //实现榨汁 public void squeeze(); } class Apple implements Fruit{//所有要用的类实现接口Fruit public void squeeze() { System.out.println("榨出苹果汁儿"); } } class Orange implements Fruit{ public void squeeze() { System.out.println("榨出橘子汁儿"); } } class Juicer{ public void run(Fruit f)//run对象为接口的 f { f.squeeze(); } }
而使用反射 : 主要是添加一个文件名为config.properties(里面写包名.你需要的实现的类名)
1 2 3 4 5 6 7 8 9 10 11 12 public class Main { public static void main(String[] args) throws Exception { //使用反射配置文件 BufferedReader br=new BufferedReader(new FileReader("config.properties"));//字符流 Class c=Class.forName(br.readLine()); //读取一行(\u53CD\u5C04\u8054\u7CFB.Apple) Fruit f=(Fruit)c.newInstance(); //---父类引用指向子类对象 //建立榨汁机对象然后调用run方法run(f) Juicer j=new Juicer(); j.run(f);//执行结果为 榨出苹果汁 } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package 反射联系; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Main2 { public static void main(String[] args) throws Exception{ Class clazz=Class.forName("反射联系.Main");//拿到字节码 //无参构造创建对象 Main m=(Main) clazz.newInstance(); System.out.println(m); Constructor c=clazz.getConstructor(Fruit.class);//获取有参构造 Main m1=(Main) c.newInstance("Apple");//有参构造创建对象 System.out.println(m1); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.lang.reflect.Constructor; public class Main2 { public static void main(String[] args) throws Exception{ Class clazz=Class.forName("反射联系.Main");//拿到字节码 Constructor c=clazz.getConstructor(String.class);//获取有参构造getConstructor Main m1=(Main) c.newInstance("Apple");//有参构造创建对象 //1 共有的public java.lang.reflect.Field f1=clazz.getField("Fruit");//获取姓名字段------getField f1.set(m1,"Orange");//将苹果apple改成orange //2.私有的private java.lang.reflect.Field f2=clazz.getDeclaredField("Fruit");//暴力反射获取姓名字段-----getDeclaredField f2.setAccessible(true); //去除私有private权限 f2.set(m1,"Orange");//将苹果apple改成orange } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class Main3 { public static void main(String[] args) throws Exception{ Class clazz=Class.forName("反射联系.Main");//拿到字节码 Constructor c=clazz.getConstructor(String.class);//获取有参构造getConstructor Main m1=(Main) c.newInstance("Apple");//有参构造创建对象 //无参方法 Method m3=clazz.getMethod("squeeze"); m3.invoke(m3); //有参方法 Method m2=clazz.getMethod("squeeze",int.class); m2.invoke(m2); } }
二、越过泛型检查 泛型只在编译期间有效,运行期(字节码文件)会被擦除掉。
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.lang.reflect.Method; import java.util.ArrayList; public class Main4 { public static void main(String[] args) throws Exception{ ArrayList<Integer> l=new ArrayList<Integer>(); l.add(111); l.add(222); Class c=Class.forName("java.util.ArrayList"); //拿到字节码文件 Method m=c.getMethod("add",Object.class); //更改add方法 m.invoke(l,"abc");调用Method方法的invoke修改方法添加add System.out.println(l); //------>[111, 222, abc] } }
三、指定值(setProperty) public void setProperty(Object o,String qian,Object hou)
:把o对象中名字是qian的属性值—>改成hou
<
HTML
稀疏数组
>