java反射

什么是反射:
反射就是类的解析,通过解析类,来获取该类的信息,比如成员变量(Field)、方法(Method)、构造方法(Constructor)、修饰符等。反射在框架中将会用的比较多。
万事万物皆对象。
一个类本身也是是对象,它是Java.lang.Class的对象。
一、Class类的使用
1、如何得到各个字节码对应的示例对象(Class类型)
*类名.class(),例如system.class
*对象.getClass.例如Person p = new Person();Class cls = p.getClass;(已知一个类的对象)
*Class.forName(“类名”),例如:Class.forName(“java.util.Date()”)

package reflect;
public class ReflectDemo1 {
    public static void main(String[] args) {
      //第一种方式
      Class fo1 = Foo.class;
      //第二种方式
      Foo f = new Foo();
      Class fol2 = f.getClass();
      //第三种方式
      Class fol3 = null;
      try {
         fol3 = Class.forName("reflect.Foo");
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
      Foo f1 = null;
     try {
        //通过类类型(ClssType)来定义对象
        f1 = (Foo)fol3.newInstance();
        f1.print();
    } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }
}
class Foo{
    void print(){
        System.out.println("foo");
    }   
}

2、Class.forName(“类全称”)
不仅代表了类类型,还代表了动态加载类。

二、动态加载类
编译时刻加载类是静态加载类,运行时刻加载类是动态加载类。
1、静态加载
java里面new创建对象静态加载类,在编译时刻就需要加载所有可能用到的类。
2、动态加载
看一个静态加载的例子

package reflect;

public class Office {

    /**
     * 静态加载
     */
    public static void main(String[] args) {
   if("Word".equals(args[0])){
       Word word = new Word();
       word.start();
   }
   if("Excel".equals(args[0])){
       Excel excel = new Excel();
               excel.start();
   }

    }

}
class Excel{
    void start(){
        System.out.println("excel...start");
    }
}
class Word{
    void start(){
        System.out.println("word...start");
    }
}

如果Excel和Word类只要有一个不存在,编译将会出现异常。如果动态加载则避免这一状况发生。
动态加载:

interface  OfficeAble {

    public void start();

}
class Excel implements OfficeAble{
    public void start(){
        System.out.println("excel...start");
    }
}
class Word implements OfficeAble{
    public  void start(){
        System.out.println("word...start");
    }
}
public class OfficeBetter {

