后续课程!!!!!!!
maven
SSH:struts+spring+hibernate
微信公众号接口开发
个人项目:物业微信公众号
SSM:spring+springmvc+mybatis
物业管理系统
补充:
shiro:权限认证
redis
git
springboot
springcloud
反射
一.概念
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象,都能够访问它的任意一个方法和属性
这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制
类中有什么信息 ,利用反射就能够获取,不过前提是知道这个类的名字(全称)
想要解刨一个类,必须先获取类的字节码文件对象
而解刨使用的就是Class类中的方法,所以先获取到每个字节码文件对应的Class类型的对象.
Class一个类,封装了当前对象所对应的类的信息(属性,方法)
在程序运行期间,一个类,只有一个Class对象产生
二.获取Class类对象的三种方式
1.对象名.getClass()
2.通过类型.class
3.Class.forName(包名.类名)
案例
1、Student类
package com.po; public class Student { private String name; private int 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; } }
package com.demo; import com.po.Student; public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { //第一种 Student s=new Student(); Class c=s.getClass(); System.out.println(c.getName()); //第二种 Class c2=Student.class; System.out.println(c2.getName()); //第三种 Class c3=Class.forName("com.po.Student"); System.out.println(c3.getName()); System.out.println(c2==c3); } }
三.反射访问构造方法
1、Student类
public Student(){ } public Student(String name,int age){ this.name = name; this.age = age; } private Student(String name){ this.name = name; }
package com.demo; import java.lang.reflect.Constructor; import com.po.Student; public class Demo2 { public static void main(String[] args) throws Exception { Class c=Class.forName("com.po.Student"); //获取所有的构造方法 Constructor[] cons=c.getDeclaredConstructors(); for (Constructor constructor : cons) { System.out.println(constructor); } //无参构造方法 Constructor constructor=c.getConstructor(); Student s=(Student)constructor.newInstance(); System.out.println(s.getStuNo()+s.getStuName()); //有参数的构造方法 Constructor constructor2= c.getConstructor(int.class,String.class); Student s2=(Student)constructor2.newInstance(1,"张三"); System.out.println(s2.getStuNo()+s2.getStuName()); } }
四.反射 访问公共属性
package com.demo; import java.lang.reflect.Field; import com.po.Student; public class Demo3 { public static void main(String[] args) throws Exception { //获取Student的字节码文件 Class c=Student.class; //获取所以公共的属性 Field[] fields2=c.getDeclaredFields(); for(Field filed:fields2){ System.out.println(filed); } //根据类中的属性名称,获取特定的某个属性 Field stuNo=c.getDeclaredField("stuNo"); Field stuName=c.getDeclaredField("stuName"); //为属性赋值 //如果成员权限的属性石private,需要用下面的代码来解除私有权限的规则,否则抛异常 Student s=(Student)c.newInstance();//通过反射创建Student对象,注意:学生类中必须有一个不带参的的构造方法 stuNo.setAccessible(true); stuName.setAccessible(true); //为成员变量赋值, stuNo.set(s, 1); stuName.set(s, "张三"); System.out.println(s.getStuNo()+s.getStuName()); } }
五.反射 访问成员方法
1、Student类
新增两个方法
public void ceshi(){ System.out.println("ceshi........"); } public int add(int a,int b){ return a+b; }
package com.demo; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import com.po.Student; public class Demo4 { public static void main(String[] args) throws Exception { Class c=Student.class; Method[] methods=c.getMethods(); for (Method method : methods) { System.out.println(method); } Method method=c.getMethod("ceshi"); //执行方法 Student s=(Student)c.newInstance();//反射创建对象 Object result=method.invoke(s);//执行方法,此方法的所属对象 System.out.println(result); System.out.println("--------------------------------"); //执行有参数的方法 第一个参数:方法名称,后面的参数:方法参数的类型列表 Method method2=c.getMethod("add", int.class,int.class); //第一个参数:方法所属的对象,后面的参数:方法的参数值列表,顺序和上面的类型顺序要一一对应 Object result2=method2.invoke(s, 3,5); System.out.println(result2); } }
六.设计模式-工厂模式
23种
工厂用来创建对象的,需要一个student对象,通过工厂创建一个student对象
案例,动物工厂案例
接口类
package com.factory; public interface Animal { void eat();//吃 }
package com.factory; public class AnimalFactory { public static Animal getInstance(String name) throws Exception{ // if("dog".equals(name)){ // return new Dog(); // } // if("cat".equals(name)){ // return new Cat(); // } //利用反射创建动物对象 Class c=Class.forName(name); Animal animal=(Animal)c.newInstance(); return animal; } }
package com.factory; public class Cat implements Animal{ @Override public void eat() { System.out.println("cat.. eat"); } }
package com.factory; public class Dog implements Animal{ @Override public void eat() { System.out.println("dog...eat"); } }
package com.factory; public class cehsi { public static void main(String[] args) throws Exception { // Animal animal=AnimalFactory.getInstance("cat"); // animal.eat(); Animal animal=AnimalFactory.getInstance("com.factory.Cat"); animal.eat(); } }
此时的效果,就是我们在测试类中,传入”cat”时,Animal是Cat类型对象,传入“dog”时,Animal是Dog类型对象;
当我们的Animal接口有其他的动物实现类时,我们就需要在AnimalFactory工厂类的getInstance()方法中新增其他动物对象的分支语句及创建对象;显然不合理,此时我们可以在工厂类中使用反射的方式创建对象,这样不管Animal有多少实现类,只需要传入相应类型,即可创建对象
6、优化
AnimalFactory类修改
//根据传递的名称,创建不同的动物对象 public static Animal getInstance(String name) throws Exception{ /*if("dog".equals(name)){ return new Dog(); } if("cat".equals(name)){ return new Cat(); }*/ //利用反射,创建动物对象 Class c = Class.forName(name); Animal animal = (Animal) c.newInstance(); return animal; }
测试类
public static void main(String[] args) throws Exception { //Animal animal = AnimalFactory.getInstance("cat"); //animal.eat(); //传入类的全称 Animal animal = AnimalFactory.getInstance("com.factory.Cat"); animal.eat(); }
最终我们的效果,就是只需修改传入的参数,就能创建不同类型的Animal对象
补充:其实这里的测试类中传入的类全称,我们每次还是需要更改源代码,才能生效,最好的方式可以把类全称配置到特定的配置文件中,如xml、properties等文件,我们代码中只需读取配置文件,即可灵活的控制对象的产生
七、结论
重点掌握反射的概念以及操作类的属性和方法;
通过反射,只需要获取到类的Class字节码类型对象,我们就能很好的操作类的对象创建、属性的赋值、方法的调用;
反射要导的包
import java.lang.reflect.