文章目录
反射
反射机制概述
反射前与反射后的操作
- 反射之前对Person类的操作
- 创建Person类的对象
- 通过对象,调用其内部的属性,方法.
- 在Person类外部,不可以通过Person类的对象调用其内部的私有结构.比如name,showNation()方法以及私有的构造器
package com.zzb.Reflection;
public class Demo1 {
//反射之前对Person类的操作
public static void main(String[] args) {
//1.创建Person类的对象
Person person = new Person("至尊宝", 18);
//2.通过对象,调用其内部的属性,方法.
person.age = 10;
System.out.println(person.toString());
person.show();
//在Person类外部,不可以通过Person类的对象调用其内部的私有结构.
//比如name,showNation()方法以及私有的构造器
}
}
class Person {
private String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
public Person() {
}
public void show() {
System.out.println("我是齐天大圣");
}
private String showNation(String nation) {
System.out.println("我的国籍是" + nation);
return nation;
}
}
- 反射之后对Person类的操作
- 通过反射,创建Person类的对象
- 通过反射,调用对象指定的属性,方法.
- 通过反射,可以调用Person类的私有结构.比如:私有的构造器,方法,属性.
package com.zzb.Reflection;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Demo1 {
//反射之前对Person类的操作
public static void main(String[] args) {
//1.创建Person类的对象
Person person = new Person("至尊宝", 18);
//2.通过对象,调用其内部的属性,方法.
person.age = 10;
System.out.println(person.toString());
person.show();
//在Person类外部,不可以通过Person类的对象调用其内部的私有结构.
//比如name,showNation()方法以及私有的构造器
}
@Test//反射之后,对于Person类的操作
public void test() throws Exception {
//1.通过反射,创建Person类的对象
Class personClass = Person.class;
Constructor constructor = personClass.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("至尊宝", 24);
Person p = (Person) obj;
System.out.println(p.toString());
//2.通过反射,调用对象指定的属性,方法.
//调用属性
Field age = personClass.getDeclaredField("age");
age.set(p, 10);
System.out.println(p);
//调用方法
Method show = personClass.getDeclaredMethod("show");
show.invoke(p);
System.out.println("-------------------");
//通过反射,可以调用Person类的私有结构.比如:私有的构造器,方法,属性.
//调用私有的构造器
Constructor cons1 = personClass.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person tom = (Person) cons1.newInstance("Tom");
System.out.println(tom);
//调用私有的属性
Field name = personClass.getDeclaredField("name");
name.setAccessible(true);
name.set(tom, "Jone");
System.out.println(tom);
//调用私有的方法
Method showNation = personClass.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String str = (String) showNation.invoke(p, "花果山");
System.out.println("str = " + str);
}
}
class Person {
private String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
public Person() {
}
public void show() {
System.out.println("我是齐天大圣");
}
private String showNation(String nation) {
System.out.println("我的国籍是" + nation);
return nation;
}
}
反射和封装性
- 疑问:通过直接new的方式或反射的方式都可以调用公共的结构.开发中到底用哪个?
- 建议:直接new的方式
- 什么时候会使用:反射的方式.反射的特征:动态性(编译时无法确定new哪个类的对象,就用反射的方式.)
- 疑问:反射机制与封装性是不是矛盾的?如何看待两个技术?
- 不矛盾.如何看到反射和封装性
关于java.lang.Class类的理解
- 类的加载过程:
- 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾),接着我们使用java.exe命令对某个字节码文件进行解释运行.相当于将某个字节码文件加载到内存中,此过程就称为类的加载.加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例.换句话说,Class的实例就对应着一个运行时类.
获取Class实例的四种方式
- 前三种掌握,第四种了解
- 方式一:调用运行时类的属性 .class
- 方式二:通过运行时类的对象,调用getClass()
- 方式三:调用Class的静态方法:forName(String classPath)(方式三使用较多,更好的体现了动态性)
- 方式四:使用类的加载器:ClassLoader(了解)
package com.zzb.Reflection;
public class Demo2 {
public static void main(String[] args) throws Exception {
//方式一:调用运行时类的属性 .class
Class<Person> personClass = Person.class;
System.out.println(personClass);
//方式二:通过运行时类的对象,调用getClass()
Person person = new Person();
Class aClass = person.getClass();
System.out.println(aClass);
//方式三:调用Class的静态方法:forName(String classPath)
Class forName = Class.forName("com.zzb.Reflection.Person");
System.out.println(forName);
//方式四:使用类的加载器:ClassLoader(了解)
ClassLoader classLoader = Demo2.class.getClassLoader();
Class loadClass = classLoader.loadClass("com.zzb.Reflection.Person");
System.out.println(loadClass);
System.out.println(loadClass == personClass);
}
}
- 哪些类算是Class对象
- 只要数组的元素类型和维度一样,就是同一个Class
- a和b数组都是一维的int数组,所以输出结果为true.
使用ClassLoader加载配置文件
通过反射创建运行时类的对象
- 通过反射创建对应的运行时类的对象
- newInstance():调用此方法,创建对应的运行时类的对象
要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够,通常,设置为public. - 在javabean中要求提供一个public的空参构造器,原因:
- 便于通过反射,创建运行时类的对象
- 便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器.