Java 反射 韩顺平老师 自学笔记

反射

反射在不修改源码的情况下,来控制程序,也符合设计模式的OCP原则(开闭原则:不修改源码,扩容功能)

一个需求引出反射

一个需求引出反射

示例:

package com.hspedu.reflection.qusttion;

import com.hspedu.Cat;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @author wty
 * @date 2022/9/22 15:07
 * 反射问题的引入
 */
@SuppressWarnings({"all"})
public class reflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 根据配置文件 re.properties指定信息调用Cat调用hi
        // 传统方法
        //Cat cat = new Cat();
        //cat.hi();

        // 反射的价值
        // 1.使用Properties 类,可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String method = properties.get("method").toString();
        System.out.println("classfullpath=" + classfullpath);
        System.out.println("method=" + method);

        // 2.创建一个对象
        // 传统方法 new classfullpath();
        // com.hspedu.Cat cat = new com.hspedu.Cat();

        // 3.使用反射机制解决
        //(1)加载类,返回一个Class类型的对象
        Class aClass = Class.forName(classfullpath);
        //(2)通过aClass得到com.hspedu.Cat的对象实例
        Object o = aClass.newInstance();
        System.out.println("o:" + o.getClass()); // 运行类型

        //(3)通过aClass得到加载的类com.hspedu.Cat的方法对象
        //   在反射中,可以把 方法 视作为 对象 (万物皆对象)
        Method method1 = aClass.getMethod(method);
        //(4)通过method1 调用方法:
        method1.invoke(o); // 传统方法 对象.方法  反射中方法.invoke(对象)

        Cat cat = (Cat)aClass.newInstance();
        cat.setName("猫猫");
        method1.invoke(cat);


    }
}

re.properties 文件

classfullpath=com.hspedu.Cat
method=hi

Cat类

package com.hspedu;

public class Cat {
    private  String name = "招财猫";
    public  void hi(){
        System.out.println("hi " + name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

反射机制

Java Reflection

  1. 反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性和方法,反射在设计模式和框架底层都会用到

  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称为反射。

反射原理示意图

反射原理示意图

反射机制可以完成

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时得到任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理

反射相关的类

  1. java.lang.Class 代表一个类,Class对象标识某个类加载后在堆中的对象
  2. java.lang.reflect.Method代表类的方法
  3. java.lang.reflect.Field代表类的成员变量
  4. java.lang.reflect.Constructor代表类的构造方法

API:Package java.lang.reflect

代码示例:

@SuppressWarnings({"all"})
@Test
public void m4() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    Properties properties = new Properties();
    properties.load(new FileInputStream("src/com/reflection/res.propeties"));
    String path = properties.get("class").toString();
    //System.out.println("pata:" +path);
    String method = properties.get("method").toString();
    //System.out.println("method:" +method);
    Class aClass = Class.forName(path);
    Object o = aClass.newInstance();

    Method dogMethod = aClass.getMethod(method);
    //System.out.println("dogMethod:" + dogMethod);
    dogMethod.setAccessible(true);
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 9; i++) {
        dogMethod.invoke(o);
    }
    long end = System.currentTimeMillis();
    System.out.println("m3合计时间为" + (end - begin));

    // 获取属性
    System.out.println("age:"+aClass.getField("age"));
    System.out.println("constructer:"+aClass.getConstructor(String.class,int.class)); // 这里传入的String.class就是String类的class对象
}

反射的优点和缺点

  1. 优点:可以动态的创建和使用对象(也是框架的核心),使用灵活,没有反射机制,框架技术就失去底层支撑
  2. 缺点:使用反射基本是解释执行,对执行速度有影响

反射调用优化-关闭访问检查

反射调用优化-关闭访问检查

示例

public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    m1(); // 执行时间5ms
    m2(); // 执行时间1603ms
    m3(); // 执行时间1030ms

}

public static void m1() {
    Dog dog = new Dog();
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 900000000; i++) {
        dog.say();
    }
    long end = System.currentTimeMillis();
    System.out.println("m1合计时间为" + (end - begin));

}

@SuppressWarnings({"all"})
public static void m2() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    Properties properties = new Properties();
    properties.load(new FileInputStream("src/com/reflection/res.propeties"));
    String path = properties.get("class").toString();
    //System.out.println("pata:" +path);
    String method = properties.get("method").toString();
    //System.out.println("method:" +method);
    Class aClass = Class.forName(path);
    Object o = aClass.newInstance();

    Method dogMethod = aClass.getMethod(method);
    //System.out.println("dogMethod:" + dogMethod);
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 900000000; i++) {
        dogMethod.invoke(o);
    }
    long end = System.currentTimeMillis();
    System.out.println("m2合计时间为" + (end - begin));
}

