Programmer Log8[反射]_19.09.02

1.认识反射机制
1.1 反射的“反”指的是根据对象来取得对象的来源信息
1.2 反射的三种方式

import java,util.Date;

public class Test{
    public static void main(String[] args){
        Date date = new Date();
        System.out.println(date.getClass());//通过Class类的getClass()获取Class类对象
    }
}





 public class Test{
      public static void main(String[] args) throws ClassNotFoundException{
          Class<?> cls =Class.forName("java.util.Date");
          System.out.println(cls.getName());
      }
  }


Date.class;//直接获取Class类的实例化对象

1.3 通过反射实例化对象的方法

  public class Test{
      public static void main(String[] args) throws ClassNotFoundException,InstantiationException,IllegalAccessException{
      Class<?> cls = Class.forName("java.util.Date");
      Object obj = cls.newInstance();//创造的是forName中的类的实例
      System.out.pringln(obj);  
      } 
  }

1.4 简单工厂模式
传统工厂类的弊端在于每加一个新的类,就得在工厂里面添加创造它的对象的代码,而用反射实例化对象就很好地避免了这一点。这种模式称为简单工厂模式。

interface IFruit{
    public void eat();
}
class Apple implements IFruit{
    public void eat(){
        System.out.println("吃苹果");
    }
}
class Orange implements IFruit{
    public void eat(){
        System.out.println("吃橘子");
    }
}

class FruitFactory{
    private FruitFactory(){}
    public static IFruit getInstance(String className){
        IFruit fruit = null;
        try{
            fruit = (IFruit)Class.forName(className).newInstance();
        }catch(InstiationException|IllegalAccessException|ClassNotFoundException e){
            e.printStackTrace();
        }
        return fruit;
    }
}
   
public class Test{
    public static void main(String[] args){
        IFruit fruit = FruitFactory.getInstance("com.stay.java.testthread.Orange");
        fruit.eat();
    }
}

2.反射在类中的其他用途
2.1反射取得父类信息
package com.stay.java.testthread;

 interface IFruit;
 interface IMessage;
 class CLS implements IFruit,IMessage{}
 
 public class Test{
     public static void main(String[] args){
         Class<?> cls = CLS.class;//取得class类对象
         System.out.println(cls.getPackage().getName());//取得包名称
         System.out.println(cls.getSuperclass().getName());//取得父类名称
         Class<?>[] iClass = cls.getInterfaces();
         for(Class<?> class1:iClass){
             System.out.println(class1.getName());
         }
      }
 }

2.2 反射调用构造方法

//取得类中所有构造信息
  package com.stay.java.testthread;
  
  import java.lang.reflect.Constructor;
  
  class Person{
      public Person(){}
      public Person(String name){}
      public Person(String name,int age){}
  }
  
  public class Test{
      public static void main(String[] args){
          Class<?> cls = Person.class;
          Constructor<?>[] constructors = cls.getConstructors();
          for(Constructor<?> constructor:constructors){                          
          System.out.println(constructor);
          } 
      }
  }

 class类通过反射实例化对象的时候,只能够调用类中的无参构造。如果类中没有无参构造则无法使用Class类调用,只能通过明确的构造调用实例化处理
package com.stay.java.testthread;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class Person{
    private String name;
    private int age;
    public Person(String name,int age){                                                                             
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Person[name="+name+",age="+age+"]";
    }
}

public class Test{
    public static void main(String[] args)throws InstantiationException,
IllegalAccessException, NoSuchMethodException, SecurityException,
IllegalArgumentException, InvocationTargetException {
    Class<?> cls = Person.class;
    Constructor<?> cons = cls.getConstructor(String.class,int.class);
    System.out.pringln(cons.newInstance("lalala",19));
    }
}

2.3 反射调用普通方法

 //取得一个类中的全部普通方法
    package com.stay.java.testthread;
    
import java.lang.reflect.InvocationTargrtException;
import java.lang.reflect.Method;

class Person{
    private String name;
    private int age;
    public Person(){}
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Person [name=" + name + ", age=" + age + "]";
    }
    public String getName(){
        return name;
    }
    public void setName(){
        this.name = name;
    }
    
    public int getAge(){
        return age;
    }
    
    public void setAge(int age){
        this.age = age;
    }
}

