反射

Class类

在面向对象中,万物皆对象,类也是对象,类是java.lang.Class的实例对象。

 

反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

反射机制的功能

 

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理。

 

获取Class对象的三种方法

 

//定义一个Class对象
class fanshe{
    
    void print(){
        System.out.println("fanshe");
    }
}

 

第一种方法(已经知道该类的对象通过getClass方法获取对象,换句话说,需要创造类的对象)

fanshe Object = new fanshe();

Class c1 = Object.getClass();

第二种方法(需要导入类的包)

Class c2 = fanshe.class(); //实际在告诉我们任何一个类都有一个隐含的静态成员变量class

第三种方法(常用)

        try {  
       Class c3
= Class.forName("包名.类名"); } catch (ClassNotFoundException e) { e.printStackTrace(); }

c1,c2,c3 为fanshe类的类类型(class type)三种方法获取的类类型是完全相同的,即c1 == c2 为true  c2 == c3 为true

 

打印类的信息,包括类的成员函数、成员变量(只获取成员函数)

public static void printClassMethodMessage(Object obj) {
        //传入的是对象,所以用对象.getClass()方法获取对象的类类型
        Class c = obj.getClass();
        System.out.println("类的名称是: " + c.getName())
        /*
         * Method类,方法对象
         * 一个成员方法就是一个Method对象
         * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
         * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
         */;
        Method[] ms = c.getMethods();//c.getDeclaredMethods()
        for(int i = 0; i < ms.length; i++) {
            //得到方法的返回值类型的类类型
            Class returnType = ms[i].getReturnType();
            System.out.print(returnType.getName()+" "); //getSimpleName()
            //得到方法的名称
            System.out.print(ms[i].getName()+"(");
            //获取参数类型--->得到的是参数列表的类型的类类型
            Class[] paramTypes = ms[i].getParameterTypes();
            for(int j = 0; j < paramTypes.length; j++) {
                System.out.print(paramTypes[j].getName()+",");
            }
            System.out.println(")");
        }
    }

String s = "Hello";
ClassUtil.printClassMethodMessage(s);

得到的结果如下

 

