JVM类加载流程和内存结构
类编译器将java源文件编译成class文件,类加载器ClassLoader将class文件加载到jvm
反射类图
生产对象步骤
// 编译期加载Person.class文件->查找Person()构造函数->通过构造函数创建对象
Person person = new Person();
// 运行期加载Person.class文件->创建构造函数Person()->通过构造函数创建对象
Class personClazz = Class.forName("com.tqq.Person");
// 初始化无参构造方法
Constructor constructor = personClazz.getConstructor();
Person person = (Person) constructor.newInstance();
// 初始化有参构造方法对象
Constructor constructor2 = personClazz.getConstructor(String.class, Integer.class, Byte.class, Boolean.class);
// 调用有参数构造方法创建Person对象
Person person2 = (Person) constructor2.newInstance("muse2", 10, (byte) 1, true);
创建Class对象的3种方式
// 方式一 类.class
Class personClazz = Person.class;
// 方式二 实例.getClass()
Person person = new Person();
Class personClazz1 = person.getClass();
// 方式三 Class.forName("类的全路径")
Class personClazz2 = Class.forName("com.tqq.reflect.Person");
Class文件包含的内容
类的属性、类的方法、类的字段、实现的接口、父类
魔数、小版本号、大版本号、常量池、访问标记、当前类
反射的应用
BeanUtils工具可以将一个对象属性相同的值赋值给另一个对象。
public static void convertor(Object originObj, Object targetObj) throws Throwable {
// 第一步,获得class对象
Class orginClazz = originObj.getClass();
Class targetClazz = targetObj.getClass();
// 第二步,获得Field
Field[] orginFields = orginClazz.getDeclaredFields();
Field[] targetFields = targetClazz.getDeclaredFields();
// 第三步:赋值
for (Field originField : orginFields) {
for (Field targetField : targetFields) {
if (originField.getName().equals(targetField.getName())) {
originField.setAccessible(true);
targetField.setAccessible(true);
targetField.set(targetObj, originField.get(originObj));
}
}
}
}
反射通过私有构造方法创建对象,破坏单例模式
Class singletonPersonClazz = SingletonPerson.class;
// Constructor constructor3 = singletonPersonClazz.getConstructor();
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 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.muse.reflect.Person");
System.out.println(personClazz == personClazz1);
System.out.println(personClazz == personClazz2);
}
/**
* 示例:通过Class创建实例对象
*
* // 无参数
* <bean id="person" class="com.muse.reflect.Person" />
*
* // 有参数
* <bean id="person" class="com.muse.reflect.Person" >
* <constructor-arg index="0" type="java.lang.String" value="muse"/>
* </bean>
*/
@Test
public void test2() throws Throwable{
/** 首先:获得Person的字节码 */
Class personClazz = Class.forName("com.muse.reflect.Person");
/** 其次:通过Class对象,创建构造方法对象 */
Constructor constructor1 = personClazz.getConstructor(); // 初始化无参构造方法
Constructor constructor2 = personClazz.getConstructor(String.class, Integer.class, Byte.class,
Boolean.class); // 初始化有参构造方法对象
/** 最后:通过构造方法创建对象 */
// 调用无参数构造方法创建Person对象
Person person1 = (Person) constructor1.newInstance();
person1.setName("muse1");
System.out.println("person1=" + person1);
// 调用有参数构造方法创建Person对象
Person person2 = (Person) constructor2.newInstance("muse2", 10, (byte) 1, true);
System.out.println("person2=" + person2);
/** 补充内容:反射通过私有构造方法创建对象,破坏单例模式 */
Class singletonPersonClazz = SingletonPerson.class;
// Constructor constructor3 = singletonPersonClazz.getConstructor();
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<Person> constructor = personClazz.getConstructor();
Person person = constructor.newInstance(); // 初始化生成Person对象
// 第三步:通过Class对象,获得Field对象 Person[类]的name属性。
Field nameField = personClazz.getField("name");
// 第四步:操作Field,获得属性值
String name = String.valueOf(nameField.get(person));
System.out.println(name);
}
/**
* private属性Field
*/
@Test
public void test4() throws Throwable{
// 第一步:获得Class
Class personClazz = Person.class;
// 第二步:获得构造方法
Constructor<Person> constructor = personClazz.getConstructor();
Person person = constructor.newInstance();
// 第三步:通过Class对象,获得Field对象
Field sexField = personClazz.getDeclaredField("sex");
sexField.setAccessible(true);
// 第四步:操作Field,获得属性值
System.out.println(sexField.get(person));
}
/**
* 通过反射获得类的public属性值
* <p>
* getField 只能获取public的,包括从父类继承来的字段。
* getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不能访问该private字段的值,
* 除非加上setAccessible(true))
*/
@Test
public void getPublicField() throws Throwable {
/** 首先:获得Person的字节码 */
Class personClazz = Person.class;
/** 其次:获得Person对象(由于非静态非private的属性,访问使用 对象.属性方式访问,所以反射必须先获得对象实例)*/
Person person = (Person) personClazz.getConstructor().newInstance();
/** 第三:通过Class对象,获得Field对象 */
// Field nameField = personClazz.getField("name"); // 不报错
Field nameField = personClazz.getDeclaredField("name");
/**
* Field.toString();
* --------------------------------------------------------------------
* public String toString() {
* int mod = getModifiers();
* return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
* + getType().getTypeName() + " "
* + getDeclaringClass().getTypeName() + "."
* + getName());
* }
*
* 【Field的重要方法】
* System.out.println("获取字段的类型:" + nameField.getType());
* System.out.println("获取字段的名字:" + nameField.getName());
* System.out.println("获取字段的访问修饰符:" + Modifier.toString(nameField.getModifiers()));
* System.out.println("获取字段所在类的全路径:" + nameField.getDeclaringClass().getName());
*/
System.out.println(nameField); // protected java.lang.Integer com.muse.Person.name
/** 最后:获取字段的类型 */
String name = String.valueOf(nameField.get(person));
System.out.println(name);
}
/**
* 获得private属性和方法
*
* @throws Throwable
*/
@Test
public void getPrivateField() throws Throwable {
/** 首先:获得Person的字节码 */
Class personClazz = Person.class;
/** 其次:获得Person对象(由于非静态非private的属性,访问使用 对象.属性方式访问,所以反射必须先获得对象实例)*/
Person person = (Person) personClazz.getConstructor().newInstance();
/** 第三:通过Class对象,获得Field对象 */
// Field sexField = personClazz.getField("sex"); // 不能使用getField,否则报错:java.lang.NoSuchFieldException: sex
Field sexField = personClazz.getDeclaredField("sex");
sexField.setAccessible(true); // 必须设置为true
/** 最后:获取字段的类型 */
Byte sex = (Byte) sexField.get(person);
System.out.println("private属性:sex=" + sex);
/** 补充内容:获取private类型的方法 */
// Method method = personClazz.getMethod("privateMethod"); // 不能使用getMethod,否则报错:java.lang.NoSuchMethodException: com.muse.reflect.Person.privateMethod()
Method method = personClazz.getDeclaredMethod("privateMethod");
method.setAccessible(true); // 必须设置为true
System.out.println("private方法:privateMethod()=" + method.invoke(person));
}
/**
* 获得protected属性
*
* @throws Throwable
*/
@Test
public void getProtectedField() throws Throwable {
/** 首先:获得Person的字节码 */
Class personClazz = Person.class;
/** 其次:获得Person对象(由于非静态非private的属性,访问使用 对象.属性方式访问,所以反射必须先获得对象实例)*/
Person person = (Person) personClazz.getConstructor().newInstance();
/** 第三:通过Class对象,获得Field对象 */
// Field ageField = personClazz.getField("age"); // java.lang.NoSuchFieldException: age
Field ageField = personClazz.getDeclaredField("age");
ageField.setAccessible(true); // 必须设置为true,如果不设置,则报错:java.lang.IllegalAccessException: Class ReflectionTest can not access a member of class com.muse.Person with modifiers "protected"
/** 最后:获取字段的类型 */
Integer age = (Integer) ageField.get(person);
System.out.println(age);
}
/**
* 获得default属性
*/
@Test
public void getDefaultField() throws Throwable {
/** 首先:获得Person的字节码 */
Class personClazz = Person.class;
/** 其次:获得Person对象(由于非静态非private的属性,访问使用 对象.属性方式访问,所以反射必须先获得对象实例)*/
Person person = (Person) personClazz.getConstructor().newInstance();
/** 第三:通过Class对象,获得Field对象 */
// Field isMarriageField = personClazz.getField("isMarriage"); // java.lang.NoSuchFieldException: isMarriage
Field isMarriageField = personClazz.getDeclaredField("isMarriage");
isMarriageField.setAccessible(true); // 必须设置为true,如果不设置,则报错:java.lang.IllegalAccessException: Class ReflectionTest can not access a member of class com.muse.Person with modifiers ""
/** 最后:获取字段的类型 */
Boolean isMarriage = (Boolean) isMarriageField.get(person);
System.out.println(isMarriage);
}
}
public class Person {
public String name = "com/muse";
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;
}
}