@SuppressWarnings({"all"})
public static void m3() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    Properties properties = new Properties();
    properties.load(new FileInputStream("src/com/reflection/res.propeties"));
    String path = properties.get("class").toString();
    //System.out.println("pata:" +path);
    String method = properties.get("method").toString();
    //System.out.println("method:" +method);
    Class aClass = Class.forName(path);
    Object o = aClass.newInstance();

    Method dogMethod = aClass.getMethod(method);
    //System.out.println("dogMethod:" + dogMethod);
    dogMethod.setAccessible(true);
    long begin = System.currentTimeMillis();
    for (int i = 0; i < 900000000; i++) {
        dogMethod.invoke(o);
    }
    long end = System.currentTimeMillis();
    System.out.println("m3合计时间为" + (end - begin));
}

Class类

基本介绍

Class类

Class类的常用方法

Class类的常用方法

代码示例

package com.cardemo;

import org.junit.Test;

import java.lang.reflect.Field;

/**
 * @author wty
 * @date 2022/10/27 23:27
 * <p>
 * 演示Class类常用方法
 */
public class Class02 {
    @Test
    @SuppressWarnings({"all"})
    public void useClassMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        String classPath = "com.cardemo.Car";

        // 1.获取到Car类对应的Class对象
        // <?> 表示不确定的Java类型
        Class<?> aClass = Class.forName(classPath);

        // 输出aClass : com.cardemo.Car
        // 2.显示aClass对象是哪一个类的Class对象
        System.out.println(aClass);
        // 运行类型 : java.lang.Class
        System.out.println(aClass.getClass());

        // 3.得到包名: com.cardemo
        System.out.println(aClass.getPackage().getName());


        // 4.得到类的全路径: com.cardemo.Car
        System.out.println(aClass.getName());

        // 5.通过aClass创建对象实例
        Object o = aClass.newInstance();
        Car car = (Car) o;
        // 会跑Car类的toString方法
        System.out.println(car);

        // 6.通过反射获取属性 brand
        Field brand = aClass.getField("brand");
        // 获取属性 属性.get(类的对象实例)
        System.out.println(brand.get(car));

        // 7.通过反射给属性赋值
        brand.set(car, "奔驰");
        System.out.println(brand.get(car));

        // 8.希望遍历得到所有的属性
        System.out.println("====遍历所有属性====");
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName() + ":" + declaredField.get(car));
        }

    }
}

获取Class类对象

获取Class类对象

1.Class.forName()

Class.forName()

2.类名.class

类名.class

3.对象.getClass()

对象.getClass()

4.对象.getClass().getClassLoader()

对象.getClass().getClassLoader()

5.基本数据类型.class

基本数据类型.class

6.包装类.TYPE

包装类.TYPE

代码示例

package getclass;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/10/29 22:18
 */
public class GetClass {
    @Test
    public void getClassExercise() throws ClassNotFoundException {
        // 方式1:Class.forName() 多用于读取配置文件
        Class<?> cls1 = Class.forName("getclass.Car");
        System.out.println(cls1);

        // 2.类名.class 多用于参数的传递
        Class<Car> cls2 = Car.class;
        System.out.println(cls2);

        // 3.对象.getClass()  已经知道对象实例
        Car car = new Car();
        Class<? extends Car> cls3 = car.getClass();
        System.out.println(cls3);

        // 4.通过类加载器获取类的Class对象
        // (1)先得到类的加载器car
        ClassLoader classLoader = car.getClass().getClassLoader();
        // (2)通过类加载器得到Class对象
        Class<?> cls4 = classLoader.loadClass("getclass.Car");
        System.out.println(cls4);

        // 这里cls1 cls2 cls3 cls4是同一个对象
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        System.out.println(cls3.hashCode());
        System.out.println(cls4.hashCode());

        // 5.基本数据类型.class
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        Class<Boolean> booleanClass = boolean.class;
        System.out.println(integerClass);
        System.out.println(integerClass.hashCode());
        System.out.println(characterClass);
        System.out.println(booleanClass);

        // 6.包装类.TYPE
        Class<Integer> type1 = Integer.TYPE;
        Class<Character> type2 = Character.TYPE;
        System.out.println(type1);
        System.out.println(type1.hashCode());
        System.out.println(type2);


    }