    /**
     * 动态加载
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
     try {
        Class c = Class.forName(args[0]);
        OfficeAble oa = (OfficeAble)c.newInstance();
        oa.start();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    }

}

三、获取方法信息
1、基本数据类型和void都存在类类型。
2、getName()和getSimpleName();
getName返回的是类类型的全称;
getSimpleName返回的是类类型的名称。

 Class classString = String.class;
    System.out.println(classString.getName());
    System.out.println(classString.getSimpleName());

结果

java.lang.String
String

3、需求:写一个工具,解析该类的所有方法:包括返回值,函数名,参数信息

package reflect;
import java.lang.reflect.*;
public class utils {
    static void printClassMessage(Object obj){
      Class c = obj.getClass();
      //获取方法名
      Method[] methods = c.getMethods();
      for(int i =0;i<methods.length;i++){
          //获取方法的返回值
          Class returnType = methods[i].getReturnType();
          System.out.print(returnType.getSimpleName()+" ");
          //获取方法的方法名
          String methodName = methods[i].getName();
          System.out.print(methodName+"(");
          //获取参数信息
          Class<?>[] paramTypes = methods[i].getParameterTypes();
          int length = paramTypes.length;
            for (int j = 0; j < length; j++) {
                if (j == length - 1) {
                    System.out.print(paramTypes[j].getSimpleName());
                    break;
                }
                System.out.print(paramTypes[j].getSimpleName() + ",");
            }
            System.out.println(")");
      }

   }

}

结果:

int hashCode()
boolean equals(Object)
String toString()
char charAt(int)
int codePointAt(int)
int codePointBefore(int)
int codePointCount(int,int)
int compareTo(Object)
int compareTo(String)
int compareToIgnoreCase(String)
String concat(String)
boolean contains(CharSequence)
boolean contentEquals(CharSequence)
boolean contentEquals(StringBuffer)
String copyValueOf(char[],int,int)
String copyValueOf(char[])
boolean endsWith(String)
boolean equalsIgnoreCase(String)
String format(Locale,String,Object[])
String format(String,Object[])
byte[] getBytes(Charset)
byte[] getBytes(String)
void getBytes(int,int,byte[],int)
byte[] getBytes()
void getChars(int,int,char[],int)
int indexOf(String)
int indexOf(int,int)
int indexOf(int)
int indexOf(String,int)
String intern()
boolean isEmpty()
int lastIndexOf(int)
int lastIndexOf(int,int)
int lastIndexOf(String)
int lastIndexOf(String,int)
int length()
boolean matches(String)
int offsetByCodePoints(int,int)
boolean regionMatches(int,String,int,int)
boolean regionMatches(boolean,int,String,int,int)
String replace(char,char)
String replace(CharSequence,CharSequence)
String replaceAll(String,String)
String replaceFirst(String,String)
String[] split(String)
String[] split(String,int)
boolean startsWith(String)
boolean startsWith(String,int)
CharSequence subSequence(int,int)
String substring(int,int)
String substring(int)
char[] toCharArray()
String toLowerCase(Locale)
String toLowerCase()
String toUpperCase()
String toUpperCase(Locale)
String trim()
String valueOf(double)
String valueOf(long)
String valueOf(float)
String valueOf(char)
String valueOf(boolean)
String valueOf(int)
String valueOf(Object)
String valueOf(char[],int,int)
String valueOf(char[])
Class getClass()
void notify()
void notifyAll()
void wait(long)
void wait(long,int)
void wait()

四、获取成员变量、构造函数信息
1、成员变量
成员变量也是对象,用Field封装其信息
getFileds方法获得是所有public类型的成员变量信息
getDeclaredFileds方法获得是该类自己声明的成员变量的信息

    public static void getConstructorMessage(Object obj) {
        Class c = obj.getClass();
        // 获得构造函数信息
        Constructor[] cs = c.getDeclaredConstructors();
        for (int i = 0; i < cs.length; i++) {
            System.out.print(cs[i].getName() + "(");
            Class[] paramTypes = cs[i].getParameterTypes();// 获取构造方法的参数类类型
            int length = paramTypes.length;
            for (int j = 0; j < length; j++) {
                if (j == length - 1) {
                    System.out.print(paramTypes[j].getSimpleName());
                    break;
                }
                System.out.print(paramTypes[j].getSimpleName() + ",");
            }
            System.out.println(")");
        }
    }

五、方法反射的基本操作
(1)如何获取某个方法:方法的名称和方法的参数列表才能唯一决定某个方法
(2)方法反射的操作
method.invoke(类对象,参数列表):

简单步骤
1、要获取一个方法,就是要获取类信息,获取类信息首先要获取类类型
2、获取方法,有方法名和参数列表决定m = c.getMethod(方法 名,参数列表);
3、方法的反射操作
m.invoke(对象,new Class[]{int.class,int.calss});方法如果没有返回值,值返回null,如果有返回值,则返回Object类型。

package reflect;
import java.lang.reflect.*;
public class ClassDemo3 {

    public static void main(String[] args) {
     B b = new B();
     Class  c = b.getClass();
     Method m = null;
     Method m1 = null;
     Method m2 = null;
    try {
        m = c.getMethod("print", int.class,int.class);
        m1 = c.getMethod("print", String.class,String.class);
        m2 = c.getMethod("print");
        Object o = m.invoke(b,1,2);
        o= m1.invoke(b, "aaa","bbb");
        o= m2.invoke(b);
    } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }  catch (IllegalAccessException e) {
        // TODO Auto-ged nerated catch block
        e.printStackTrace();

    } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    }

}
class B{
     public void print(int a,int b){
         System.out.println(a+b);
     }
     public void print(String a,String b){
         System.out.println(a+b);
     }
     public void print(){
         System.out.println("hi ,reflect");
     }
}

结果

3
aaabbb
hi ,reflect

b.print()调用和m.invoke(对象,参数列表)效果完全相同。
六、通过反射了解集合泛型的本质
首先明确几点:
1‘反射都是编译之后的操作,也就是说反射出现在运行时期
2、编译之后集合的泛型是去泛型化的,也就是说泛型实际上是防止错误输入的,集合的泛型只在编译阶段有效,绕过编译就无效了。
示例:

import java.util.*;

public class ClassDemo4 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        ArrayList<String> list1 = new ArrayList();
        Class c1 = list.getClass();
        Class c2 = list1.getClass();
        System.out.println(c1==c2);
    }
}

结果

true

说明编译之后的集合泛型去泛型化的,泛型已经失去了作用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值