概述
引入
package ref;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class Ref {
public static void main(String[] args) throws Exception {
//加载properties
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String calsspath= properties.getProperty("classpath");
String methodName=properties.getProperty("method");
// System.out.println(method);
// System.out.println(calss);
//使用反射机制解决
//(1) 加载类, 返回Class类型的对象cls
Class cls=Class.forName(calsspath);
//实例化对象
Object o = cls.newInstance();
//通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi" 的方法对象
//即:在反射中,可以把方法视为对象(万物皆对象
Method method = cls.getMethod(methodName);
method.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)
//得到字段
//getfield 不能得到私有的字段,只能得到共有的字段
// Field name = cls.getField("name");
Field age = cls.getField("age");
System.out.println(age.get(o));
//得到构造器
Constructor constructor = cls.getConstructor();//()中可以指定参数,返回无参构造器
Constructor constructor1 = cls.getConstructor(String.class);//String.class 就是 String类的class 对象
System.out.println(constructor1);
}
}
原理
优化
优缺点
优点:
- 可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就是去底层支持
缺点:
- 使用反射基本是解释执行,对执行速度有影响
- 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。
Class类
常用方法
类型 | 访问方法 | 返回值类型 | 说明 |
---|---|---|---|
包路径 | getPackage() | Package 对象 | 获取该类的存放路径 |
类名称 | getName() | String 对象 | 获取该类的名称 |
继承类 | getSuperclass() | Class 对象 | 获取该类继承的类 |
实现接口 | getlnterfaces() | Class 型数组 | 获取该类实现的所有接口 |
构造方法 | getConstructors() | Constructor 型数组 | 获取所有权限为 public 的构造方法 |
getDeclaredContruectors() | Constructor 对象 | 获取当前对象的所有构造方法 | |
方法 | getMethods() | Methods 型数组 | 获取所有权限为 public 的方法 |
getDeclaredMethods() | Methods 对象 | 获取当前对象的所有方法 | |
成员变量 | getFields() | Field 型数组 | 获取所有权限为 public 的成员变量 |
getDeclareFileds() | Field 对象 | 获取当前对象的所有成员变量 | |
内部类 | getClasses() | Class 型数组 | 获取所有权限为 public 的内部类 |
getDeclaredClasses() | Class 型数组 | 获取所有内部类 | |
内部类的声明类 | getDeclaringClass() | Class 对象 | 如果该类为内部类,则返回它的成员类,否则返回 null |
String classpath="learn.Car";
//<?>代表不确定的cls
Class<?> cls = Class.forName(classpath);
System.out.println(cls);//显示的时cls对象是那个类的Class对象 class learn.Car
System.out.println(cls.getClass());//显示的是cls的运行类型class java.lang.Class
//得到包名
System.out.println(cls.getPackage());//package learn
System.out.println(cls.getPackage().getName());//learn
//得全类名
System.out.println(cls.getName());//learn.Car
//通过cls创建实例
Car car = (Car)cls.newInstance();
car.setName("宝马");
System.out.println(car.getName());
//获取属性,但属性要是共有的
Field weight = cls.getField("weight");
System.out.println(weight.get(car));
//设置属性
weight.set(car,200);
System.out.println(weight.get(car));
//得到所有的字段属性,也是public
Field[] fields = cls.getFields();
System.out.println(fields.length);//1
for (Field field:
fields) {
System.out.println(field.getName());
}
得到Class对象的方法
//1.Class.forName 往往通过配置文件读取到
String classpath="learn.Car";
Class<?> cls = Class.forName(classpath);
System.out.println(cls);
System.out.println(cls.hashCode());
//2.类名.class 多用于参数传递
Class<Car> cls2 = Car.class;
System.out.println(cls2);
System.out.println(cls2.hashCode());
//3.通过对象名来获取 对象名.getclas
Car car=new Car();
Class cls3=car.getClass();
System.out.println(cls3);
System.out.println(cls3.hashCode());
//4.通过类加载器(4种),来获取
// 1,先得到类加载器
ClassLoader classLoader = car.getClass().getClassLoader();
// 2,通过类加载器得到类对象
Class<?> cls4= classLoader.loadClass(classpath);
System.out.println(cls4);
System.out.println(cls4.hashCode());
//5.基本数据类型也可以 int.class
Class<Integer> integerClass = int.class;
System.out.println(integerClass);//int
//6.基本数据类型的包装类 Integer.TYPE
Class<Integer> type = Integer.TYPE;
System.out.println(type);//int
System.out.println(integerClass.hashCode());
System.out.println(type.hashCode());//Integer.TYPE和int.class二者是一样的,底层通过拆箱和装箱是同一个
那些类型有Class对象
Class<String> stringClass = String.class;//外部类
Class<Serializable> serializableClass = Serializable.class;//接口类
Class<int[]> aClass = int[].class;//数组类
Class<Deprecated> deprecatedClass = Deprecated.class;//注解类
Class<Thread.State> stateClass = Thread.State.class;//枚举类
Class<Integer> integerClass = int.class;//基本数据类型类
Class<Integer> integerClass1 = Integer.class;//基本数据类型包装类类
Class<Void> voidClass = void.class;//void 类
Class<Class> classClass = Class.class;//Class类,也是一种外部类
通过反射获取类的结构信息
Class类
package class_;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Class07 {
public static void main(String[] args) {
}
@Test
public void api01() throws ClassNotFoundException {
Class<?> peopleClass = Class.forName("class_.People");
//获得全类名
System.out.println(peopleClass.getName());//class_.People
//获得简单类名
System.out.println(peopleClass.getSimpleName());//people
//获取本类以及父类的所有公共属性
Field[] fields = peopleClass.getFields();
for (Field field:
fields) {
System.out.println(field.getName());
}
//获取本类的所有属性,包括私有等
System.out.println("===");
Field[] declaredFields = peopleClass.getDeclaredFields();
for (Field field:
declaredFields) {
System.out.println(field.getName());
}
//获取本类及父类的public方法,不限于直接父类
System.out.println("====");
Method[] methods = peopleClass.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
//获取本类的所有方法
System.out.println("=====");
Method[] declaredMethods = peopleClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
//获取本类的所有public构造器,没有父类
System.out.println("=====");
Constructor<?>[] constructors = peopleClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor.getName());
}
//获取本类的所有方法,不局限于public
System.out.println("+++");
Constructor<?>[] declaredConstructors = peopleClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName());
}
//得到包名
System.out.println(peopleClass.getPackage());//package class_
//得到父类的信息
System.out.println(peopleClass.getSuperclass());//class class_.Animal
//返回接口
Class<?>[] interfaces = peopleClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface.getName());
}
//返回注解
Annotation[] annotations = peopleClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
interface IFA {
}
interface IFB {
}
class Animal{
public String hobby;
public void hi() {
}
public Animal() {
}
public Animal(String hobby) {
}
}
@Deprecated
class People extends Animal implements IFA,IFB{
//属性
public String name;
protected static int age; // 4 + 8 = 12
String job;
private double sal;
//构造器
public People(){
}
public People(String name) {
}
//私有的
private People(String name, int age) {
}
//方法
public void m1(String name, int age, double sal) {
}
protected String m2() {
return null;
}
void m3() {
}
private void m4() {
}
}
Filed类,Method类
package class_;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Class07 {
public static void main(String[] args) {
}
@Test
public void api01() throws ClassNotFoundException {
Class<?> peopleClass = Class.forName("class_.People");
//获得全类名
System.out.println(peopleClass.getName());//class_.People
//获得简单类名
System.out.println(peopleClass.getSimpleName());//people
//获取本类以及父类的所有公共属性
Field[] fields = peopleClass.getFields();
for (Field field:
fields) {
System.out.println(field.getName());
}
//获取本类的所有属性,包括私有等
System.out.println("===");
Field[] declaredFields = peopleClass.getDeclaredFields();
for (Field field:
declaredFields) {
System.out.println(field.getName());
}
//获取本类及父类的public方法,不限于直接父类
System.out.println("====");
Method[] methods = peopleClass.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
//获取本类的所有方法
System.out.println("=====");
Method[] declaredMethods = peopleClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
//获取本类的所有public构造器,没有父类
System.out.println("=====");
Constructor<?>[] constructors = peopleClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor.getName());
}
//获取本类的所有方法,不局限于public
System.out.println("+++");
Constructor<?>[] declaredConstructors = peopleClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor.getName());
}
//得到包名
System.out.println(peopleClass.getPackage());//package class_
//得到父类的信息
System.out.println(peopleClass.getSuperclass());//class class_.Animal
//返回接口
Class<?>[] interfaces = peopleClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface.getName());
}
//返回注解
Annotation[] annotations = peopleClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
@Test
public void api02() throws ClassNotFoundException {
Class<?> peopleClass = Class.forName("class_.People");
//获取本类中所有的属性
Field[] declaredFields = peopleClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("本类中的属性:"+declaredField.getName()+
"该属性的修饰符:"+declaredField.getModifiers()+
" 该属性的类型"+declaredField.getType());
}
}
@Test
public void api03() throws ClassNotFoundException {
Class<?> peopleClass = Class.forName("class_.People");
//获取本类中所有的方法
Method[] declaredMethods = peopleClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println("该类的方法"+declaredMethod.getName()+
"该属性的修饰符:"+declaredMethod.getModifiers()+
"该类的返回类型"+declaredMethod.getReturnType());
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("该方法的参数类型"+parameterType.getName());
}
}
}
@Test
public void api04() throws ClassNotFoundException {
Class<?> peopleClass = Class.forName("class_.People");
//获取本类中所有的构造器
Constructor<?>[] declaredConstructors = peopleClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
System.out.println(declaredConstructor.getName());//名字
System.out.println(declaredConstructor.getModifiers());//修饰符
System.out.println(declaredConstructor.getParameterCount());//参数个数
}
}
}
interface IFA {
}
interface IFB {
}
class Animal{
public String hobby;
public void hi() {
}
public Animal() {
}
public Animal(String hobby) {
}
}
@Deprecated
class People extends Animal implements IFA,IFB{
//属性
public String name;
protected static int age; // 4 + 8 = 12
String job;
private double sal;
//构造器
public People(){
}
public People(String name) {
}
//私有的
private People(String name, int age) {
}
//方法
public void m1(String name, int age, double sal) {
}
protected String m2() {
return null;
}
void m3() {
}
private void m4() {
}
}
动态加载和静态加载
package class_;
import learn.Car;
import javax.management.MBeanRegistration;
import java.util.Scanner;
public class Class05 {
public static void main(String[] args) throws ClassNotFoundException {
Scanner scanner=new Scanner(System.in);
String key=scanner.next();
switch (key){
case "1":
//静态加载,如果没有import learn.Car,编译javac就会报错
Car car =new Car();
case "2":
//动态加载,javac编译不会报错
Class<?> aClass = Class.forName("learn.Cat");
break;
}
}
}
类加载
类加载前两个阶段由JVM控制,初始化是由程序员控制,主要是静态成员
- 加载loading
- JVM在该阶段的主要目的是将字节码从 不同的数据源(可能是class文件,也可能是jar包,甚至是网络)转换成二进制字节流加载到内存(方法区中)并生成一个该类的java.lang.Class对象(堆中)
- 连接Linking
- 验证verification
- 目的是为了确保Class文件的字节流中包含的信息复合当前虚拟机的要求,并且不会危害虚拟机自身的安全
- 包括:文件格式验证(是否以魔数 oxcafebage开头)、元数据验证、字节码验证和符号引用验证
- 可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机加载的时间
- 准备preparation
- JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始化值,eg.0,0L,null,false等)(和Class对象一起存放在堆中)
- 解析resolution
- 虚拟机将常量池内的符号引用替换为直接引用的过程
- 即在编译阶段,并没有放到内存中没有内存地址,所以引用是符号引用;在解析这一步把符号引用替换为直接引用
- 验证verification
- 初始化initialization
- 到初始化阶段,才开始执行类中定义的Java代码,此阶段执行clinit()方法的过程
- clinit()方法是由编译器按照语句在源文件中出现的顺序,一次自动收集类中所有的静态变量的赋值动作和静态代码块中的语句,并进行合并
- 虚拟机会保证一个类的clinit()方法在多线程环境中被正确的加锁,同步,如果多个线程同时去初始化一个类,俺么只会有一个线程去执行这个类的clint()方法
通过反射创建对象
package class_;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class calss08 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//得到Class对象
Class<?> cls = Class.forName("class_.User");
//通过public的无参构造器创建对象
Object o = cls.newInstance();
System.out.println(o);
//通过public的有参构造器创建实例
//先获得有参构造器,才创建实例
Constructor<?> constructor = cls.getConstructor(String.class);
Object zhang = constructor.newInstance("zhang");
System.out.println(zhang);
//通过private的有参构造器
Constructor<?> declaredConstructor = cls.getDeclaredConstructor(int.class, String.class);
declaredConstructor.setAccessible(true);//爆破,使用返反射可以用private构造器
Object baby = declaredConstructor.newInstance(2, "baby");
System.out.println(baby);
}
}
class User { //User类
private int age = 10;
private String name = "gao";
public User() {//无参 public
}
public User(String name) {//public的有参构造器
this.name = name;
}
private User(int age, String name) {//private 有参构造器
this.age = age;
this.name = name;
}
public String toString() {
return "User [age=" + age + ", name=" + name + "]";
}
}
类的成员和方法
package com.hspedu.reflection;
import java.lang.reflect.Field;
/**
* @author 韩顺平
* @version 1.0
* 演示反射操作属性
*/
public class ReflecAccessProperty {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
//1. 得到Student类对应的 Class对象
Class<?> stuClass = Class.forName("com.hspedu.reflection.Student");
//2. 创建对象
Object o = stuClass.newInstance();//o 的运行类型就是Student
System.out.println(o.getClass());//Student
//3. 使用反射得到age 属性对象
Field age = stuClass.getField("age");
age.set(o, 88);//通过反射来操作属性
System.out.println(o);//
System.out.println(age.get(o));//返回age属性的值
//4. 使用反射操作name 属性
Field name = stuClass.getDeclaredField("name");
//对name 进行暴破, 可以操作private 属性
name.setAccessible(true);
//name.set(o, "老韩");
name.set(null, "老韩~");//因为name是static属性,因此 o 也可以写出null
System.out.println(o);
System.out.println(name.get(o)); //获取属性值
System.out.println(name.get(null));//获取属性值, 要求name是static
}
}
class Student {//类
public int age;
private static String name;
public Student() {//构造器
}
public String toString() {
return "Student [age=" + age + ", name=" + name + "]";
}
}
package com.hspedu.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author 韩顺平
* @version 1.0
* 演示通过反射调用方法
*/
public class ReflecAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1. 得到Boss类对应的Class对象
Class<?> bossCls = Class.forName("com.hspedu.reflection.Boss");
//2. 创建对象
Object o = bossCls.newInstance();
//3. 调用public的hi方法
//Method hi = bossCls.getMethod("hi", String.class);//OK
//3.1 得到hi方法对象
Method hi = bossCls.getDeclaredMethod("hi", String.class);//OK
//3.2 调用
hi.invoke(o, "韩顺平教育~");
//4. 调用private static 方法
//4.1 得到 say 方法对象
Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
//4.2 因为say方法是private, 所以需要暴破,原理和前面讲的构造器和属性一样
say.setAccessible(true);
System.out.println(say.invoke(o, 100, "张三", '男'));
//4.3 因为say方法是static的,还可以这样调用 ,可以传入null
System.out.println(say.invoke(null, 200, "李四", '女'));
//5. 在反射中,如果方法有返回值,统一返回Object , 但是他运行类型和方法定义的返回类型一致
Object reVal = say.invoke(null, 300, "王五", '男');
System.out.println("reVal 的运行类型=" + reVal.getClass());//String
//在演示一个返回的案例
Method m1 = bossCls.getDeclaredMethod("m1");
Object reVal2 = m1.invoke(o);
System.out.println("reVal2的运行类型=" + reVal2.getClass());//Monster
}
}
class Monster {}
class Boss {//类
public int age;
private static String name;
public Boss() {//构造器
}
public Monster m1() {
return new Monster();
}
private static String say(int n, String s, char c) {//静态方法
return n + " " + s + " " + c;
}
public void hi(String s) {//普通public方法
System.out.println("hi " + s);
}
}