    @Test
    public void getClassExer() throws ClassNotFoundException {
        String classPath = "getclass.Car";
        // 1.Class.forName()
        Class<?> cls1 = Class.forName(classPath);
        System.out.println(cls1);

        // 2. 类名.Class()
        Class<Car> cls2 = Car.class;
        System.out.println(cls2);

        // 3.对象名.getClass()
        Car car = new Car();
        Class<? extends Car> cls3 = car.getClass();
        System.out.println(cls3);

        // 4.类加载器
        ClassLoader classLoader = car.getClass().getClassLoader();
        Class<?> cls4 = classLoader.loadClass(classPath);
        System.out.println(cls4);

        // 5.基本数据类型.class
        Class<Integer> integerClass = int.class;
        Class<Byte> byteClass = byte.class;
        Class<Character> characterClass = char.class;
        Class<Short> shortClass = short.class;
        Class<Double> doubleClass = double.class;
        Class<Float> floatClass = float.class;
        Class<Boolean> booleanClass = boolean.class;
        Class<Long> longClass = long.class;
        System.out.println(integerClass);
        System.out.println(byteClass);
        System.out.println(characterClass);
        System.out.println(shortClass);
        System.out.println(doubleClass);
        System.out.println(floatClass);
        System.out.println(booleanClass);
        System.out.println(longClass);

        // 6.包装类.TYPE
        System.out.println("=====包装类=====");
        Class<Byte> type1 = Byte.TYPE;
        Class<Short> type2 = Short.TYPE;
        Class<Integer> type3 = Integer.TYPE;
        Class<Long> type4 = Long.TYPE;
        Class<Float> type5 = Float.TYPE;
        Class<Double> type6 = Double.TYPE;
        Class<Boolean> type7 = Boolean.TYPE;
        Class<Character> type8 = Character.TYPE;
        System.out.println(type1);
        System.out.println(type2);
        System.out.println(type3);
        System.out.println(type4);
        System.out.println(type5);
        System.out.println(type6);
        System.out.println(type7);
        System.out.println(type8);

    }
}

输出结果1

class getclass.Car
class getclass.Car
class getclass.Car
class getclass.Car
1637070917
1637070917
1637070917
1637070917
int
1555009629
char
boolean
int
1555009629
char

输出结果2

class getclass.Car
class getclass.Car
class getclass.Car
class getclass.Car
int
byte
char
short
double
float
boolean
long
=====包装类=====
byte
short
int
long
float
double
boolean
char

哪些类型有Class对象

如下类型有Class对象

  1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
  2. interface:接口
  3. 数组
  4. enum枚举
  5. annotation注解
  6. 基本数据类型
  7. void

代码示例

package alltype;

import org.junit.Test;

import java.lang.annotation.Target;
import java.util.Collection;

/**
 * @author wty
 * @date 2022/10/29 22:53
 */
public class AllTypeClass {
    @Test
    public void AllTypeClass(){
        /**
         * > 1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
         * > 2. interface:接口
         * > 3. 数组
         * > 4. enum枚举
         * > 5. annotation注解
         * > 6. 基本数据类型
         * > 7. void
         */
        // 1. 外部类
        Class<String> cls1 = String.class;

        // 2. interface:接口
        Class<Collection> cls2 = Collection.class;

        // 3.数组
        Class<Integer[]> cls3 = Integer[].class;

        // 4.二维数组
        Class<float[][]> cls4 = float[][].class;

        // 5.注解
        Class<Target> cls5 = Target.class;
        // 6.Deprecated过时的
        Class<Deprecated> cls6 = Deprecated.class;

        //7.枚举
        Class<Thread.State> cls7 = Thread.State.class;
        /**
         *  线程的状态是枚举类型
         *     public static enum State {
         *         NEW,
         *         RUNNABLE,
         *         BLOCKED,
         *         WAITING,
         *         TIMED_WAITING,
         *         TERMINATED;
         *
         *         private State() {
         *         }
         *     }
         */

        // 8. 基本数据类型
        Class<Integer> cls8 = int.class;

        // 9.void
        Class<Void> cls9 = void.class;

        // 10. Class
        Class<Class> cls10 = Class.class;

        System.out.println(cls1);
        System.out.println(cls2);
        System.out.println(cls3);
        System.out.println(cls4);
        System.out.println(cls5);
        System.out.println(cls6);
        System.out.println(cls7);
        System.out.println(cls8);
        System.out.println(cls9);
        System.out.println(cls10);


    }
}

输出结果

