Java反射应用

1. 获取一个Class对象

其中Class<?> 和Class<? extends Object>等效,可以接收所有java类

//方法一:新建一个对象,调用它的getClass()方法
Object object = new Object();
Class<? extends Object> c1 = object.getClass();
//方法二:直接调用类的class,只有这种方法可以直接接收对应的类
Class<Object> c2 = Object.class;
//方法三:通过Class的forName()方法,注意此时传入参数应为完整的路径
Class<?> c3 = Class.forName("java.lang.Object");

2.类的实例化

这是一个测试类

package reflect;

public class Person {
	public String sex;
	protected String name;
	String birthday;
	private int age;

	public Person() {
		super();
	}

	public Person(String sex, String name, String birthday, int age) {
		super();
		this.sex = sex;
		this.name = name;
		this.birthday = birthday;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [sex=" + sex + ", name=" + name + ", birthday=" + birthday + ", age=" + age + "]";
	}
}
  • 获取到Class对象后,有无参构造方法的类可以直接通过newInstance()方法实例化对象,
		Class<?> clazz = Class.forName("reflect.Person");
		Person person = null;
		try {
			person = (Person) clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}
		System.out.println(person.toString());

这里输出

Person [sex=null, name=null, birthday=null, age=0]

  • 没有无参构造方法的类或者需要使用特定的有参构造方法时,通过Constructor类的newInstance()方法实例化对象;
		Class<?> clazz = Class.forName("reflect.Person");
		Person person = null;
		Constructor<?> constructor = null;
		try {
			// 根据对应的参数类型找到匹配的构造方法
			constructor = clazz.getConstructor(String.class, String.class, String.class, int.class);
			try {
				// 根据对应参数类型输入参数实例化对象
				person = (Person) constructor.newInstance("男", "blue_ice", "1998.05.26", 21);
			} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				e.printStackTrace();
			}
		} catch (NoSuchMethodException | SecurityException e) {
			e.printStackTrace();
		}
		System.out.println(person);

这里输出

Person [sex=男, name=blue_ice, birthday=1998.05.26, age=21]

  • 另外getConstructors()方法可以获取到所有的共有构造方法
Constructor<?>[] constructors = clazz.getConstructors();
for (int i = 0; i < constructors.length; i++) {
	System.out.println(constructors[i]);
}

输出

public reflect.Person()
public reflect.Person(java.lang.String,java.lang.String,java.lang.String,int)

3.获取类的方法

  • getMethods()获取类的所有共有方法
Class<?> clazz = Class.forName("reflect.Person");
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
	System.out.println(methods[i]);
}

这里输出

public java.lang.String reflect.Person.toString()
public int reflect.Person.getAge()
public void reflect.Person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

其中前三行为当前类方法,后边的是Object类的方法

  • getMethod()获取指定的方法,name为方法名,parameterTypes是参数类型

public Method getMethod(String name, Class<?>… parameterTypes)
throws NoSuchMethodException, SecurityException

try {
	Method method = clazz.getMethod("setAge", int.class);
	System.out.println(method);
} catch (NoSuchMethodException | SecurityException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

这里输出

public void reflect.Person.setAge(int)

4.获取类的属性

  • getFields()获取类的所有公有属性
Class<?> clazz = Class.forName("reflect.Person");
Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
	System.out.println(fields[i]);
}

这里输出

public java.lang.String reflect.Person.sex

若父类有公有属性则会输出,这里因为父类没有公有属性,所以没有输出父类的公有属性

  • getField()获取指定的类属性,name为属性名

public Field getField(String name)
throws NoSuchFieldException, SecurityException

try {
	Field field = clazz.getField("sex");
	System.out.println(field);
} catch (NoSuchFieldException | SecurityException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

这里输出

public java.lang.String reflect.Person.sex

5.类的非公有的属性、构造方法、方法均可以通过getDeclared*()获取到

6、反射有关的一些面试题

(1)什么是反射,反射的作用是什么:
1.是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
  对于任意一个对象,都能够调用它的任意一个方法和属性;
  这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2.在运行时判断任意一个对象所属的类;
  在运行时构造任意一个类的对象;
  在运行时获取一个类拥有的属性、方法;
  在运行时调用任意一个对象的方法。
(2)反射机制的优点和缺点:
优点:可以动态的创建对象,提高了程序的灵活性和扩展性,最大限度发挥了java的灵活性。
缺点:
  性能问题:由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。 
  	因此,反射操作的性能低于非反射操作,并且应避免在性能敏感应用程序中频繁调用的代码段中。
  安全问题:要在没有安全限制的环境下使用反射,如果一个程序必须在有安全限制的环境中运行,
    如Applet,那么这就是个问题了。
  内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),
    所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。
    反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
  模糊程序内部逻辑:程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,
    因而会带来维护问题。反射代码比相应的直接代码更复杂。
(3)在Java反射中,Class.forName和ClassLoader的区别

这是Class.forName()的源码,可以看到,Class.forName()也是通过调用的CLassLoader来实现的。

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
  • 第二个参数为true会对类进行初始化,代表会执行类中的静态代码块,以及对静态变量的赋值等操作。
  • 这是public static Class<?> forName(String name, boolean initialize, ClassLoader loader)方法,在这个方法的第二个参数可以动态的设置是否对类进行初始化
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
                               ClassLoader loader)
    throws ClassNotFoundException
{
    Class<?> caller = null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // Reflective call to get caller class is only needed if a security manager
        // is present.  Avoid the overhead of making this call otherwise.
        caller = Reflection.getCallerClass();
        if (sun.misc.VM.isSystemDomainLoader(loader)) {
            ClassLoader ccl = ClassLoader.getClassLoader(caller);
            if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                sm.checkPermission(
                    SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
    }
    return forName0(name, initialize, loader, caller);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值