我是靠谱客的博主 疯狂向日葵,最近开发中收集的这篇文章主要介绍JAVA反射--一些常用方法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述


       反射中,最基础的是对Class类的了解和使用。在JAVA中Object是一切类的父类,而getClass()方法是Object中定义的,如下

public final native Class<?> getClass();

       那么可以这么说,所有类的对象实际上都是Class类的实例。如果你对类加载及JVM方法区有所了解,这个应该很容易理解。

       本文主要是写点代码认识Class类的一些常用方法。

1.获取Class对象

      在Class类中,只定义了个私有的构造方法,这意味着,无法通过new Class()方式创建一个Class对象。

/*
* Constructor. Only the Java Virtual Machine creates Class
* objects.
*/
private Class() {}


      虽然无法直接使用new Class()方式创建对象,但是Class类中提供了forName()方法,通过它仍然可以获得Class对象。

public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, ClassLoader.getCallerClassLoader());
}
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException


        除了使用forName()方法获得Class对象外,上面说过了Object是所有类的父类,而Object中有getClass()方法,所以通过"类名.getClass()"也可以获得Class对象,也可以通过“类名.class"

package test;
public class A1 {
}
/**
* 获取Class对象
*/
public class A2 {
public static void main(String[] args){
Class<?> c1=null;
Class<?> c2=null;
Class<?> c3=null;
try {
c1=Class.forName("test.A1");//通过forName()获取
c2=A1.class;//通过"类名.class"获取
A1 a1=new A1();
c3=a1.getClass();//通过"对象.getClass()"获取
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("类路径:"+c1.getName());
System.out.println("类路径:"+c2.getName());
System.out.println("类路径:"+c3.getName());
}
}


运行结果

类路径:test.A1
类路径:test.A1
类路径:test.A1