class [Ljava.lang.Integer;
class [[F
interface java.lang.annotation.Target
interface java.lang.Deprecated
class java.lang.Thread$State
int
void
class java.lang.Class

类加载

基本说明

反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载。

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  2. 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错,降低了依赖。

代码示例

静态加载

import java.util.*;
public Classload{
	public static void main(String args[]){
		Scanner scanner = new Scanner(System.in);
		System.out.printlin("请输入key");
		String key = scaaner.next();
		switch(key){
			case "1":
			Dog dog = new Dog(); // 静态加载 这里会报错,因为没有Dog类
			dog.cry();
			break;
			case "2":
			System.out.printlin("ok");
			break;
			default:
			System.out.printlin("do nothing");

		}
	}
}

静态加载优化

import java.util.*;
import java.lang.reflect.*;
public class Classload{
	public static void main(String args[]) throws Exception{
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入key");
		String key = scanner.next();
		switch(key){
			case "1":
			Dog dog = new Dog(); // 静态加载 依赖性很强
			dog.cry();
			break;
			case "2":
			Class cls = Class.forName("Person"); // 加载Person
			Object o = cls.newInstance();
			Method m = cls.getMethod("hi");
			// 反射是动态加载
			m.invoke(o);
			System.out.println("ok");
			break;
			default:
			System.out.println("do nothing");

		}
	}
}
// 因为Dog是静态加载,所以必须编写
// Person是动态加载,所以没有编写Person也不会报错,只有运行到那一行才会报错
class Dog{
	private String name;
	public Dog(String name){
		this.name = name;
	}
	public Dog(){}

	public void cry(){
		System.out.println("Dog.cry");
	}
}

class Person{
	public void hi(){
		System.out.println("Person.hi");
	}
}

动态加载

import java.util.*;
import java.lang.reflect.*;
public class Classload{
	public static void main(String args[]) throws Exception{
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入key");
		String key = scanner.next();
		switch(key){
			case "1":
			//Dog dog = new Dog(); // 静态加载 依赖性很强
			//dog.cry();
			break;
			case "2":
			Class cls = Class.forName("Person"); // 加载Person
			Object o = cls.newInstance();
			Method m = cls.getMethod("hi");
			// 反射是动态加载,依赖性弱
			m.invoke(o);
			System.out.println("ok");
			break;
			default:
			System.out.println("do nothing");

		}
	}
}

类加载的时机

  1. 当创建对象时(new) // 静态加载
  2. 当子类被加载时 // 静态加载
  3. 调用类中的静态成员时 // 静态加载
  4. 通过反射 // 动态加载

类加载过程图

类加载过程图
Loading和Linking是JVM负责,initialization中静态成员的初始化也是JVM实现

类加载各个阶段完成的任务

类加载各个阶段完成的任务

类加载的各个阶段

加载阶段Loading

JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是Jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象。

连接阶段Linking
验证verification
  1. 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并不会危害虚拟机自身的安全。
  2. 包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证符号引用验证。
  3. 可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机加载的时间

代码示例:

 @Test
    public void vertificationClass(){
        Car car = new Car();
        /**
         *         public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
         *             int var3 = var1.lastIndexOf(46);
         *             if (var3 != -1) {
         *             // 这里有个 System.getSecurityManager()安全管理器:用来验证
         *                 SecurityManager var4 = System.getSecurityManager();
         *                 if (var4 != null) {
         *                     var4.checkPackageAccess(var1.substring(0, var3));
         *                 }
         *             }
         */
    }

oxcafebabe开头值的是class文件开头
oxcafebabe开头

准备Preparation
  1. JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配。
Java初始化
初始化类型初始化值
byte0
booleanfalse
short0
int0
long0
float0.0
double0.0
类对象null
接口对象null
int型数组0
float型数组0.0
double型数组0.0
char型数组0或者’\u0000’
boolean型数组false

代码示例:

class A{
    // 属性--成员变量--字段
    // 类加载准备阶段,如何处理属性
    // 1.n1是实例变量,不是静态变量,准备阶段不分配内存
    public int n1 = 10;
    // 2.n2是静态变量,分配内存n2是默认初始化0
    public static int n2 = 20;
    // 3.n3是个常量,和静态变量不一样,会一次性分配,直接初始化为30
    public static final int n3 = 30;
}
解析Resolution
  1. 虚拟机将常量池内的符号引用替换为直接引用的过程
Initialization初始化
  1. 到初始化阶段,才是真正开始执行类中定义的Java程序代码,此阶段是执行< clinit >()方法的过程。
  2. < clinit >()方法是由编译器按照语句在源文件中出现的顺序,依次自动收集类中的静态变量的赋值动作和静态代码块中的语句,并进行合并。
  3. 虚拟机会保证一个类的< clinit >()方法在多线程环境中被正确地加锁和同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的< clinit >()方法,其它线程都需要阻塞等待,直到活动线程执行< clinit >()方法完毕。
    针对2.的代码示例:
@SuppressWarnings({"all"})
@Test
public void getLinking(){
    // 1.加载B类,生成B类的class对象
    // 2.连接 num赋值为0
    // 3.初始化 依次自动收集类中的*静态变量*的赋值动作和静态代码块中的语句,并进行合并
    /**
     * clinit(){
     *     System.out.println("B 静态代码块被执行");
     *     num = 300;
     *     int num = 100;
     * }
     * 合并后 num = 100;
     */
    System.out.println(B.num);
}
/**
 * @author wty
 * @date 2022/10/30 10:17
 * 类加载阶段:初始化
 */
class B{
    // 静态代码块
    static {
        System.out.println("B 静态代码块被执行");
        num = 300;
    }
    static int num = 100;
    public B(){
        System.out.println("B的构造器");
    }
}

运行结果

B 静态代码块被执行
100

针对3.的源码示例:

    @Test
    public void vertificationClass(){
        Car car = new Car();
        /**
         * 源码:正因为有这个机制,才能保证某个类在内存中只有一份
         *    synchronized
         *    protected Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
         *         // 注意这里的synchronized
         *         synchronized(this.getClassLoadingLock(var1)) {
         *             Class var4 = this.findLoadedClass(var1);
         *             if (var4 == null) {
         *                 long var5 = System.nanoTime();
         *     …………………………
         *         }
         *     }
         */
    }

通过反射获取类的结构信息

相关方法1

  1. 类名.class.getName(); 获取全类名
  2. 类名.class.getSimpleName(); 获取简单类名
  3. 类名.class.getFields(); 获取所有public修饰的属性,包含本类以及父类的
  4. 类名.class.getDeclaredFields(); 获取本类中所有属性
  5. 类名.class.getMethods(); 获取所有public修饰的方法,包含本类以及父类的
  6. 类名.class.getDeclaredMethods(); 获取本类中的所有方法
  7. 类名.class.getConstructors(); 本类所有public构造器
  8. 类名.class.getDeclaredConstructors(); 获取本类中的所有构造器
  9. 类名.class.getPackage(); 以Package形式返回 包信息
  10. 类名.class.getSuperclass(); 以Class形式返回父类信息
  11. 类名.class.getInterfaces(); 以Class[]形式返回接口信息
  12. 类名.class.getAnnotations(); 以Annotation[]形式返回注解信息

代码示例:

 @Test
    @SuppressWarnings({"all"})
    /**
     * 通过反射获取类的结构信息
     */
    public void getClassInfo() throws NoSuchFieldException, NoSuchMethodException, ClassNotFoundException {
        Class<?> car = Class.forName("getclass.Car");
        /**
         * 源码:正因为有这个机制,才能保证某个类在内存中只有一份
         *    synchronized
         *    protected Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
         *         // 注意这里的synchronized
         *         synchronized(this.getClassLoadingLock(var1)) {
         *             Class var4 = this.findLoadedClass(var1);
         *             if (var4 == null) {
         *                 long var5 = System.nanoTime();
         *     …………………………
         *         }
         *     }
         */
        System.out.println(car.getName());
        System.out.println(car.getSimpleName());
        Field[] fields = car.getFields();
        System.out.println("====本类以及父类public属性====");
        for (Field field : fields) {
            System.out.println(field + "-----" + field.getName());
        }
        System.out.println("====本类所有属性====");
        Field[] declaredFields = car.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField + "----" + declaredField.getName());
        }
        System.out.println("====本类以及所有父类public方法====");
        Method[] methods = car.getMethods();
        for (Method method : methods) {
            System.out.println(method + "-----" + method.getName());
        }
        System.out.println("====本类所有方法====");
        Method[] declaredMethods = car.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod + "----" + declaredMethod.getName());
        }
        //System.out.println("====本类以及所有父类public构造器(构造器本身就是public的否则不允许继承)====");
        System.out.println("====本类所有public构造器====");
        Constructor<?>[] constructors = car.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor + "-----" + constructor.getName());
        }
        System.out.println("====本类所有显示声明的构造器====");
        Constructor<?>[] declaredConstructors = car.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor + "-----" + declaredConstructor.getName());
        }
        System.out.println("---包---");
        Package aPackage = car.getPackage();
        System.out.println(aPackage);
        System.out.println("---父类全路径---");
        System.out.println(car.getSuperclass());
        System.out.println("---所有接口---");
        Class<?>[] interfaces = car.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println(anInterface);
        }
        System.out.println("---所有注解---");
        Annotation[] annotations = car.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

    }

