java基础教程之Class类和反射API介绍

1.      Class

1.1.   Class类说明

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(booleanbytecharshortintlongfloat double)和关键字 void 也表示为 Class 对象。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。比如说,当我们编写了Student这么一个类,编译完后,就会产生一个Student.class的字节码文件,用于表示Student类的类型信息。

1.2.   获取Class实例的四种方式

Ø        利用对象调用getClass()方法获取该对象的Class实例;

Ø        使用Class类的静态方法forName(),用类的名字获取一个Class实例;

Ø        运用.class的方式来获取Class实例;

Ø        对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例。

现在来编写一个类来实现这几种方式,

public class A {

    public static void main(String args[]){

        Point p = new Point();

        Class c1 = p.getClass();

        System.out.println(c1.getName());

       

        //由于forName这个静态方法会抛出一个异常,所以在调用时要么在类中也

//抛出一个异常,要么捕获异常

        try{

            Class c2 = Class.forName("Point");

            System.out.println(c2.getName());

        }catch(Exception e){

            e.printStackTrace();

        }

       

        Class c3 = Point.class;

        System.out.println(c3.getName());

       

        Class c4 = int.class;

        System.out.println(c4.getName());

       

        Class c5 = Integer.class;

        System.out.println(c5.getName());

       

        Class c6 = Integer.TYPE;

        System.out.println(c6.getName());

       

    }

}

 

class Point{

    int x,y;

}

 

编译结果:

Point

Point

Point

int

java.lang.Integer

int

1.3.   关于JAVA对象加载说明

在运行期间,如果我们要产生某个类的对象,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。

现在我们根据这段话说明描述来编写一个类,验证这段话。

public class A {

    public static void main(String args[]){

        System.out.println("before class Loading......");

        new Point();

        System.out.println("after class Loading......");

        try{

            Class.forName("Line");       

        }catch(Exception e){

            e.printStackTrace();

        }

    }

}

 

class Point{

    //静态代码段,当类被加载时,就会被执行

    static{

        System.out.println("Point class Loading......");

    }

}

 

class Line{

    static{

        System.out.println("Line class Loading......");

    }

}

 

编译结果:

before class Loading......

Point class Loading......

after class Loading......

Line class Loading......

1.4.   newInstance()方法

newInstance()方法是Class类的实例方法,用于创建此Class对象所表示的类的一个新实例。

在创建对象时,都要调用类的构造函数。

new关键字创建对象可以自由选择构造函数相比,newInstance()方法创建对象时,只能调用类中缺省的构造方法,也就是没有参数的构造函数。如果一个类的所有构造函数都有参数,那么就会出现异常。但用newInstance()方法创建对象有个最大好处,事先不知道类的名称的情况下可以创建类的对象,也就是说在代码中可以动态创建类的对象。

现在来编写一个利用newInstance()方法创建一个对象的实例:

public class A {

    public static void main(String args[]){

        try{

            Class c = Class.forName("Point");

            Point p = (Point)c.newInstance();

            p.output();

        }catch(Exception e){

            e.printStackTrace();

        }      

    }

}

 

class Point{

    int x,y;

    Point(int x, int y){

        this.x = x;

        this.y = y;

    }

    public void output(){

        System.out.println("x="+x+",y="+y);

    }

}

编译结果:

x=5,y=5

如果在Point类中只有带参构造函数,在编译时,会出现这样的异常:

java.lang.InstantiationException: Point

    at java.lang.Class.newInstance0(Class.java:340)

    at java.lang.Class.newInstance(Class.java:308)

    at A.main(A.java:5)

1.5.   反射API

1.5.1.    反射API的作用

利用newInstance()方法创建对象类,将调用到类的缺省构造方法,如果不存在缺省构造方法时,就会出现异常,这时就要使用反射API来解决这个问题。

反射API的作用有:

Ø        检测一个对象的类

Ø        获取类的修饰符、属性、函数、构造函数及基类的信息