public class Test{
    public static void main(String[] args)throws Exception{
        Class<?> cls = Person.class;'
        Method[] methods = cls.getMethods();
        for(Method nethod : methods){
            System.out.println(method);
        }
    }
}


//通过反射调用方法
public class Test{
    public static void main(String[] args)throws Exception{
        Class<?> cls = Class.forName("com.stay.java.testthread.Person");
        Object obj = cls.newInstance();
        Method setMethod = cls.getMethod("setName",String class);//需要传入方法名和参数
        setMethod.invoke(obj,"lalala");//给对象的属性赋值 invoke方法的参数是要被赋值的属性所属的对象名称和所赋的值
        Method getMethod = cls.getMethod("getName");
        Object result = getMethod.invoke(obj);
        System.out.println(result);
    }
}

2.4 反射调用类中属性

//取得类中全部属性
 package com.stay.java.testthread;
 
 import java.lang.reflect.Field;
 
 class Person{
     public String name;
     public int age;
 }
 class Student extends Person{
     private String school;
 }
 public class Test{
     public static void main(String[] args)throws Exception{
         Class<?> cls = Class.forName("com.stay.java.testthread.Student");
         {
             //第一组-取得类中全部属性(父类中)
             Field[] fields = cls.getFields();
             for(Field field : fields){
                 System.out.println(field);
             }
         }
         System.out.println("------------------------");
         {
             //第二组(本类中)
             Field[] fields = cls.getDeclareFields();
             for(Field field : fields){
                 System.out.println(field);
             }   
         }
     }
 }

2.5 动态设置封装方法

public void setAccessible(boolean flag)throws SecurityException

2.6 getType()方法
此方法用来取得属性类型

package com.stay.java.testthread;

import java.lang.reflect.Field;

class Person{
    private String name;
}

public class Test{
    public static void main(String[] args)throws Exception{
        Class<?> cls = Class.forName("com.stay.java.testthread.Person");
        Object obj = cls.newInstance();
        Field nameField = cls.getDeclareField("name");
        System.out.println(name.Field.getType().getName());
        System.out.println.out.println(name.Field.getType().getSimpleName());
    }
}

3.反射与简单Java类
用反射的方法对对象的属性进行赋值

package com.stay.java.vo;

class Emp{
    private String ename;
    private String job;
    public String getEname(){
        return ename;
    }
 
public void setEname(String ename){
    this.name = ename;
}

public String getJob(){
    return job;
}

public void setJob(String job){
    this.job = job;
}

public String toString(){
    return "Emp{" +"ename='" + ename + '\'' + ", job='" + job + '\'' +'}';
}
}


package com.stay.java.ov;

import com.stay.java.util.BeanOperation;


public class EmpAction extends Emp{
    private Emp emp = new Emp();
    //接收一长串字符串,跳转到拆分方法
    public void setValue(String value) throws Exception{
        BeanOperation.setBeanValue(this,value);
    }
    
    public Emp getEmp(){
        return emp;
    }
}


package com.stay.java.util;
//实现对象与属性值的匹配
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BeanOperation{
    private BeanOperation(){}
    
    //属性的具体内容,格式为:"属性名称:内容|属性名称:内容..."
    //属性名称的格式是对象名.属性名
    public static void setBeanValue(Object actionObject,String msg) throws Exception{
        //按竖线拆分
        String[] result = msg.split("\\|");
        for(int i = 0;i<result.length;i++){//进一步拆分
            String[] temp = result[i].split{":"};
            String attribute = temp[0];//存属性名
            String value = temp[1];//存属性值
            String[] fields = attribute.split("\\.");
            Object currentObject = getObject(actionObject,fields[1]);
            setObjectValue(currentObject,fields[1],temp[1]);
            
        }
        
    }
}

public static Object getObject(Object obj,String attribute) throws
Exception{
String methodName = "get" + initCap(attribute) ;
//field[1]里面存的是属性名称,field[0]里面存的是属性要被赋值的那个对象名称
// 调⽤指定属性的Field对象,⽬的是取得对象类型,如果没有此属性意味着操作⽆法继续进
⾏
Field field = obj.getClass().getDeclaredField(attribute) ;

if (field == null) {
// 第⼆次尝试从⽗类中取得该属性
field = obj.getClass().getField(attribute) ;
}
if (field == null) {
// 两次都未取得指定属性的对象,表示该对象⼀定不存在
return null ;
}
//如果找到了就取出来
Method method = obj.getClass().getMethod(methodName) ;
return method.invoke(obj) ;
}

