----------android培训、java培训期待与您交流!----------
在java中较为重要的就是反射机制,那么什么是反射机制?正常情况下,如果已经有一个类,则肯定可以通过类创建对象;那么如果现在要求通过一个对象找到一个类的名称,此时就需要用到反射机制。如果要完成反射操作,则首先要认识的就是Class类
Class类
在正常情况下,需要先有一个类的完整路径引入后才可以按照固定的格式产生实例化对象,但是在java中也允许通过一个实例化对象找到一个类的完整信息,那么这就是Class的功能。首先来看一段代码
通过一个对象饿到完整的“包。类”名称
class X{
};
public class Demo{
public static void main(String args[]){
Xx = new X() ; //实例化X类的对象
System. out.println(x.getClass().getName()); //得到对象所在的类
}
};
结果:demo.X
从上可以发现,通过一个对象得到了对象所在的完整的包.类名称。。。那么getClass()方法时哪里定义的?从以前的只是可以知道,一个类如果没有明确的声明继承哪个父类,则默认继承Object类,所以getClass()方法时Object类中的。此方法定义如下
pubcic final Class getClass();返回值类型是一个Class类,此类是java反射的源头
反射从程序的运行结果来看也很好理解
正常方式:引入需要的包.类名称----->通过new实例化----->取得实例化对象
反射方式:实例化对象------>getClass()方法------->得到完整的包.类名称
ps:所有类的对象实际上都是Class类的实例。在java中,Object类是一切类的父类,那么所有类的对象实际上也就是都是java.lang.Class类的实例,所以所有的对象都可以转变为java.lang.Class类型表示.
在Class类中本身没有定义任何的构造方法,所有如果要使用则首先必须通过forName()方法实例化。除此之外,也可以使用类.class或者对象.getClass方法实例化
代码范例---实例化Class对象
class X{
};
public class Demo{
public static void main(String args[]){
Class<?>c1 = null ; //指定泛型
Class<?>c2 = null ; //指定泛型
Class<?>c3 = null ; //指定泛型
try{
//最常用的一种形式
c1= Class. forName("demo.X") ;
} catch(ClassNotFoundException e){
e.printStackTrace();
}
c2= new X().getClass(); //通过Object类中的方法实例化
c3= X. class ; //通过类.class实例化
System. out.println("类名称:" + c1.getName()) ; // 得到类的名称
System. out.println("类名称:" + c2.getName()) ; // 得到类的名称
System. out.println("类名称:" + c3.getName()) ; // 得到类的名称
}
};
结果:类名称:demo.X
类名称:demo.X
类名称:demo.X
PS:forName()实例化
类.class 实例化
对象.getClass()此三种实例化Class对象,其中forName()更加具备灵活性,也比较常用
Class类的使用
Class类在实际中最常用的方法就是实例化对象的操作,既可以通过一个给定的字符串来实例化一个类的对象
通过Class类实例化对象-通过无参构造实例化对象
如果要想通过Class类本身实例化对象其他类的对象,则可以使用newInstance方法,但是必须保证被实例化的类中存在一个无参构造方法
代码示例
class Person{
private String name ; // name属性
private int age ; // age属性
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this .name ;
}
public int getAge(){
return this .age ;
}
public String toString(){ //覆写toString()方法
return "姓名:" + this.name + ",年龄:" + this.age ;
}
};
public class Demo{
public static void main(String args[]){
Class<?>c = null ; //声明Class对象
try{
c= Class. forName("demo.Person") ;//forName()实例化
} catch(ClassNotFoundException e){
e.printStackTrace();
}
Personper = null ; //声明Person对象
try{
per= (Person)c.newInstance() ; // 使用newInstance方法实例化对象
} catch(Exception e){
e.printStackTrace();
}
per.setName( "hello") ; //设置姓名
per.setAge(30); //设置年龄
System. out.println(per) ; //内容输出,调用toString()
}
};
结果:姓名:hello,年龄:30
PS:通过Class.forName()方法实例化Class对象之后,直接调用newInstance()方法就可以根据传入的完整的“包.类"名称的方式对象的实例化操作,完全取代了之前使用关键字new的操作方式。但是一定要注意,被实例化对象的类中必须存在无参构造方法,如果不存在,则无法实例化。
调用有参构造实例化对象
一般步骤
1通过Class类中的getConstructors()方法取得本类中的全部构造方法
2向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数
3之后通过Constructor实例化对象
此时要用到Constructor类,表示的是构造方法,常用的方法如下表
int getModefiers():取得构造方法的修饰符
String getName():得到构造方法的名称
Class<?>[] getParameterTypes()得到构造方法中参数的类型
String toString():返回此构造方法的信息
代码实例-调用类中的有参构造
class Person{
private String name ; // name属性
private int age ; // age属性
public Person(String name, int age){
this.setName(name) ;
this.setAge(age);
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this .name ;
}
public int getAge(){
return this .age ;
}
public String toString(){ //覆写toString()方法
return "姓名:" + this.name + ",年龄:" + this.age ;
}
};
public class Demo{
public static void main(String args[]){
Class<?>c = null ; //声明Class对象
try{
c= Class. forName("demo.Person") ;
} catch(ClassNotFoundException e){
e.printStackTrace();
}
Personper = null ; //声明Person对象
Constructor<?>cons[] = null ;
cons= c.getConstructors() ;
try{
per= (Person)cons[0].newInstance("hello" ,30) ; //实例化对象
} catch(Exception e){
e.printStackTrace();
}
System. out.println(per) ; //内容输出,调用toString()
}
}
结果:姓名:hello,年龄:30
PS:以上是反射在开发中用的最多的地方
反射的应用----取得类的结构
在实际应用中,还可以通过反射取得一个类的完整结构,那么这个就要用到java.lang.reflect包中的类
Constructor:表示类中的构造方法
Field:表示类中的属性
Method:表示类中的方法
这三个都是AccessibleObject类的子类.下面通过以上几个类和Class类共同完成类的反射操作
取得所实现的全部接口
要取得一个类实现的全部接口,则必须使用Class类中的getInterfaces()方法,此方法定义如下
public Class[] getInsterfaces()
返回一个Class类的对象数组,之后利用Class类中的forName()方法输出即可
package demo;
interface China{ //定义 China接口
public static final String NATIONAL = "China" ; //定义全局常量
public static final String AUTHOR = "hello" ; //定义全局常量
public void sayChina(); //无参的,没有返回值的方法
public String sayHello(String name, int age) ; // 定义有两个参数的方法,并返回内容
}
public class Person implements China{
private String name ;
private int age ;
public Person(){ //无参构造
}
public Person(String name){
this.name = name ; // 设置name属性
}
public Person(String name, int age){
this(name) ;
this.age = age ;
}
public void sayChina(){ //覆写方法
System. out.println("作者:" + AUTHOR + ",国籍:" + NATIONAL) ;
}
public String sayHello(String name, int age){
return name + ",你好!我今年:" + age + "岁了!" ;
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this .name ;
}
public int getAge(){
return this .age ;
}
};
public class Demo{
public static void main(String args[]){
Class<?>c1 = null ; //声明Class对象
try{
c1= Class. forName("demo.Person") ; //实例化对象
} catch(ClassNotFoundException e){
e.printStackTrace();
}
Class<?>c[] = c1.getInterfaces() ; //以数组形式返回实现的全部接口
for(int i=0;i<c.length;i++){
System. out.println("实现的接口名称:" + c[i].getName()) ; // 输出接口名称
}
}
};
结果:实现的接口名称:demo.China
取得父类
一个类可以实现多个接口,但是只能继承一个父类,要取得一个类的父类,可以直接使用Class类中的getSuperclass()方法
public Class<?super T> getSuperclass()
public class Demo{
public static void main(String args[]){
Class<?>c1 = null ; //声明Class对象
try{
c1= Class. forName("demo.Person") ; //实例化对象
} catch(ClassNotFoundException e){
e.printStackTrace();
}
Class<?>c2 = c1.getSuperclass() ; //取得父类
System. out.println("父类名称:" + c2.getName()) ;
}
};
结果:父类名称:java.lang.Object
PS:Person类编写时没有明确的继承一个父类,所以默认继承Object类
取得全部构造方法
要取得一个类中的全部构造方法,则要使用Class类中的getConstructors方法
import java.lang.reflect.Constructor; //导入构造方法的包
public class Demo{
public static void main(String args[]){
Class<?>c1 = null ; //声明Class对象
try{
c1= Class. forName("demo.Person") ; //实例化对象
} catch(ClassNotFoundException e){
e.printStackTrace();
}
Constructor<?>con[] = c1.getConstructors() ; //取得一个类中的全部构造
for(int i=0;i<con.length;i++){
System. out.println("构造方法:" + con[i]) ; //输出构造,直接打印
}
}
};
结果:
构造方法:public demo.Person(java.lang.String)
构造方法:public demo.Person(java.lang.String,int)
构造方法:public demo.Person()
小结:
1 Class类是反射机制操作的源头
2 class类对象有3种实例化方式
通过Object类中的getClass方法
通过类.class的形式
通过Class.forName方法,此种方式最为常见
3 可以通过Class类中的newInstance方法进行对象的实例化操作,但是要求类中必须存在无参数构造函数,如果类中没有构造函数,则必须使用Constructor类完成对象的实例化操作
4 使用反射机制可以通过Method调用类中的方法,也可以直接操作类中的属性