类结构

package getclass;

/**
 * @author wty
 * @date 2022/10/29 22:26
 */
@SuppressWarnings({"all"})
@Deprecated
public class Car extends Animals implements IA,IB {
    // 属性
    public String name;
    protected int age;
    String job;
    private double sal;

    public void m1(){}
    protected void m2(){}
    void m3(){}
    private void m4(){}

    public Car(String name){
        this.name = name;
    }
    public Car(){}
    private Car(double sal){
        this.sal = sal;
    }
}

class Animals{
    public String act;
    public void AnimalsAct(){}
    public Animals(String act){}
    public Animals(){}
}

interface IA{

}
interface IB{

}

输出结果:

getclass.Car
Car
====本类以及父类public属性====
public java.lang.String getclass.Car.name-----name
public java.lang.String getclass.Animals.act-----act
====本类所有属性====
public java.lang.String getclass.Car.name----name
protected int getclass.Car.age----age
java.lang.String getclass.Car.job----job
private double getclass.Car.sal----sal
====本类以及所有父类public方法====
public void getclass.Car.m1()-----m1
public void getclass.Car.AnimalsAct()-----AnimalsAct
public final void java.lang.Object.wait() throws java.lang.InterruptedException-----wait
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException-----wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException-----wait
public boolean java.lang.Object.equals(java.lang.Object)-----equals
public java.lang.String java.lang.Object.toString()-----toString
public native int java.lang.Object.hashCode()-----hashCode
public final native java.lang.Class java.lang.Object.getClass()-----getClass
public final native void java.lang.Object.notify()-----notify
public final native void java.lang.Object.notifyAll()-----notifyAll
====本类所有方法====
public void getclass.Car.m1()----m1
protected void getclass.Car.m2()----m2
private void getclass.Car.m4()----m4
void getclass.Car.m3()----m3
public void getclass.Car.AnimalsAct()----AnimalsAct
====本类所有public构造器====
public getclass.Car()-----getclass.Car
public getclass.Car(java.lang.String)-----getclass.Car
====本类所有显示声明的构造器====
public getclass.Car()-----getclass.Car
private getclass.Car(double)-----getclass.Car
public getclass.Car(java.lang.String)-----getclass.Car
------
package getclass
---父类全路径---
class getclass.Animals
---所有接口---
interface getclass.IA
interface getclass.IB
---所有注解---
@java.lang.Deprecated()