public static void setObjectValue(Object obj,String attribute,String
value) throws Exception{
Field field = obj.getClass().getDeclaredField(attribute) ;
// 判断属性是否存在
if (field == null) {
// 第⼆次尝试从⽗类中取得该属性
field = obj.getClass().getField(attribute) ;
}
if (field == null) {
// 两次都未取得指定属性的对象,表示该对象⼀定不存在
return ;
}
String methodName = "set" + initCap(attribute) ;
Method setMethod =
obj.getClass().getMethod(methodName,field.getType()) ;
setMethod.invoke(obj,value) ;
}
}

测试类:

package www.bit.java.vo;

public class TestDemo {
public static void main(String[] args) throws Exception {
String value = "emp.ename:yuisama|emp.job:Java Coder" ;
EmpAction empAction = new EmpAction() ;
empAction.setValue(value) ;
System.out.println(empAction.getEmp());
}
}

4.ClassLoader类加载器
Q:什么是类加载器?
A:在JVM中,“通过一个类的全限定类名来获取描述此类的二进制字节流”这个动作放在java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”
如果说现在你的类加载路径可能是网络、文件,这个时候就必须实现类加载器,也就是ClassLoader类的主要作用。
4.1 认识ClassLoader

     public ClassLoader getClassLoader()
class Member{}
public class TestDemo{
    public static void main(String[] args){
        Class<?> cls = Member.class;
        System.out.println(cls.getClassLoader());//结果是sun.misc.Launcher$AppClassLoader@58644d46
        System.out.println(cls.getClassLoader().getParent()) ;//结果是sun.misc.Launcher$ExtClassLoader@6a38e57f
        System.out.println(cls.getClassLoader().getParent().getParent());//结果是null
    }
}

三个类加载器:
Bootstrap(启动类加载器):隶属于虚拟机,无法被Java程序直接引用。其他类加载器都继承java.lang.ClassLoader.BootStrap.这个类主要负责将lib目录下能被虚拟机识别的类库加载到JVM内存中。
ExtClassLoader(扩展类加载器):负责加载lib\ext目录中,或者被java.ext.dirs系统变量指定的路径中的类库。开发者可以直接i使用扩展类加载器。
AppClassLoader(应用程序类加载器):负责加载用户类路径上指定的类库。此加载器是默认类加载器。
4.2 双亲委派模型
所有的类加载器收到了类加载请求的第一个操作是丢给父类加载器去加载,父类加载器找不到类时,会丢回子类加载器,这时子类加载器尝试自己加载
4.3 loadClass()方法

 //首先检查类是否已经被加载
    Class<?> c = findLoadClass(name);
    if(c == null){
        long t0 = System.nanoTime();
        try{
            if(parent != null){
                c = parent.loadClass(name,false);
            }else{
                c = findBootstrapClassOrNull(name);
            }
        }catch(ClassNotFoundException e){
           e.printStackTrace();
        }
    
    if(c == null){
        long t1 = System.nanoTime();
        c = findClass(name);
    }
}

if(resolve){
    resolveClass(c);
} 

5.反射与代理设计模式
5.1 动态代理设计模式
一个代理类可以代理所有需要被代理的接口的子类对象

 public interface InvocationHandler{
     public Object invoke(Object proxy,Method method,Object[] args){
         throws Throwable;
     }
 }

如果要进行对象的绑定,那么就需要一个java.lang.reflect.Proxy程序类。这个程序类的功能是可以绑定所有需要绑定的接口子类对象,而且这些对象都是根据接口自动创建的,该类有一个动态创建绑定对象的方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException

//动态代理设计实现
package www.stay.java.agency

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface ISubject{
    public void eat(String msg,int num);
}
class RealSubject implements ISubject{
    public void eat(String msg,int num){
        System.out.println("我要吃 "+num + "分量的 "+msg) ;
    }
}