       通过运行结果可知,3种实例化Class对象的方式是一样的,但是使用forName()是较为常用的一种(当然,如果使用Hibernate或spring等框架时,经常使用"类.class“方式传送一个JavaBean实体)。

     

   下面先看过设计上比较丑陋的例子。

package test;
/**
* 水果类接口
* 所有水果必须实现此接口
*
*/
public interface Fruit {
public void say();
}
package test;
/**
* 苹果类,实现接口Fruit
*
*/
public class Apple implements Fruit {
@Override
public void say() {
System.out.println("hello,I'm apple!");
}
}
/**
* 香蕉类,实现接口Fruit
*
*/
public class Banana implements Fruit {
@Override
public void say() {
System.out.println("hello,I'm banana!");
}
}
package test;
/**
* 水果工具类
*
*/
public class FruitUtil {
public static Fruit createFruit(String fruitName){
if("apple".equalsIgnoreCase(fruitName)) return (Fruit)new Apple();
if("banana".equalsIgnoreCase(fruitName)) return (Fruit)new Banana();
return null;
}
}
package test;
/**
* 测试类
*
*/
public class Test {
public static void main(String[] args){
Fruit f=FruitUtil.createFruit("apple");
if(f!=null) {
f.say();
}else{
System.out.println("没有水果!");
}
}
}

运行结果

hello,I'm apple!

 

      代码没错,运行结果也没错,我之所以说它丑陋,是从代码扩展性方面考虑。比如,如果我要再添加一种水果呢?那么就必须修改FruitUtil.createFruit()方法中的代码了,增加if判断。那如果我要新曾几十种水果呢?那是不是要写几十个if判断。。。。。作为一个接触JAVA两年的菜鸟的我,都觉得代码设计不友好了,更别说修改原有代码对系统的危害了。那有没有一种方法,当新增水果时,不需要对原有代码做任何修改呢?有,这时,Class.forName()一声大哄,粉墨登场了。

package test;
/**
* 水果类接口
* 所有水果必须实现此接口
*
*/
public interface Fruit {
public void say();
}
package test;
/**
* 苹果类,实现接口Fruit
*
*/
public class Apple implements Fruit {
@Override
public void say() {
System.out.println("hello,I'm apple!");
}
}
package test;
/**
* 香蕉类,实现接口Fruit
*
*/
public class Banana implements Fruit {
@Override
public void say() {
System.out.println("hello,I'm banana!");
}
}
package test;
/**
* 水果工具类
*
*/
public class FruitUtil {
public static Fruit createFruit(String classPath)throws Exception{
Fruit fruit=null;
try {
fruit=(Fruit)Class.forName(classPath).newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new Exception("创建水果失败!");
}
return fruit;
}
}
package test;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
/**
* 测试类
*
*/
public class Test {
private final static String FRUIT_CONF_PATH=System.getProperty("user.dir");
public static void main(String[] args){
Properties p=new Properties();
try {
//在eclipse下建立普通JAVA项目,src写的内容放在bin下了
FileInputStream in=new FileInputStream(new File(FRUIT_CONF_PATH+File.separator+"bin"+File.separator+"fruit.properties"));
p.load(in);
String fruitClassPath=p.getProperty("apple");
p.clear();
in.close();
Fruit f=FruitUtil.createFruit(fruitClassPath);
f.say();
} catch (Exception e) {
e.printStackTrace();
System.out.println("获取水果实例失败!");
}
}
}

fruit.properties配置文件


apple=test.Apple
banana=test.Banana


 运行结果

hello,I'm apple!

 

    这样改写后,以后有新增水果时,只要编写新增水果类,并再配置文件中配置新水果的类路径就OK了,原有的代码不需要修改。

这样的设计就具有很好的扩展性。

 

2.获取类中的成员变量

       getFields():获得类(包括父类)的public成员变量

       getDeclaredFields():获得类(不包括父类)的全部成员变量

   

 

package test;
public class A {
public int n_A;
private String s_A;
protected double d_A;
}
package test;
public class A1 extends A {
public int n_A1;
private String s_A1;
protected double d_A1;
}
package test;
import java.lang.reflect.Field;
public class A2 {
public static void main(String[] args){
Class<?> c1=null;
try {
c1=Class.forName("test.A1");//通过forName()获取A1的Class对象
Field[] f1=c1.getFields();//A1(包括父类)中的public成员变量
for(Field f:f1)
System.out.println("A1(包括父类)类中public 成员变量:"+f.getName());
System.out.println("获取A1(不包括父类)类中的所有成员变量::::::::");
Field[] f2=c1.getDeclaredFields();//A1中的所有成员变量
for(Field f:f2)
System.out.println("A1(不包括父类)类中的成员变量:"+f.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}


运行结果

A1(包括父类)类中public 成员变量:n_A1
A1(包括父类)类中public 成员变量:n_A
获取A1(不包括父类)类中的所有成员变量::::::::
A1(不包括父类)类中的成员变量:n_A1
A1(不包括父类)类中的成员变量:s_A1
A1(不包括父类)类中的成员变量:d_A1

3.获取类中的方法

      getMethods():获取类(包括父类)中的public方法(不包括构造方法)

      getDeclaredMethods():获取本类(不包括父类)中的所有方法(不包括构造方法)

      getConstructors():获取本类(不包括父类)中的所有public构造方法

     考虑到篇幅问题,就不贴代码了。

4.实例化对象

package test;
public class A1
{
private int n;
public A1(){
this.n=0;
}
public A1(int n){
this.n=n;
}
public int getN() {
return n;
}
public void setN(int n) {
this.n = n;
};
}
package test;
import java.lang.reflect.Constructor;
public class A2 {
public static void main(String[] args){
Class<?> c1=null;
try {
c1=Class.forName("test.A1");//通过forName()获取A1的Class对象
A1 a1=(A1)c1.newInstance();//使用这种实例化方式,则A1中必须有无参构造方法
System.out.println("使用Class类中的newInstance()方法实例化,a1.n="+a1.getN());
Constructor<?>[] con=c1.getConstructors();//类中存在多个构造方法时,数组顺序和类中写构造方法的顺序一致
A1 a2=(A1)con[0].newInstance();//A1中也必须存在无参构造方法
System.out.println("使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a2.n="+a2.getN());
A1 a3=(A1)con[1].newInstance(10);//A1中可以不存在无参构造方法,或者无参构造方法用private修饰时
System.out.println("使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a3.n="+a3.getN());
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果

使用Class类中的newInstance()方法实例化,a1.n=0
使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a2.n=0
使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a3.n=10

5.通过反射调用类中的方法

package test;
public class A {
public void sayHello(){
System.out.println("hello,world");
}
public void sayHello(String name){
System.out.println("hello,"+name);
}
}
package test;
import java.lang.reflect.Method;
public class Test01 {
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("test.A");//通过forName()获取A的Class对象
A a=(A)c.newInstance();
Method m1=c.getMethod("sayHello");//获得无参数的syaHello方法
m1.invoke(a);
Method m2=c.getMethod("sayHello", String.class);//获得只含有String类型参数的sayHello方法
m2.invoke(a, "everyOne");
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果

hello,world
hello,everyOne


6.通过反射破坏类的封装性(给私有变量赋值并访问)

package test;
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
package test;
import java.lang.reflect.Field;
/**
* 通过反射访问类的私有变量
*
*/
public class Test01 {
public static void main(String[] args){
Class<?> c=null;
try {
c=Class.forName("test.User");//通过forName()获取A的Class对象
User user=(User)c.newInstance();
Field name=c.getDeclaredField("name");//获得name变量
Field age=c.getDeclaredField("age");//获得age变量
name.setAccessible(true);//将name属性设置成可被外部访问
age.setAccessible(true);//将age变量设置成可被外部访问
name.set(user, "张三");
age.set(user, 20);
System.out.println("姓名:"+name.get(user)+"
"+user.getName());
System.out.println("年龄:"+age.get(user)+"
"+user.getAge());
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果

姓名:张三   张三
年龄:20   20


 
 
 
 

 

最后

以上就是疯狂向日葵为你收集整理的JAVA反射--一些常用方法的全部内容,希望文章能够帮你解决JAVA反射--一些常用方法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部