类的名称是: java.lang.String
boolean equals(java.lang.Object,)
java.lang.String toString()
int hashCode()
int compareTo(java.lang.String,)
int compareTo(java.lang.Object,)
int indexOf(java.lang.String,int,)
int indexOf(java.lang.String,)
int indexOf(int,int,)
int indexOf(int,)
java.lang.String valueOf(int,)
java.lang.String valueOf(long,)
java.lang.String valueOf(float,)
java.lang.String valueOf(boolean,)
java.lang.String valueOf([C,)
java.lang.String valueOf([C,int,int,)
java.lang.String valueOf(java.lang.Object,)
java.lang.String valueOf(char,)
java.lang.String valueOf(double,)
char charAt(int,)
int codePointAt(int,)
int codePointBefore(int,)
int codePointCount(int,int,)
int compareToIgnoreCase(java.lang.String,)
java.lang.String concat(java.lang.String,)
boolean contains(java.lang.CharSequence,)
boolean contentEquals(java.lang.CharSequence,)
boolean contentEquals(java.lang.StringBuffer,)
java.lang.String copyValueOf([C,)
java.lang.String copyValueOf([C,int,int,)
boolean endsWith(java.lang.String,)
boolean equalsIgnoreCase(java.lang.String,)
java.lang.String format(java.util.Locale,java.lang.String,[Ljava.lang.Object;,)
java.lang.String format(java.lang.String,[Ljava.lang.Object;,)
void getBytes(int,int,[B,int,)
[B getBytes(java.nio.charset.Charset,)
[B getBytes(java.lang.String,)
[B getBytes()
void getChars(int,int,[C,int,)
java.lang.String intern()
boolean isEmpty()
java.lang.String join(java.lang.CharSequence,[Ljava.lang.CharSequence;,)
java.lang.String join(java.lang.CharSequence,java.lang.Iterable,)
int lastIndexOf(int,)
int lastIndexOf(java.lang.String,)
int lastIndexOf(java.lang.String,int,)
int lastIndexOf(int,int,)
int length()
boolean matches(java.lang.String,)
int offsetByCodePoints(int,int,)
boolean regionMatches(int,java.lang.String,int,int,)
boolean regionMatches(boolean,int,java.lang.String,int,int,)
java.lang.String replace(char,char,)
java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence,)
java.lang.String replaceAll(java.lang.String,java.lang.String,)
java.lang.String replaceFirst(java.lang.String,java.lang.String,)
[Ljava.lang.String; split(java.lang.String,)
[Ljava.lang.String; split(java.lang.String,int,)
boolean startsWith(java.lang.String,int,)
boolean startsWith(java.lang.String,)
java.lang.CharSequence subSequence(int,int,)
java.lang.String substring(int,)
java.lang.String substring(int,int,)
[C toCharArray()
java.lang.String toLowerCase(java.util.Locale,)
java.lang.String toLowerCase()
java.lang.String toUpperCase()
java.lang.String toUpperCase(java.util.Locale,)
java.lang.String trim()
void wait()
void wait(long,int,)
void wait(long,)
java.lang.Class getClass()
void notify()
void notifyAll()
java.util.stream.IntStream chars()
java.util.stream.IntStream codePoints()

 

获取成员变量的信息

public static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        /*
         * 成员变量也是对象
         * java.lang.reflect.Field
         * Field类封装了关于成员变量的操作
         * getFields()方法获取的是所有的public的成员变量的信息
         * getDeclaredFields获取的是该类自己声明的成员变量的信息
         */
        //Field[] fs = c.getFields();
        Field[] fs = c.getDeclaredFields();
        for(int i = 0; i < fs.length; i++) {
            Class fieldType = fs[i].getType();
            String typeName = fieldType.getName();
            //得到成员变量的名称
            String fieldName = fs[i].getName();
            System.out.println(typeName+" "+fieldName);
        }
    }

ClassUtil.printFieldMessage("Hello");
System.out.println("==============================");
ClassUtil.printFieldMessage(new Integer(1));

得到的结果如下

[C value
int hash
long serialVersionUID
[Ljava.io.ObjectStreamField; serialPersistentFields
java.util.Comparator CASE_INSENSITIVE_ORDER
==============================
int MIN_VALUE
int MAX_VALUE
java.lang.Class TYPE
[C digits
[C DigitTens
[C DigitOnes
[I sizeTable
int value
int SIZE
int BYTES
long serialVersionUID

打印对象的构造函数的信息

 

public static void printConMessage(Object obj) {
        Class c = obj.getClass();
        /*
         * 构造函数也是对象
         * java.lang.Constructor中封装了构造函数的信息
         * getConstructors获取所有的public的构造函数
         * getDeclaredConstructors得到所有的构造函数
         */
        //Constructor[] cs = c.getConstructors();
        Constructor[] cs = c.getDeclaredConstructors();
        for(int i = 0; i < cs.length; i++) {
            System.out.print(cs[i].getName()+"(");
            //获取构造函数的参数列表--->得到的是参数列表的类类型
            Class[] paramType = cs[i].getParameterTypes();
            for(int j = 0; j < paramType.length; j++) {
                System.out.print(paramType[j].getName()+",");
            }
            System.out.println(")");
        }
    }

ClassUtil.printConMessage("Hello");
System.out.println("=============================");
ClassUtil.printConMessage(new Integer(1));

得到的结果如下

java.lang.String([B,int,int,)
java.lang.String([B,java.nio.charset.Charset,)
java.lang.String([B,java.lang.String,)
java.lang.String([B,int,int,java.nio.charset.Charset,)
java.lang.String([B,int,int,java.lang.String,)
java.lang.String([C,boolean,)
java.lang.String(java.lang.StringBuilder,)
java.lang.String(java.lang.StringBuffer,)
java.lang.String([B,)
java.lang.String([I,int,int,)
java.lang.String()
java.lang.String([C,)
java.lang.String(java.lang.String,)
java.lang.String([C,int,int,)
java.lang.String([B,int,)
java.lang.String([B,int,int,int,)
=============================
java.lang.Integer(int,)
java.lang.Integer(java.lang.String,)

以上获取信息时要注意是getXX()方法还是getDeclaredXX()方法

两者的区别是getXX()得到所有的public包括父类的(函数Methods,成员变量Fields,构造函数Constructors)信息

而getDeclaredXX()方法得到该类的所有包括私有的(函数Methods,成员变量Fields,构造函数Constructors)信息

 

方法的反射操作

首先定义一个类

class A {
    public void print() {
        System.out.println("无参的print方法");
    }
    public void print(int a, int b) {
        System.out.println("带两个int参数的加法方法,结果为:" + (a+b));
    }
    public void print(String a, String b) {
        System.out.println("带两个String参数的方法: " + a.toUpperCase() + "," + b.toLowerCase());
    }
}

如果我们想要调用这几个方法,以往的操作是

A a1 = new A();

a1.print();

a1.print(10,20);

a1.print("hello","WORLD");

那么如何通过反射来调用这几个方法呢

1、首先要获取该类的类类型  Class c = a1.getClass();

2、获取方法

  从上面的例子可以知道获取该类全部方法的方式是  Method[] ms = c.getDeclaredMethods();

  获取单个方法的写法如下:

  Method m = c.getMethod("方法名",new Class[]{参数类型1.class,参数类型2.class.....});

  获取无参print方法

    Method m2 = c.getMethod("print", new Class[]{});  或者  Method m2 = c.getMethod("print");

  获取带int参数方法

    Method m =  c.getMethod("print", new Class[]{int.class,int.class});  或者  Method m = c.getMethod("print", int.class, int.class);

  同样的获取带String参数方法

    Method m1 = c.getMethod("print", new Class[]{String.class,String.class});  或者  Method m1 = c.getMethod("print", String.class, String.class);

3、获取方法后进行反射操作

  java的反射操作通过invoke()调用,如实例中的加法方法

    Object o = m.invoke(a1,new Object[]{10,20});

    方法的反射操作是用m对象来进行方法调用 和a1.print调用的效果完全相同

    方法如果没有返回值返回null,有返回值返回具体的返回值

  同样的不带参数和带String参数的方法调用也是如此,代码如下

import java.lang.reflect.Method;

public class MethodDemo1 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        //要获取print(int ,int )方法  1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型
        A a1 = new A();
        Class c = a1.getClass();
        
        try {
            Method m = c.getMethod("print", int.class, int.class);
            Object o = m.invoke(a1, 10, 20);
            System.out.println("========================");
            
            Method m1 = c.getMethod("print", String.class, String.class);
            o = m1.invoke(a1, "hello", "Hello");
            System.out.println("========================");
            
            Method m2 = c.getMethod("print");
            m2.invoke(a1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class A {
    public void print() {
        System.out.println("无参的print方法");
    }
    public void print(int a, int b) {
        System.out.println("带两个int参数的加法方法,结果为:" + (a+b));
    }
    public void print(String a, String b) {
        System.out.println("带两个String参数的方法: " + a.toUpperCase() + "," + b.toLowerCase());
    }
}

运行结果如下

 

带两个int参数的加法方法,结果为:30
========================
带两个String参数的方法: HELLO,hello
========================
无参的print方法

 

与普通的方法调用得到的结果相同

 

posted @ 2018-04-25 14:15  努力学习的IT萌新  阅读(159)  评论(0编辑  收藏  举报