//动态代理类
class ProxySubject implements InvacationHandler{
    private Object target;
    
public Object bind(Object target){
    this.target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}

public void preHandle(){
    System.out.println("[ProxySubject] 方法处理前");
}

public void afterHandle(){
    System.out.println("[ProxySubject] 方法处理后");
}

public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
    this.preHandle();
    Object ret = method.invoke(this.target,args);
    this.afterHandle();
    return ret;
}
}

public class TestDemo{
    public static void main(String[] args){
        ISubject subject = (ISubject) new ProxySubject().bind(newRealSubject());
        subject.eat("重庆小面",15);
    }
}

PS:若要离开接口实现动态代理模式,就要依赖第三方组建包CGLIB

6.反射与Annotation
6.1反射取得Annotation信息
与Annotation有关的信息在java.lang.reflect.AccessibleObject类中有定义

//取得定义在类上的Annotation
package com.stay.annotation

import java.io.Serializable;
import java.lang.annotation.Annotation;

@SuppressWarnings("serial")
@Deprecated
class Member implements Serializable{}

public class TestAnnotation{
    public static void main(String[] args){
        Annotation[] ant = Member.class.getAnnotations();
        for(Annotation a:ant){
            System.out.println(a);
        }
    }
}


//获取方法的Annotation

package com.stay.annotation

import java.io.Serializable;
import java.lang.annotation.Annotation;

@SuppressWarnings("serial")
@Deprecated
class Member implements Serializable{
    @Deprecated
    @Override
    public String toString(){
        return super.toString();
    }
}

public class TestAnnotation{
    public static void main(String[] args){
        Annotation[] ant = new Annotation[0];
        try{
            ant = Member.class.getMethod("toString").getAnnotations();
        }catch(NoSuchMethodException e){
            e.printStackTrace();
        }
        for(Annotation a:ant){
            System.out.println(a);
        }
    }
}


6.2 自定义Annotation 首先需要解决的是Annotation的作用范围。不同的Annotation有自己的运行范围,而这些范围就在一个枚举类中定义。

//定义一个在运行时生效的Annotation

    package com.stay.annotation;
    
    import java.io.Serializable;
    import java.lang.annotation.Annotation;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /*
     *自定义一个Annotation名叫MyAnnotation
     */
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation{
        public String name();
        public int age();
        //也可以直接定义默认值
        public String name() default "stay";
        public int age() default 22;
    }
    
    @Deprecated
    @MyAnnotation(name = "stay",age=22)
    class Member implements Serializable{
    }
    
    public class TestAnnotation{
        public static void main(String[] args){
            Annotation[] ant = new Annotation[0];
            ant = Member.class.getAnnotations();
            for(Annotation a:ant){
                System.out.println(a);
            }
        }
    }
    
    
    //获取一个具体Annotation的信息
    package com.stay.annotation;
    
    import java.io.Serializable;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /*
     *自定义一个Annotation名叫MyAnnotation
     */
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation{
        public String name();
        public int age();
        //也可以直接定义默认值
        public String name() default "stay";
        public int age() default 22;
    }
    
    @Deprecated
    @MyAnnotation(name = "stay",age=22)
    class Member implements Serializable{
    }
    public class TestAnnotation{
        public static void main(String[] args){
            MyAnnotation ma = Member.class.getAnnotation(MyAnnotation.class);
            System.out.println("姓名:"+ma.name());
            System.out.println("年龄:"+ma.age());
        }
    }


6.3 Annotation与工厂设计模式

package com.stay.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 *自定义一个Annotation
 *这个Annotation中定义了一个类
 */
 @Retention(RetentionPolicy.RUNTIME)
 @interface MyAnnotation{
     public Class<?> target();
 }
 
 interface IFruit{
     public void eat();
 }
 
 class Apple implements IFruit{
     @Override
     public void eat(){
         System.out.println("吃苹果");
     }
 }
 
 @MyAnnotation(target=Apple.class)//这样使用target和之前使用类就是同一个作用了
 class Factory {
public static <T> T getInstance() throws Exception{
MyAnnotation mt = Factory.class.getAnnotation(MyAnnotation.class) ;
return (T) mt.target().newInstance() ;
}
}
public class TestAnnotation {
public static void main(String[] args) throws Exception{
IFruit fruit = Factory.getInstance() ;
fruit.eat() ;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值