-
反射机制
反射机制:
①可以构造任意一个类的对象。
②可以获取任意一个对象所属类的信息。
③可以调用任意一个类的成员变量与方法。
④可以获取任意一个对象的属性与方法。反射可以理解为使用类的另一种方式:
①原本的方式:
1)利用构造函数创建一个类的对象。
2)获取这个对象的属性值、给对象的属性赋值。
3)调用该类的方法操作该类。①使用反射:
1)获取类的字节码文件。
2)调用Class类中相关的方法获取指定的成员对象(构造方法、成员变量、成员方法)。
3)调用成员对象的相关方法使用对应的成员。 -
Class类
通过Class类获取类中的字节码文件对象。
三种实例化Class对象的三种方式:
1)通过完整类名获取。Class.forName("完整类名")
1)通过对象获取
对象.getClass()
1)通过类名获取
类名.class()
使用实例:
可以发现三种方式得到结果是一样的,
//获取A字节码文件对象,使用较多
Class claZz1= Class.forName("N_Reflect.Ex01.A");
//调用GetClass获取
Class claZz2 = new A().getClass();
//通过静态属性.class获取
Class claZz3 = A.class ;
//同一个字节码文件
System.out.println(claZz1 == claZz2);
System.out.println(claZz2 == claZz3);
System.out.println("类名:"+ claZz1.getName());
System.out.println("类名:"+ claZz2.getName());
System.out.println("类名:"+ claZz3.getName());
Class类常用方法:
常用于将Class类对象实例化为自定义类对象,即可以通过一个给定的字符串(全类名)实例化一个本类的对象,可以通过无参、有参构造方法实例化对象。
public static Class<?> forName(String className) //实例化Class对象。
public Constructor[] getConstructors()//获取类中的所有方法。
public Field[] getDeclaredFields()//获取本类全部属性。
public Fileld[] getFileds()//获取继承而来的全部属性。
public Method[] getMethods()//获取类中的全部方法。
public Method getMethod(String name, Class...parmeterType)//获取Method对象并设置一个方法中的所有参数类型。
public Class[] getInterfaces()//获取类中的全部接口。
public String getName()//获取类的完整(包.类)名。
public Package getPackage()//得到一个类的包。
public Class getSuperclass()//得到一个类的父类。
public Object newInstance()//根据Class定义的类实例化对象。
public Class<?> getComponentType() 返回数组类型的Class。
public boolean isArray() //判断此Class是否是一个数组。
Constructor类常用方法:
Constructor类用于存储本类的构造方法。
public getModifiers()//获取构造方法的修饰符。
public String getName()//获取构造方法的名称。
publi Class<?>[] getParameterTypes()//获取构造方法中参数的类型。
public String toString()//返回构造方法的信息。
public T newInstance()//向构造方法中传递参数,实例化对象。
Method类常用方法:
需要获取类中的全部方法,可以使用getMethod()方法,该方法返回一个Method类的对象数组,可以通过Method类进一步获取方法的具体信息。
public int getModifiers()//获取方法的修饰符
public String getName()//获取方法名称
public Class<?>[] getParamterTypes()//获取方法的全部参数类型。
public Class<?> getReturnType() //获取方法的返回值类型
public Class<?> getExceptionType()//获取方法的全部抛出异常
public Class<?>[] getExceptionType()//通过反射调用类中的方法
Field类常用方法:
使用Field类可以获取类的全部属性,有两个部分:父类继承的属性、本类的属性。
1)public Field[] getFields()//获取实现的接口、父类的公共属性。
2)public Field[] getDeclaredFields()//获取本类全部属性。
public int getModifiers()//获取本属性的修饰符
public String getName()//得到属性的名称
public boolean isAccessible()//判断属性是否可被外部调用
public void setAccessible(Boolean flag)//设置一个属性是否能被外部嗲用
public String toString()//返回Filed类的信息
public Object get(Object obj)//获取对象中的具体内容。
public void set(Object obj,Object value)//设置对象属性内容
- 实例化对象
1)无参构造实例化对象,即使用newInstance()方法。
package N_Reflect.Ex02;
import java.time.Period;
class Person{
private String name;
private int age;
// public Person(String name,int age) {
// super();
// }
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Ex_02 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//获取字节码文件对象
Class clazz = Class.forName("N_Reflect.Ex02.Person");
//创建对象
Person per = null;
// 如果没有无参的构造方法会报错,所以要求必须要有无参的构造方法
//(默认有一个无参的构造方法,如果新增一个有参的构造方法,
// 还需要使用无参的必须再定义一个无参的构造方法)。
per = (Person) clazz.newInstance();//实例化对象。
per.setAge(20);
per.setName("耶耶");
System.out.println(per);
}
}
2)有参构造实例化对象,getConstructors()和.newInstance()结合使用。
package N_Reflect.Ex03;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {
return age;
}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Ex_03 {
//通过有参构造方法
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
//获取字节码文件对象
Class clazz = Class.forName("N_Reflect.Ex03.Person");
Constructor[] constructors = clazz.getConstructors();
Person per = (Person) constructors[0].newInstance("zhangsan", 20);//参数对应构造方法的参数
System.out.println(per);
}
}
3)获取所有实现的接口,getInterfaces()方法使用。
package N_Reflect.Ex04;
interface Country{}
interface City{}
class Person implements Country, City{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Ex_04 {
public static void main(String[] args) throws ClassNotFoundException {
//获取所实现的全部接口
Class clazz = Class.forName("N_Reflect.Ex04.Person");
Class[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println("实现的接口名称:"+anInterface.getName());
}
}
}
4)获取所有方法,getMethods()方法。
package N_Reflect.Ex05;
import java.lang.reflect.Method;
interface Country{
public abstract void sayHello();
}
class Person implements Country {
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
@Override
public void sayHello() {
System.out.println("say Hello......");
}
}
public class Ex_05 {
//获取全部方法
public static void main(String[] args) throws ClassNotFoundException {
//获取字节码文件
Class clazz = Class.forName("N_Reflect.Ex05.Person");
//获取成员方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println("方法名称"+method.getName());//会有其他的Object方法,因为都继承Object。
}
}
}
5)获取所有属性,.getDeclaredFields()方法。
package N_Reflect.Ex06;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
class Person{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class EX_06 {
//获取全部属性
public static void main(String[] args) throws ClassNotFoundException {
//获取字节码文件
Class clazz = Class.forName("N_Reflect.Ex06.Person");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("属性名称:"+ field.getName()+",属性类型:"+ field.getType()+",属性修饰符"+ Modifier.toString(field.getModifiers()));
}
}
}
6)利用反射重写toString。
package N_Reflect.EX07_toString;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
}
public class StringUtils {
public String toString(Object obj) {
//获取该对象的字节码文件
Class clazz = obj.getClass();
//创建StringBuilder对象
StringBuilder sb = new StringBuilder();
//获取包所在包
Package packageName = clazz.getPackage();
sb.append("包名:"+packageName.getName()+"\n");
String simpleName = clazz.getSimpleName();
sb.append("类名:"+simpleName+"\n");
sb.append("公共的构造方法:\n");
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
final String modifier=Modifier.toString(constructor.getModifiers());
if (modifier.contains("public")){
sb.append(constructor.toGenericString()+"\n");//获取基本信息
}
}
//获取共有成员变量
sb.append("公共的Field:\n");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String modifier = Modifier.toString(field.getModifiers());
if (modifier.contains("public")){
sb.append(field.toGenericString()+"\n");
}
}
//获取共有成员方法
sb.append("公共的方法:\n");
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String modifier = Modifier.toString(method.getModifiers());
if (modifier.contains("public")){
sb.append(method.toGenericString()+"\n");
}
}
return sb.toString();
}
public static void main(String[] args) {
StringUtils stringUtils = new StringUtils();
//Object
System.out.println(stringUtils.toString(new Object()));
//其他方法
Person person = new Person();
System.out.println(stringUtils.toString(person));
}
}
7)模拟获取普通用户与Vip用户下载速度(●’◡’●)…。
package N_Reflect.Ex08;
import java.util.Scanner;
interface Common {
int getDownload(int speed);
}
class Consumer implements Common {
@Override
public int getDownload(int speed) {
return 128;
}
}
class Vip implements Common{
@Override
public int getDownload(int speed) {
return speed;
}
}
public class Download {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Scanner in = new Scanner(System.in);
System.out.println("输入用户角色:Vip/Consumer");
String username = in.nextLine();//Vip Consumer
int speed = 10000;
String user = "N_Reflect.Ex08." + username;
Common common = (Common) Class.forName(user).newInstance();
System.out.println("userSpeed:" + common.getDownload(speed));
}
}
8)通过反射读取配置文件进行类的实例化。
①新建Person类
package N_Reflect.Ex09;
public class Person {
public void sleep(){
System.out.println("Person....sleep............");
}
}
②新建Student类
package N_Reflect.Ex09;
public class Student {
public void sleep(){
System.out.println("Student....sleep............");
}
}
③新建test.properties文件,需要注意路径,需要带包名,maven可以放在resources目录下。
className=N_Reflect.Ex09.Student
methodName=sleep
④新建测试类
package N_Reflect.Ex09;
import java.lang.reflect.Method;
import java.util.Properties;
public class TestSleep {
public static void main(String[] args) throws Exception {
//加载test.properties中的内容并存储到Properties集合。
Properties properties = new Properties();
properties.load(TestSleep.class.getResourceAsStream("/config/test.properties"));
//获取数据
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
//获取字节码文件
Class clazz = Class.forName(className);
//创建类的对象
Object obj = clazz.newInstance();
//获取指定的方法对象,
Method method = clazz.getMethod(methodName);
//执行该成员方法
method.invoke(obj);//通过obj调用指定方法
}
}
⑤修改配置文件的参数执行测试,查看变化可以根据配置文件内容进行实例化。