文章目录
一、反射
Java里面的反射可以帮助我们在运行程序时候加载、使用编译期间完全未知的class,简单来说就是Java可以加载一个运行时候才得知名称的class,获得其完整的构造,并生成实例化对象,对其成员变量赋值,调用其方法等等。
我的理解:反射就是将一个类的成员映射成相对应的类型,也包括该类本身
。
反射和类加载的区别
RTTI(Run Time Type Identification)即通过运行时类型识别,对RTTI来说,编译器会在编译期打开和检查.class文件。但对反射来说,.class文件是由运行时环境打开和检查。
反射关键类图
生成对象的步骤
1.正常new对象:
1.编译期加载.class文件
2.查找构造函数
3.通过构造函数创建对象
2.反射:
1.运行期加载.class文件
2.创建构造函数
3.通过构造函数创建对象
示例
1.Person类
public class Person {
public String name = "com/xiaoMao";
protected Integer age = 1;
private Byte sex = (byte) 1;
Boolean isMarriage = true;
// 无参数
public Person() {
}
// 有参数
public Person(String name, Integer age, Byte sex, Boolean isMarriage) {
this.name = name;
this.age = age;
this.sex = sex;
this.isMarriage = isMarriage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Byte getSex() {
return sex;
}
public void setSex(Byte sex) {
this.sex = sex;
}
public Boolean getMarriage() {
return isMarriage;
}
public void setMarriage(Boolean marriage) {
isMarriage = marriage;
}
private String privateMethod() {
return "This is private method!";
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", isMarriage=" + isMarriage +
'}';
}
}
2.Test类
public class ReflectionTest {
/**
* 示例:创建Class对象的3种方式
*/
@Test
public void test() throws Throwable {
// 方式一 类.class
Class personClazz = Person.class;
// 方式二 实例.getClass()
Person person = new Person();
Class personClazz1 = person.getClass();
// 方式三 Class.forName("类的全路径")
Class personClazz2 = Class.forName("com.xiaoMao.reflect.Person");
System.out.println(personClazz == personClazz1);
System.out.println(personClazz == personClazz2);
}
/**
* 示例:通过Class创建实例对象
* <p>
* // 无参数
* <bean id="person" class="com.xiaoMao.reflect.Person" />
* <p>
* // 有参数
* <bean id="person" class="com.xiaoMao.reflect.Person" >
* <constructor-arg index="0" type="java.lang.String" value="xiaoMao"/>
* </bean>
*/
@Test
public void test2() throws Throwable {
/** 首先:获得Person的字节码 */
Class personClazz = Class.forName("com.xiaoMao.reflect.Person");
/** 其次:通过Class对象,创建构造方法对象 */
Constructor constructor1 = personClazz.getConstructor(); // 初始化无参构造方法
Constructor constructor2 = personClazz.getConstructor(String.class, Integer.class, Byte.class,
Boolean.class); // todo 初始化有参构造方法对象,注意这里获得有参构造方法是传参数类型不是传具体的参数值
/** 最后:通过构造方法创建对象 */
// 调用无参数构造方法创建Person对象
Person person1 = (Person) constructor1.newInstance();
person1.setName("xiaoMao1");
System.out.println("person1=" + person1);
// 调用有参数构造方法创建Person对象
Person person2 = (Person) constructor2.newInstance("xiaoMao2", 10, (byte) 1, true);
System.out.println("person2=" + person2);
/** 补充内容:反射通过私有构造方法创建对象,破坏单例模式 */
Class singletonPersonClazz = SingletonPerson.class;
// getxxx 不能访问private属性(方法),会报异常,找不到该方法(这里是构造方法):java.lang.NoSuchMethodException
// Constructor constructor3 = singletonPersonClazz.getConstructor();
//想要访问私有(属性或方法)必须使用getDeclaredxxx方法,若想访问(改变)原来的值,必须在之后setAccessible(true)
Constructor constructor3 = singletonPersonClazz.getDeclaredConstructor();
constructor3.setAccessible(true);
SingletonPerson singletonPerson = (SingletonPerson) constructor3.newInstance();
SingletonPerson singletonPerson1 = SingletonPerson.getInstance();
SingletonPerson singletonPerson2 = SingletonPerson.getInstance();
System.out.println("singletonPerson==singletonPerson1 is " + (singletonPerson == singletonPerson1));
System.out.println("singletonPerson==singletonPerson2 is " + (singletonPerson == singletonPerson2));
System.out.println("singletonPerson1==singletonPerson2 is " + (singletonPerson1 == singletonPerson2));
}
/**
* public属性的Field
*/
@Test
public void test3() throws Throwable {
// 第一步:获得Class
Class personClazz = Person.class;
// 第二步:获得构造方法
Constructor<