Process finished with exit code 0

相关方法2

  1. 属性.getModifiers(); 以int形式返回修饰符
    说明:
    默认修饰符 0
    public 1
    private 2
    protected 4
    static 8
    final 16
  2. 属性.getTypeName(); 以Class形式返回类型
  3. 属性.getName(); 返回属性名

代码示例:

    @Test
    @SuppressWarnings({"all"})
    /**
     * 通过反射获取类的结构信息
     */
    public void getClassInfo() throws NoSuchFieldException, NoSuchMethodException, ClassNotFoundException {
        Class<?> car = Class.forName("getclass.Car");
        System.out.println("====本类以及所有父类public方法以及访问修饰符====");
        Field[] fields = car.getFields();
        for (Field field : fields) {
            System.out.println(field.getModifiers() + "---"+field.getType()+"---" + field.getName());
        }
        System.out.println("====本类所有方法以及访问修饰符====");
        Field[] declaredFields = car.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getModifiers() + "--"+declaredField.getType()+"--" + declaredField.getName());
        }

        // public static 修饰的访问,类名.getModifiers()采用相加形式 1+8 = 9
    }

Car类

package getclass;

/**
 * @author wty
 * @date 2022/10/29 22:26
 */
@SuppressWarnings({"all"})
@Deprecated
public class Car extends Animals implements IA,IB {
    // 属性
    public String name;
    protected int age;
    String job;
    private double sal;
    public static int height;

    public void m1(){}
    protected void m2(){}
    void m3(){}
    private void m4(){}

    public static void m5(){}

    public Car(String name){
        this.name = name;
    }
    public Car(){}
    private Car(double sal){
        this.sal = sal;
    }
}

class Animals{
    public String act;
    public void AnimalsAct(){}
    public Animals(String act){}
    public Animals(){}
}

interface IA{

}
interface IB{

}

相关方法3

  1. 方法.getModifiers(); 以int形式返回修饰符
    说明:
    默认修饰符 0
    public 1
    private 2
    protected 4
    static 8
    final 16
  2. 方法.getReturnType(); 以Class形式返回类型
  3. 方法.getName(); 返回方法名
  4. getParameterTypes:以Class[]返回参数类型数组

代码示例:

    @Test
    @SuppressWarnings({"all"})
    /**
     * 通过反射获取类的结构信息
     */
    public void getClassInfo() throws NoSuchFieldException, NoSuchMethodException, ClassNotFoundException {
        Class<?> car = Class.forName("getclass.Car");
        System.out.println("====本类以及所有父类public方法以及修饰符====");
        Method[] methods = car.getMethods();
        for (Method method : methods) {
            System.out.println(method.getModifiers() + "-----" + method.getName()+ "-----" + method.getReturnType());
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(method.getName() + "该方法的形参返回值是:" + parameterType);
            }
        }
        System.out.println("====本类所有方法以及修饰符====");
        Method[] declaredMethods = car.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getModifiers() + "----" + declaredMethod.getName()+ "-----" + declaredMethod.getReturnType());
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(declaredMethod.getName()+"该方法的形参返回值是:" + parameterType);
            }
        }

        // public static 修饰的访问,类名.getModifiers()采用相加形式 1+8 = 9
    }

