反射--通过获取Class类型的对象从而文件中的成员变量/成员方法/构造方法并执行
类名.class通过类名的属性class获取,多用于参数的传递
对象.getClass(),通过对象的getClass()方法获取,多用于获取字节码的方式
Class.forName("全类名")获取字符串路径,用于配置文件,将类名定义在配置文件中
### 类的加载器
(1)BootstrapClassLoader 根类加载器,无法获取 比如System,String等。
(2)ExtClassLoader 扩展类加载器-jar包的加载
(3)AppClassLoader 系统类加载器-java写的
三者之间不存在继承关系,最终的父类 java.lang.ClassLoader
### 类的加载时机
public class Person {
public static int NUM = 100;
static {
System.out.println("Person 静态代码块执行了...");
}
public static void method() {
System.out.println(NUM);
}
}
public class Student extends Person {
static {
System.out.println("Student...代码块执行了....");
}
}
*/
public class Demo02LoadClass {
public static void main(String[] args) throws ClassNotFoundException {
类(类的.class文件)的加载时机
1. 创建类的实例。
2. 类的静态变量,或者为静态变量赋值。
3. 类的静态方法。
Student stu = new Student();
6. 直接使用java.exe命令来运行某个主类。
}
}
1获取类加载器 ClassLoader=String/DNSNameService/Demo03ClassLoader.class.getClassLoader();
2getParent(): 返回委托的父类加载器。 ClassLoader p = c.getParent();
3获取Class类型 getSimpleName(): 获得简单类名,只是类名,没有包
4获取Class类型 @1getName(): 获取完整类名,包含包名+类名
返回与带有给定字符串名的类或接口相关联的 Class 对象。
@2建议使用forName(String className)
参数: String className
User user = new User();
Class c3 = Class.forName("domain.User");
5newInstance()创建class新实例要求:类必须有public的无参数构造方法
newInstance() 空参构造方法创建对象。
newInstance(Object... initargs) 根据指定参数创建对象。
6Constructor是构造方法类,用来实例化对象。
Constructor getConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,只能获得public修饰的构造方法。
如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常
参数是可变参数,调用此方法时,可以不写参数,获取的空参构造
可以写参数,给定的参数必须是Class对象
比如: 参数 String name,int age
调用此方法: String.class,int.class
7.指定参数私有构造方法对象调用setAccessible方法,取消 Java 语言访问检查 con.setAccessible(true);
false,实施 Java 语言访问检查private 有效 true 取消 Java 语言访问检查 private 失效
8 Method类通过Method对象可以调用方法。
getMethods()数组 getMethod getDeclaredMethod可以获取private的
9invoke ---Object invoke(Object obj, Object... args)
根据参数args调用对象obj的该成员方法 如果obj=null,则表示该方法是静态方法
Object value = setNameMethod.invoke(user, "张三");
String name = (String) getNameMethod.invoke(user);
char[] chs = (char[]) m.invoke(user,"helloworld");
System.out.println(new String(chs));
10 ClassLoader的子类 InputStream getResourceAsStream(String name): 返回读取指定资源的输入流。
如果配置文件写在src根下: String name: 只需要写文件名.扩展名 config.properties
如果配置文件写在src/itheima02下: String name: itheima02/config.properties
11 ResourceBundle类:获取资源的类
注意: 该类是抽象类,不能直接创建对象,可以创建子类对象
getBundle(String baseName): 用于获取该抽象类的子类对象
参数: String baseName: 如果配置文件写在src根下,此处只需要写文件名(不需要写扩展名)
getString(String key): 根据String类型的属性名,获取String类型属性值(根据键找值)
public class Demo04GetConstructor {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("domain.User");
Constructor<?>[] cons = clazz.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
System.out.println("----------------");
Constructor<?> con1 = clazz.getConstructor();
System.out.println(con1);
getConstructor(Class... parameterTypes)调用此方法时,可以不写参数,获取的空参构造可以写参数,给定的参数必须是Class对象 比如: 参数 String name,int age 调用此方法: String.class,int.class
Constructor<?> con2 = clazz.getConstructor(String.class, int.class);
System.out.println(con2);
Constructor<?> con4 = clazz.getDeclaredConstructor(int.class);
System.out.println(con4);
getDeclaredConstructors 获取private所有的构造方法
}
}
获取空参构造方法并运行
获取到了空参构造方法对象
Constructor con = ...;
Object obj = con.newInstance();
获取到了满参构造方法对象 Constructor con = ...;
Object obj = con.newInstance("zhangsan",18);
public class Demo05NewInstance {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("domain.User");
反射带参构造方法并运行
Constructor con = clazz.getConstructor();
User user = (User) con.newInstance("张三",18);
System.out.println(user);
}
}
获取public修饰符的所有成员方法
获取public修饰的名称为toString的没有参数的方法
获取public修饰的名称为setName的参数为String类型的方法
获取public修饰的名称为getSum的参数为两个int类型的方法
获取public修饰的名称为my2CharArray的参数为String类型的方法
public class Demo01GetMethod {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("domain.User");
Method[] ms = clazz.getMethods();
for (Method m : ms) {
System.out.println(m);
}
System.out.println("----------------");
Method m1 = clazz.getMethod("toString");
System.out.println(m1);
Method m2 = clazz.getMethod("setName", String.class);
System.out.println(m2);
Method m3 = clazz.getMethod("getSum", int.class, int.class);
System.out.println(m3);
Method m5 = clazz.getDeclaredMethod("my2CharArray", String.class);
System.out.println(m5);
}
}
反射案例 写一个"框架"不改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
步骤: 1.定义配置文件config.properties,以属性名=属性值
className=itheima02.Dog
methodName=eat
注意: 配置文件config.properties必须写在src根路径下
src下写的java源代码,项目完成后,给客户的是.class文件
配置文件会跟着.class文件,到类路径(存储.class文件的路径)下,同步的
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼...");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头....");
}
}
public class Demo03ReflectTest {
之前 1 props.load(new FileInputStream("day14\\src\\config.properties"));
Properties props = new Properties();
ClassLoader classLoader = Demo03ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("config.properties");
props.load(is);
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
}
}
public class Demo04ReflectTest {
public static void main(String[] args) throws Exception {
ResourceBundle resourceBundle = ResourceBundle.getBundle("config");
String className = resourceBundle.getString("className");
String methodName = resourceBundle.getString("methodName");
Class<?> clazz = Class.forName(className);
Method eatMethod = clazz.getMethod("eat");
Object obj = clazz.newInstance();
eatMethod.invoke(obj);
}
}