Java反射基础知识

250 阅读6分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

啥是反射?

在加载完类后,堆里面产生了应该class对象,我们可以通过这个class对象看到类的源码结构。这个class对象就像一面镜子,透过他可以看到类结构,所以我们把这个叫做反射。

一般情况,我们引入包类名称,然后new得到对象,进行该对象内部属性和方法的操作

反射方式:先实例化对象,然后透过getClass()方法得到该类的全类名(包名.类名)

这么写反射代码?

拿到反射入口

1.通过Class.forName("全类名")
但是这个需要捕获异常
// 1.class.forname(全类名)
try {
Class<?> perClass=Class.forName("reflect.person");
System.out.println(perClass);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2.通过全类名.class
3.通过对象.class
先对我们要操纵的对象实例化(new),然后对象.getClass
这里我们的实体类是person

person代码

package reflect;

public class person implements{
private int age;
private String name;
public int hhqq;
private void privatemethod() {
	System.out.println("私有方法");
}
	@Override
public String toString() {
	return "person [age=" + age + ", name=" + name + "]";
}
	public person(int age, String name) {
	super();
	this.age = age;
	this.name = name;
}
	private person( String name) {
	super();
	this.name = name;
}
	public person(int age) {
	super();
	this.age = age;

}
	public person() {
	super();
	// TODO Auto-generated constructor stub
}
	public int getAge() {
	return age;
}
public void setAge(int age) {
	this.age = age;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}


}

拿到反射入口代码

package reflect;

public class 拿到反射入口 {
public static void main(String[] args) {
//	1.class.forname(全类名)
	try {
		Class<?> perClass=Class.forName("reflect.person");
		System.out.println(perClass);
	} catch (ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
//	2. 全类名.class
	Class<?> perClass1=reflect.person.class;
	System.out.println(perClass1);
//	3.对象.getClass
	person p=new person();
	Class<?> perClass2=p.getClass();
	System.out.println(perClass2);
}
}

上面运行结果是 class 包名.person

反射的相关方法

获取public方法

Method[]method=perClass1.getMethods();
for(Method m:method) {
System.out.println(m);

// 拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
}
运行结果比如
public java.lang.String reflect.person.getName()
其实等于person类里面的 public String getName()方法

获取全部方法,但是只能是当前类的

Method[]method1=perClass1.**getDeclaredMethods()**;;
for(Method m:method1) {
	System.out.println(m);

// 拿到的是全类名,有私有方法 }

获取父类

Class<?> fac=perClass1.getSuperclass();
System.out.println(fac);        

获取构造方法

System.out.println("---------------------------------");
Constructor<?>[] meth=perClass1.getConstructors();
for(Constructor c:meth) {
	System.out.println(c);
}

拿到公共属性

Field[]md=perClass1.getFields();
for(Field m:md) {
    //		拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
	System.out.println(m);

}

拿到所有属性

Field[]md1=perClass1.getDeclaredFields();
for(Field m:md1) {
   // 拿到所有方法
	System.out.println(m);
	
}

获取person对象

try {
	Object in=perClass1.newInstance();
	person pp=(person) in;
	pp.systest1();
} catch (InstantiationException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} catch (IllegalAccessException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}
    

获取接口

先添加接口类,然后然person继承接口

Class<?>[] inter=perClass1.getInterfaces();
for(Class iq:inter) {
	System.out.println(iq);
}

完整代码:

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class 获取反射方法 {
public static void main(String[] args) {
//	2. 拿到反射入口
	Class<?> perClass1=reflect.person.class;
	System.out.println(perClass1);
//	拿方法
//1.所有公共方法
	Method[]method=perClass1.getMethods();
	int i=0;
	for(Method m:method) {
		System.out.println(m);
		i++;
//		拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
	}
	System.out.println(i);
	System.out.println("=============================================");
//	拿全部方法,只能当前类
	Method[]method1=perClass1.getDeclaredMethods();
	int j=0;
	for(Method m:method1) {
		System.out.println(m);
		j++;
//		拿到的是全类名,有私有方法
	}
	System.out.println(j);
	System.out.println("---------------------------------");
//	2.获取所有接口
	Class<?>[] inter=perClass1.getInterfaces();
	for(Class iq:inter) {
		System.out.println(iq);
	}
	System.out.println("---------------------------------");
//	获取父类
	Class<?> fac=perClass1.getSuperclass();
	System.out.println(fac);
//	获取构造方法
	System.out.println("---------------------------------");
	Constructor<?>[] meth=perClass1.getConstructors();
	for(Constructor c:meth) {
		System.out.println(c);
	}
	System.out.println("---------------------------------");
//	拿到公共属性
	Field[]md=perClass1.getFields();
	for(Field m:md) {
		System.out.println(m);
//		拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
	}
	System.out.println("---------------------------------");
//	拿到所有属性
	Field[]md1=perClass1.getDeclaredFields();
	for(Field m:md1) {
		System.out.println(m);
//		拿到的是全类名,而且还有object里面的方法,重新的接口方法,但是没有私有方法
	}
	System.out.println("---------------------------------");
//获取代表对象
	try {
		Object in=perClass1.newInstance();
		person pp=(person) in;
		pp.systest1();
	} catch (InstantiationException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
}
}

person

package reflect;

public class person implements myinterface,myinterface2{
private int age;
private String name;
public int hhqq;
private void privatemethod() {
	System.out.println("私有方法");
}
	@Override
public String toString() {
	return "person [age=" + age + ", name=" + name + "]";
}
	public person(int age, String name) {
	super();
	this.age = age;
	this.name = name;
}
	private person( String name) {
	super();
	this.name = name;
}
	public person(int age) {
	super();
	this.age = age;

}
	public person() {
	super();
	// TODO Auto-generated constructor stub
}
	public int getAge() {
	return age;
}
public void setAge(int age) {
	this.age = age;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
	@Override
	public void systest() {
		// TODO Auto-generated method stub
		System.out.println("test myinterface");
	}
	@Override
	public void systest1() {
		// TODO Auto-generated method stub
		System.out.println("test myinterface2");
	}

}

接口

package reflect;

public interface  myinterface {
public void systest();
}
package reflect;

public interface  myinterface2 {
public void systest1();
}


通过反射操纵对象

先拿到反射入口,然后拿到反射对象,然后getDeclaredField,对象.方法操作属性
注意因为属性是私有的需要通过setAccessible(true),然反射可以操纵他
getDeclaredField(属性)
set(操作对象,值)

代码

package reflect;

import java.lang.reflect.Field;

public class 通过反射操纵对象 {
	public static void demo1() {
		Class<?> p1 = reflect.person.class;
//	System.out.println(p1);
		try {
			Object in = p1.newInstance();
			person pp = (person) in;
//		pp.systest1();
			pp.setAge(10);
			pp.setName("zs");
			System.out.println(pp);
			System.out.println("===============");
			System.out.println(pp.getAge() + "," + pp.getName());
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void demo2() {
		Class<?> p1 = reflect.person.class;
		try {
			Object in = p1.newInstance();
			person pp = (person) in;
                        访问,person里面age属性
			Field f = p1.getDeclaredField("age");
			/*
			 * private 是本类才能,这里不能访问 f.set(pp, 10); System.out.println(pp.getAge());
			 */
//		修改属性访问权限
			f.setAccessible(true);
                        给age设置值10,
			f.set(pp, 10);
			System.out.println(pp.getAge());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
//同理。给方法,用Method.setAccessible(true);,然后 f.invork();
	public static void main(String[] args) {
		demo1();
		demo2();
	}
}

通过反射操作构造方法

package reflect;

import java.lang.reflect.Constructor;

public class 操纵构造方法 {
public static void main(String[] args) {
	Class<?> p1=reflect.person.class;
//	System.out.println(p1);

try {
//	公共
	Constructor<?> con=p1.getConstructor(int.class);
	System.out.println(con);
//	私有
	Constructor<?> con1=p1.getDeclaredConstructor(String.class);
    System.out.println(con1);
//    
    Constructor<?> con2=p1.getConstructor();

		person inst=(person)con2.newInstance();
	System.out.println(inst);
//	
	con1.setAccessible(true);
	person inst1=(person)con1.newInstance("zs");
	
System.out.println(inst1);
} catch (NoSuchMethodException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

}
}

面试题目

1.   描述一下JVM加载class文件的原理机制?

答:JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。

2. 利用反射和重载完成以下功能

1)创建Student类,类中有属性name和age并封装属性

2)重载Student的构造函数,一个是无参构造并,另一个是带两个参数的有参构造,要求在构造函数打印提示信息

3)创建带main函数的NewInstanceTest类,利用Class类得到Student对象

4)通过上述获取的Class对象分别调用Student有参函数和无参函数

3. 利用反射的知识完成下面的操作

1)创建Mytxt类,创建myCreate()方法完成创建文件。创建带main方法的NewInstanceTest类,通过Class类获取Mytxt对象,调用myCreat()

4. 利用Annotation和反射知识完成操作

1)自定义一个有效的Annotation注释名为MyAnnotation,其中有属性myname创建Student类并重写toString(),toString()要求使用三个基本的Annotation和自定义的MyAnnotation注释

2)创建TestGetAnno类,打印出Student类的toString方法的所有注释

5. 利用通过反射修改私有成员变量

1.   定义PrivateTest类,有私有name属性,并且属性值为hellokitty,只提供name的getName的公有方法

2.   创建带有main方法ReflectTest的类,利用Class类得到私有的name属性

3.   修改私有的name属性值,并调用getName()的方法打印name属性值

6. 利用反射和File完成以下功能

1.   利用Class类的forName方法得到File类

2.   在控制台打印File类的所有构造器

3.   通过newInstance的方法创建File对象