相关方法4

  1. 构造器.getModifiers(); 以int形式返回修饰符
    说明:
    默认修饰符 0
    public 1
    private 2
    protected 4
    static 8
    final 16
  2. 构造器.getName(); 返回方法名
  3. 构造器.getParameterTypes:以Class[]返回参数类型数组

代码示例:

    @Test
    @SuppressWarnings({"all"})
    /**
     * 通过反射获取类的结构信息
     */
    public void getClassInfo() throws NoSuchFieldException, NoSuchMethodException, ClassNotFoundException {
        Class<?> car = Class.forName("getclass.Car");
        System.out.println("====本类所有public声明的构造器====");
        Constructor<?>[] constructors = car.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getModifiers() + "-----" + constructor.getName());
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(constructor.getName() + "的构造器的形参类型:" + parameterType);
            }
        }
        System.out.println("====本类所有显示声明的构造器====");
        Constructor<?>[] declaredConstructors = car.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getModifiers() + "-----" + declaredConstructor.getName());
            Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println(declaredConstructor.getName() + "的构造器的形参类型:" + parameterType);
            }
        }

        // public static 修饰的访问,类名.getModifiers()采用相加形式 1+8 = 9
    }

通过反射创建对象

  1. 方式一:调用类中的public修饰的无参构造器
  2. 方式二:调用类中的指定构造器
  3. Class类相关方法
    newInstance:调用类中的无参构造器,获取对应类的对象
    getConstructor(Class):根据参数列表,获取public修饰的构造器对象
    getDecalaredConstructor(Class):根据参数列表,获取对应的构造器
  4. Constructor类相关方法
    setAccessible暴破
    newInstance(Object):调用构造器

代码示例:

package reflectiondemo;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @author wty
 * @date 2022/10/30 23:42
 * 通过反射机制创建实例
 */
public class ReflectionInstance {
    @Test
    @SuppressWarnings({"all"})
    public void getReflectionInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 1.先获取User的Class对象
        Class<?> user = Class.forName("reflectiondemo.User");

        // 2.通过public的无参构造器创建实例
        Object o = user.newInstance();
        System.out.println(o);

        // 3.通过public的有参构造器创建实例
        Constructor<?> constructor = user.getConstructor(String.class);
        /**
         *     public User(String name){
         *         this.name = name;
         *     }
         */
        Object ls = constructor.newInstance("李四");
        System.out.println(ls);

        // 4.通过private(非公有)的有参构造器创建实例
        Constructor<?> constructor1 = user.getDeclaredConstructor(int.class, String.class);
        constructor1.setAccessible(true); // 暴破(暴力破解),使用反射可以访问,反射面前都是纸老虎
        Object zsf = constructor1.newInstance(20, "张三丰");
        System.out.println(zsf);
    }
}

class User{
    private int age = 10;
    private String name = "小明";
    public User(){}
    public User(String name){
        this.name = name;
    }
    private User(int age,String name){
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

输出示例:

User{age=10, name='小明'}
User{age=10, name='李四'}
User{age=20, name='张三丰'}

通过反射访问类中的成员

访问属性

  1. 根据属性名获取Field对象
    Field f = class对象.getDeclaredField(“属性名”);
  2. 暴破:f.setAccessible(true)
  3. 访问
    f.set(o,值);
    syso(f.get(o));
  4. **注意:**如果是静态属性,则set和get中的参数o,可以写成null

代码示例:

package reflectiondemo;

import org.junit.Test;

import java.lang.reflect.Field;

/**
 * @author wty
 * @date 2022/10/31 0:06
 */
public class RefctionAccessable {
    @Test
    public void getRefctionAccessable() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        // 1.得到Student类对应的Class对象stu
        Class<?> stu = Class.forName("reflectiondemo.Student");

        // 2.创建对象
        // 运行类型;Student
        Object o = stu.newInstance();
        System.out.println(o.getClass());


        // 3.反射得到属性
        Field age = stu.getField("age");
        // 设置年龄
        age.set(o,20);
        System.out.println(o);
        System.out.println(age.get(o));

        // 4.使用反射操作name属性(私有静态属性)
        Field name = stu.getDeclaredField("name");
        name.setAccessible(true);
        //name.set(o,"王二麻子");
        // 因为name属性是静态私有的,因此o也可以写为null
        name.set(null,"王二麻子");
        System.out.println(o);
        System.out.println(name.get(o));
        // 获取属性值 静态才能用
        System.out.println(name.get(null));

    }
}

class Student{
    public int age;
    private static String name;
    public Student(){}

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
}

输出:

class reflectiondemo.Student
Student{age=20}
20
Student{age=20}
王二麻子
王二麻子

访问方法

