反射定义
反射:(运行时发现和使用类的信息)指的是对象的反向处理。根据对象倒推类的组成。(比如根据汽车倒退他的设计图纸,通过,可以拿到零件,并更换零件)
反射的核心类class类(专门描述其他类的组成)
Object类中的取得对象的Class对象
public final native Class<?> getClass();
class类描述接口与类的组成,Class对象由JVM在第一次加载类时产生,并且全局唯一。
1.三种取得任意类Class对象的方法
-
I.调用对象.getClass()取得Class对象
-
II. 类名称.class取得Class对象
-
III.Class.forName(类全称)
1.1 public T newInstance():通过反射实例化类对象
synchronized(Test.class){
//全局锁
//通过类.class (全局唯一)
}
Class<Date> cls = Data.class;
Date date = cls.newInstance();通过反射实例化对象
1.2 反射与工厂方法模式
反射与工场方法模式
工厂方法模式:
一个接口, 多个实现子类 , 一个工厂,
通过客户端传入的name来判断要生产神魔,当添加子类时,
在工厂中需要添加新增的类的判断,(这正是他的弊端)
使用反射的工场方法模式: 当有 新的子类产生时,不用修改工场
通过想工厂中传入 类名.class Class对象 ,就可以不论是那个类,都可以通过反射产生新对象
interface Computer{
void buy();
}
class DellComputer implements Computer{
@Override
public void buy() {
System.out.println("买一个戴尔笔记本");
}
}
class HUAWEIComputer implements Computer{
@Override
public void buy() {
System.out.println("买个华为笔记本");
}
}
class LenovoComputer implements Computer{
@Override
public void buy() {
System.out.println("买一个联想笔记本呢");
}
}
class ComputerFactory{
public Computer buyComputer(Class<?> cls) throws IllegalAccessException, InstantiationException {
return (Computer) cls.newInstance();
}
}
public class FactoryMethod2 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
ComputerFactory computerFactory = new ComputerFactory();
Computer computer = computerFactory.buyComputer(HUAWEIComputer.class);
computer.buy();
}
}
2.反射与类操作
2.1取得父类&父接口信息
-
I.取得包信息- Package(描述包信息的类)
public Package getPackage();
-
II.取得父类的Class对象
getSuperClass() Class<? super T>
-
III.取得实现的父接口Class对象
getInterfaces() : Class<?>[]
2.2反射与构造方法 - Constructor(描述类的构造方法信息)
-
I.取得本类中指定参数的构造方法
getConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,权限为public。 getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数
-
II.取得本类中所有构造方法
getConstructors() 返回包含一个数组 Constructor对象,取得权限为public的 getDeclaredConstructors() 返回一个反映 Constructor对象,取得所有的构造方法
Class类的newInstance()实际上调用的是类中的无参构造,如果类中没有无参构造或者权限为private,此方法无法使用!!!!
2.3 Constructor类中的方法(调用有参构造的.class)
public T newInstructce(Object ... initargs);
若类中没有无参构造,则只能使用Constructor类提供的newInStance方法使用有参构造
2.4 普通方法
2.4.1 取得指定名称的方法
getMethod(String name, 类<?>... parameterTypes)
返回一个 方法对象,权限为public修饰。
getDeclaredMethod(String name, 类<?>... parameterTypes)
返回一个 方法对象,所有方法,不考虑修饰符。
2.4.2 取得所有方法
1. public Method[] getMethods() throws SecurityException :
取得本类以及父类所有权限为public的普通方法(public,包含静态方法)
2. public Method[] getDeclaredMethods() throws SecurutyException
只能取得本类中的的所有方法(包含private)
2.4.3 Method类 - 提供的方法(重要)
反射调用普通方法
obj:类的实例化对象
args:普通方法参数
通过对象调用:参数不同则方法的执行结果不同,所以要找到对象
public Object invoke(Object obj,Object …args);
2.5 普通属性
2.5.1 取得类中指定名称的属性
public Field getField(String name)
public Field getDeclaredField(String name)
2.5.2 取得类中所有属性
找本类与父类中所有public权限的属性:public Field[] getFields() throws SecurityException
只找本类中的所有属性:public Field[] getDeclaredFields() throws SecurityException
2.5.3 Filed类 - 提供的设置和取得值(重要)
obj:obj的实例化对象
value:要设置的值
public void set(Object obj,Object vlaue);
//取得属性值
public Object get(Object obj){
}
//取得属性类型
public Class<?> getType();
代码:
interface IA{}
interface IB{}
class SuperC{}
class SubD extends SuperC implements IA,IB {
private String name;
public int age;
public SubD(){
}
public SubD(String name){
this.name = name;
}
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;
}
}
/**
* Class类中的方法
*
*/
public class Reflex_Parents {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//1. 基本方法
Class<SubD> cls = SubD.class;
System.out.println("getPackage = "+cls.getPackage());//获取包名
System.out.println("getSuperclass ="+cls.getSuperclass());//父类全名称
System.out.println("getInterfaces = "+cls.getInterfaces());//接口数组
Class<SubD>[] clsInterfaces= (Class<SubD>[]) cls.getInterfaces();
for(Class<SubD> d: clsInterfaces){
System.out.println(d);
}
System.out.println("getTypeName = "+cls.getTypeName());//本类包名
//2. 构造方法
//调用无参构造
Class<SubD> cls2 = SubD.class;
cls.newInstance(); //默认调用无参构造 -> 所以无参构造不能是private修饰
//调用有参构造
Constructor<SubD> constructor = cls.getConstructor(String.class);//指定参数类型
SubD subD= constructor.newInstance("zhanga");
//3. 重点):反射调用普通方法;
//通过cls.getMethod(方法名称,参数类型.class)方法获取到方法的对象
/*
1. public Method[] getMethods() throws SecurityException :4
取得本类以及父类所有权限为public的普通方法(public,包含静态方法)
2. public Method[] getDeclaredMethods() throws SecurutyException
只能取得本类中的的所有方法(包含private)
*/
Class<SubD> cls3 = SubD.class;
Method setName = cls.getMethod("setName",String.class);
Method getName = cls.getMethod("getName");
SubD ret = cls.newInstance();
setName.invoke(ret,"zhang");
System.out.println(getName.invoke(ret));
//4.调用类中的属性
/*
2.4.1 取得类中指定名称的属性
public Field getField(String name)
public Field getDeclaredField(String name)
2.4.2 取得类中所有属性
找本类与父类中所有public权限的属性:public Field[] getFields() throws SecurityException
只找本类中的所有属性:public Field[] getDeclaredFields() throws SecurityException
*/
Class<SubD> cls4 = SubD.class;
SubD subD1= cls.newInstance();
Field field = cls.getDeclaredField("name");
field.setAccessible(true);
field.set(subD1,"zhag");
System.out.println(field.get(subD1));
// 5.破坏封装
/*
Field field = cls.getDeclaredField("name");
field.setAccessible(true);
*/
Class<SubD> cls5 = SubD.class;
SubD subD5= cls.newInstance();
Field field5 = cls.getDeclaredField("name");
field.setAccessible(true);
field.set(subD5,"zhag");
System.out.println(field.get(subD5));
}
}
动态破坏封装(反射特性) - 在一次JVM进程中
Constructor,Method,Field类都继承AccessibleObject类,
此类中有一个破坏封装的方法
public class BrackPackage {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<Child> cls = Child.class;
//1.创建一个Field对象
Field field = cls.getDeclaredField("age");
Child ch = cls.newInstance();
//调用属性的setAccessible方法
field.setAccessible(true);
field.set(ch,20);
System.out.println(field.get(ch));
}
}
public void setAccessible(bollean flag);
(重点)反射与单极VO操作
输入字符串“属性名称:属性值|属性名称:属性值|属性名称:属性值”
BeanOpenation类
public class BeanOpenation {
public static void setBeanValue(Object actionObj,String msg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
String[] ret = msg.split("\\|");
//emp.name:zhang emp.job:programmer
for(int i = 0; i< ret.length; i++){
String[] temp = ret[i].split(":");
//emp.name zhang
String attritube = temp[0];
String value = temp[1];//值
String[] filed = attritube.split("\\.");//属性类名.属性名
//获取当前对象emp name
Object curObj = getObject(actionObj,filed[0]);
//name
setObject(curObj,filed[1],value);
}
}
private static void setObject(Object curObj, String s, String value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
//返回的是一个emp对象,要调用Emp类中的"set"+"Name/Job"方法设置值
//首先还是要判断属性存不存在
Field field = curObj.getClass().getDeclaredField(s);
if(field == null){
field = curObj.getClass().getField(s);
}
if(field == null){
return ;
}
//获取到当前类中的方法,并调用该方法设置值
String methodName = "set"+initCap(s);//setName
Method method = curObj.getClass().getDeclaredMethod(methodName,field.getType());
method.invoke(curObj,value);
}
public static String initCap(String s){
return s.substring(0,1).toUpperCase()+s.substring(1);
}
private static Object getObject(Object actionObj, String s) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
//emp
String ret = "get"+initCap(s);//getEmp
//判断是否由emp属性
Field field = actionObj.getClass().getDeclaredField(s);
if(field == null){
//从父类中获取这个属性
field = actionObj.getClass().getField(s);
}
if(field ==null){
return null;
}
//使用getEmp方法对象
Method method = actionObj.getClass().getDeclaredMethod(ret);
return method.invoke(actionObj);//当前的对象调用getEmp返回一个emp对象
}
}
EmpAction类
public class EmpAction {
private Emp emp = new Emp();
public void setValue(String value) throws InvocationTargetException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
BeanOpenation.setBeanValue(this,value);
}
public Emp getEmp(){
return emp;
}
}
Emp类
public class Emp {
private String name;
private String job;
public Emp(){
}
public Emp(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Emp ="+"{ name: "+this.name+ " "+"job: "+this.job+" }";
}
}
反射与简单java类
3.ClassLoader类加载器
3.1定义:
类加载定义:通过一个类的全名称来获取此类的二进制字节流
类加载器: 实现类加载功能的代码模块;
3.2JDK内置的三大类加载器
3.2.1:BootStrap(启动类加载器)
I.独立于JVM外部,并且无法被Java程序直接引用。
II.负责将存放于JAVA_HOME/lib目录下的能被识别的所有类库加载到JVM中
能被JVM识别的所有的类库(例如rt.jar - java基础类库)加载到JVM中。
jar文件 = 压缩文件 - 存放编译好的若干个class文件
3.2.2ExtClassLoader(扩展类加载器)
I.使用java语言实现,可以被java程序直接引用的
II.负责将存于JAVA_HOME\lib\ext(Xml文件解析类,页面框架类)
目录下的所有能被JVM识别的类库。
3.2.3 AppClassLoader(应用程序加载器)
I.使用JAVA程序实现,如果用户没有自定义类加载器
II.负责加载用户classPath指定的类库
3.3(重点)类加载器的双亲委派模型(定义,工作流程,存在意义)
定义:四种类加载器的层次关系
工作流程:
如果一个类加载器收到一个类加载请求,首先自己不会加载此类,而是将类加载请求委托给父类加载器完成,每层的类加载器都是如此,只用当夫类加载器无法加载此类时,子加载器才会尝试自己去加载。
存在意义:
双亲委派模型对于保证JAVA程序的稳定运行十分重要。
例如:java.lang.Object,存放在rt.jar中,由于双亲委派模型的存在,无论哪一类累加载器要加载此类,最终都是委派给处于顶端的启动类加载器进行加载,因此,Object类在程序的各种类加载器环境中都是一个类
比较两个类是否是相等的前提条件:这两个类是由同一个类加载器加载的,
否则即使两个类来源与同一个Class文件,被同一个JVM加载,
只要加载这两个类的类加载器不同,这两个类的注定不相等。