Ø        找出接口的常量及方法

Ø        在不知道类名的情况下创建对象,类名在运行的时候动态获取

Ø        设置或获取对象属性的值,即使不知道属性的名称,名称在运行的时候动态获取

Ø        调用对象的方法,即使不知道方法名称,名称在运行的时候动态获取

Ø        创建新的数组,其大小和元素数据类型都是未知的,在运行的时候动态获取

1.5.2.    反射API相关类和使用

Ø        Constructor提供关于类的单个构造方法的信息以及对它的访问权限

Ø        Field提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

Ø        Method提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

Ø        Modifier提供了 static 方法和常量,对类和成员访问修饰符进行解码。

现在来使用这些类:

import java.lang.reflect.*;

public class A {

    public static void main(String args[]){

        try{

            Class c = Class.forName("Point");

            Constructor[] cons = c.getDeclaredConstructors();

            for(int i=0; ilength; i++){

                System.out.println(cons[i]);

            }

            Method[] method = c.getDeclaredMethods();

            for(int i=0; ilength; i++){

                System.out.println(method[i]);

            }

            Field[] field = c.getDeclaredFields();

            for(int i=0; ilength; i++){

                System.out.println(field[i]);

            }

        }catch(Exception e){

            e.printStackTrace();

        }              

    }

}

 

class Point{

    int x,y;

    Point(){

        this.x = 5;

        this.y = 5;

    }

    Point(int x, int y){

        this.x = x;

        this.y = y;

    }

    public void output(){

        System.out.println("x="+x+",y="+y);

    }

}

编译结果:

Point()

Point(int,int)

public void Point.output()

int Point.x

int Point.y

1.5.3.    ConstructorgetParameterTypes()方法使用说明

getParameterTypes()方法返回一组按照声明顺序Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。如果底层构造方法不带任何参数,则返回一个长度为 0 的数组。

现在以一个实例来说明该方法的使用:

import java.lang.reflect.*;

public class A {

    public static void main(String args[]){

        try{

            Class c = Class.forName("Point");

            Constructor[] cons = c.getDeclaredConstructors();

            for(int i=0; ilength; i++){

                Class[] parm = cons[i].getParameterTypes();

                for(int j=0; jlength; j++){

                    System.out.println(parm[i]);

                }

            }

        }catch(Exception e){

            e.printStackTrace();

        }              

    }

}

 

class Point{

    int x,y;

    Point(int x, int y){

        this.x = x;

        this.y = y;

    }

    public void output(){

        System.out.println("x="+x+",y="+y);

    }

}

编译结果:

int

int

如果Point类的构造函数形参是两个Object类对象,那么编译结果:

class java.lang.Object

class java.lang.Object

1.5.4.    使用Constructor类的newInstance()方法创建对象

newInstance:使用此Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

现在来编写使用该方法的实例:

import java.lang.reflect.*;

public class A {

    public static void main(String args[]){

        try{

            Class c = Class.forName("Point");

            Constructor[] cons = c.getDeclaredConstructors();

            Class[] params = cons[0].getParameterTypes();  //获取Point(int x, int y)构造函数参数

            Object[] o = new Object[params.length];

            for(int i=0; ilength; i++){

                if(params[i].isPrimitive()){    //params[i]是否是基本数据类型变量

                    o[i] = new Integer(i);

                }

            }

            Object obj = cons[0].newInstance(o);

            Method[] method = c.getDeclaredMethods();

            method[0].invoke(obj, null);

        }catch(Exception e){

            e.printStackTrace();

        }              

    }

}

 

class Point{

    int x,y;

    Point(int x, int y){

        this.x = x;

        this.y = y;

    }

    public void output(){

        System.out.println("x="+x+",y="+y);

    }

}

编译结果:

x=0,y=1

这样,使用Class类和反射API就可以动态创建类的对象,动态调用对象的方法。

你可能感兴趣的:(java基础教程之Class类和反射API介绍)