  1. 根据方法名获取Field对象
    Method m = class对象.getDeclaredMethod(“属性名”);
  2. 获取对象:Object o = class.newInstance();
  3. 暴破:m.setAccessible(true)
  4. 访问
    Object returnValue = m.invoke(o)
  5. **注意:**如果是静态方法,则set和get中的参数o,可以写成null
    代码示例:
package reflectiondemo;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author wty
 * @date 2022/10/31 0:06
 */
public class RefctionAccessable {
    @Test
    public void getRefctionAccessable() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        // 1.得到Student类对应的Class对象stu
        Class<?> stu = Class.forName("reflectiondemo.Student");

        // 2.创建对象
        // 运行类型;Student
        Object o = stu.newInstance();
        System.out.println(o.getClass());


        // 3.反射得到public方法
        Method getCount = stu.getMethod("getCount",int.class);
        System.out.println(getCount.getName());

        // 如果想得到非public方法可以用
        Method getNum = stu.getDeclaredMethod("getNum", String.class);
        System.out.println(getNum.getName());

        // 4.使用反射调用方法
        getCount.invoke(o,10);

        // 私有化要暴破
        getNum.setAccessible(true);
        getNum.invoke(o,"1001");

        // 因为height属性是静态私有的,因此o也可以写为null
        Method getHeight = stu.getDeclaredMethod("getHeight",double.class);
        getHeight.setAccessible(true);
        getHeight.invoke(o,23.34);

        // 获取属性值 静态才能用
        getHeight.invoke(null,33.37);

        //返回值:在反射中,方法有返回值,统一返回Object
        Object height = getHeight.invoke(null, 26.6);
        // 运行类型 class java.lang.String
        System.out.println(height.getClass());


    }
}

class Student{
    public int age;
    private String id;
    private static String name;
    private static double height;
    public Student(){}

    public void getCount(int age){
        this.age = age;
        System.out.println(age+"\tStudent.getCount()方法被调用");
    }
    private void getNum(String id){
        this.id = id;
        System.out.println(age+"\tStudent.getNum()方法被调用");

    }
    private static String getHeight(double height){
        System.out.println(height+"\tStudent.getHeight()方法被调用");
        return "";
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                '}';
    }
}

输出结果:

class reflectiondemo.Student
getCount
getNum
10	Student.getCount()方法被调用
10	Student.getNum()方法被调用
23.34	Student.getHeight()方法被调用
33.37	Student.getHeight()方法被调用
26.6	Student.getHeight()方法被调用
class java.lang.String

Process finished with exit code 0

课后作业1

课后作业1

代码示例:

package homework;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author wty
 * @date 2022/10/31 10:21
 */
public class HomeWork01 {
    @Test
    public void getHomeWork01() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> ptest = Class.forName("homework.PrivateTest");
        // 注意要用类的对象
        Object o = ptest.newInstance();

        Field name = ptest.getDeclaredField("name");
        name.setAccessible(true);
        name.set(o,"helloworld");

        Method getName = ptest.getMethod("getName");
        System.out.println(getName.invoke(o));


    }
}
class PrivateTest{
    private String name = "helloketty";

    public String getName() {
        //System.out.println("属性name:" + name);
        return name;
    }
}


输出示例:

helloworld

课后作业2

课后作业2
代码示例:

package homework;

import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author wty
 * @date 2022/10/31 10:47
 */
public class HomeWork02 {
    @Test
    public void getFileExercise() throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException {
        Class<File> fileClass = File.class;

        Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors();
        System.out.println("File的构造器有:");
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName()+"\t" + declaredConstructor);
        }
        System.out.println("==========");
        Constructor<File> constructor = fileClass.getConstructor(String.class);
        if (constructor.newInstance("E:\\mynew.txt").exists() == false){
            // 方法一:用文件对象直接创建
            //constructor.newInstance("E:\\mynew.txt").createNewFile();
            // 方法二:用反射创建
            File file = constructor.newInstance("E:\\mynew.txt");
            Method createNewFile = fileClass.getMethod("createNewFile");
            createNewFile.invoke(file);

            System.out.println("文件创建完毕");
        }else {
            System.out.println("文件已经存在");
        }

    }
}


结果展示:

File的构造器有:
java.io.File	public java.io.File(java.lang.String,java.lang.String)
java.io.File	public java.io.File(java.lang.String)
java.io.File	private java.io.File(java.lang.String,java.io.File)
java.io.File	public java.io.File(java.io.File,java.lang.String)
java.io.File	public java.io.File(java.net.URI)
java.io.File	private java.io.File(java.lang.String,int)
==========
文件已经存在

Process finished with exit code 0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心向阳光的天域

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值