java学习-反射机制

Posted 懒佯佯大哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java学习-反射机制相关的知识,希望对你有一定的参考价值。

java反射介绍

  • 什么是反射?
    • 可以在运行过程中,动态的获取对象信息,操作对象,从而修改程序的状态、行为
    • 反射是java中非常重要的一环,是框架设计的灵魂
  • 什么是框架:
    • 框架是一个半成品的软件,在框架的基础上进行开发,可以极大的简化编码

java Class对象

  • 在了解java发射之前,需要了解Class对象,这是反射的基础:
    • Class类的实例,表示正在运行的Java应用程序的类和接口
    • 存在于java.lang中的一个包,拥有私有构造函数
    • Class对象:在加载时由Java虚拟机调用类加载器中defineClass对象构造的
  • 获取Class对象的四种方式:
    • 方式1:Class.forName(“全类名”):动态加载字节码进内存:多用于配置文件读取,比如spring中的配置中读取driverClass
    • 方式2:类名.class:获取反射对象,多用于参数传递
    • 方式3:Object.getClass():多用于对象的获取字节码的方式
    • 方式4:内置的类型的TYPE(部分java内置的存在):Integer.TYPE.getClass();
  • 注意1:方式2和方式3返回类型是不一样的:
类名.classObject.getClass()
class是类的属性getClass是类的方法
静态解析,编译器解析动态加载,运行期确定
返回确定:Class<类>返回为向上限定,动态:Class<? Extends Object>
Class<Bird> birdClass = Bird.class;  // 返回具体类,为静态解析
Class<? extends Bird> aClass = bird.getClass();  // 返回向上限定类,可以返回子类信息,有多态能力
  • 注意2:同一个字节码文件,只会被加载器加载一次,故:
    • 上面四种方式获取的Class对象,都是同一个:可以通过hashCode()方法判断
    • 都可以通过newInstance创建对象
class BirdTest 
    public static void main(String[] args) throws Exception
        // 三种获取Class的方式,并且都可以newInstance创建对象
        Bird bird = Bird.class.newInstance();
        Bird bird1 = (Bird) Class.forName("classTest.Bird").newInstance();
        Bird bird2 = new Bird().getClass().newInstance();
        System.out.println(bird);
        System.out.println(bird1);
        System.out.println(bird2);
    

  • 万物皆对象Class:
@Test
public void testAllIsClass() 
    System.out.println("对象Class:" + Object.class);
    System.out.println("接口Class:" + Comparable.class);
    System.out.println("一维数组Class:" + String[].class);
    System.out.println("二维数组Class" + int[][].class);
    System.out.println("注解Class:" + Override.class);
    System.out.println("枚举Class:" + ElementType.class);
    System.out.println("基础类型Class:" + int.class);
    System.out.println("void类型Class:" + void.class);
    System.out.println("Class自身的class:" + Class.class);

    System.out.println("类型一样,维度一样的数组,拥有同样的Class(hascode一样):");
    System.out.println(new int[10].hashCode());
    System.out.println(new int[50].hashCode());

输出:

对象Class:class java.lang.Object
接口Class:interface java.lang.Comparable
一维数组Class:class [Ljava.lang.String;      # 一维数组,有一个中括号
二维数组Classclass [[I             # 二维数组,有两个中括号
注解Class:interface java.lang.Override
枚举Class:class java.lang.annotation.ElementType
基础类型Class:int
void类型Class:void
Class自身的class:class java.lang.Class
类型一样,维度一样的数组,拥有同样的Class(hascode一样):
2121744517
2121744517

Class对象使用

可以获取/操作如下对象:
  • 成员变量Filed
  • 成员函数Method
  • 构造函数Constructor
  • 注解Annotation
  • 实现的接口Interfaces
  • 父类SuperClass
  • 包名Package
  • 枚举元素EnumConstants
  • 判断是否是接口、注解、实例匹配等等
代码:
  • 创建测试类Anamal:
package classTest;

public interface Anamal 
    void sing();


  • 创建测试类Fly:
package classTest;

class Fly 


  • 创建测试注解:
package classTest;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE, ElementType.METHOD, ElementType.FIELD)
// 注意,发射获取的注解,需要为RUNTIME.  因为SOURCE和CLASS无法在运行阶段被获取
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation 
    String value() default "";
    String user() default "lanyyyy";


  • 创建测试类Bird:
package classTest;

@MyAnnotation(value = "我的注解")
public class Bird extends Fly implements Anamal 
    public String name;
    private int age;

    enum xEnums 
        a,
        b,
        c
    

    public Bird(String name, int age) 
        this.name = name;
        this.age = age;
    

    public Bird() 
    

    private Bird(int age) 
        this.age = age;
    

    private void fly() 
        System.out.println("I can fly...");
    

    @Override
    public void sing() 
        System.out.println("I can sing...");
    

    @MyAnnotation
    protected void sleep(int a) 
        System.out.println("I am sleep " + a + " s");
    

    @Override
    @MyAnnotation
    public String toString() 
        return "Bird" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '';
    


  • Field操作:
    @Test
    public void test1Field() throws Exception 
        // 1. 获取成员变量
        System.out.println("################# 1. 获取成员变量 #################");
        Field name = birdClass.getField("name");    // 获取公有变量
        Field[] fields = birdClass.getFields();         // 获取所有公有变量
        Field[] declaredFields = birdClass.getDeclaredFields(); // 获取所有公有变量
        Field age = birdClass.getDeclaredField("age");  // 获取指定名称的变量
        System.out.println("getFiled: " + name);
        System.out.println("getDeclaredField" + age);
        for (Field field : fields) 
            System.out.println("getFileds: " + field);
        
        for (Field declaredField : declaredFields) 
            System.out.println("getDeclaredFields: " + declaredField);
        
        System.out.println("setAccessible是启动、禁用访问安全检查的开关");
        System.out.println("暴力反射修改变量前:" + bird);
        age.setAccessible(true);
        age.setInt(bird, 22);
        System.out.println("暴力反射修改变量后:" + bird);

    

输出:

################# 1. 获取成员变量 #################
getFiled: public java.lang.String classTest.Bird.name
getDeclaredFieldprivate int classTest.Bird.age
getFileds: public java.lang.String classTest.Bird.name
getDeclaredFields: public java.lang.String classTest.Bird.name
getDeclaredFields: private int classTest.Bird.age
setAccessible是启动、禁用访问安全检查的开关
暴力反射修改变量前:Birdname='null', age=0
暴力反射修改变量后:Birdname='null', age=22
  • 操作方法:
    @Test
    public void test2Method() throws Exception 
        // 2. 获取成员方法
        System.out.println("################# 2. 获取成员方法 #################");
        // 注意区别:
        //  getMethods:当前类公共方法 + 父类公共方法
        //  getDeclaredMethods:当前类所有方法
        Method sing = birdClass.getMethod("sing");  // 获取sing方法(必须是公共的)
        Method[] methods = birdClass.getMethods();
        Method say = birdClass.getDeclaredMethod("fly");
        Method[] declaredMethods = birdClass.getDeclaredMethods();
        System.out.println("getMethod: " + sing);
        System.out.println("getDeclaredMethod: " + say);
        for (Method method : methods) 
            System.out.println("getMethods: " + method);
        
        for (Method declaredMethod : declaredMethods) 
            System.out.println("getDeclaredMethods: " + declaredMethod);
        
        System.out.println("调用一下私有方法-需要暴力反射: ");
        Method fly = birdClass.getDeclaredMethod("fly");
        fly.setAccessible(true);
        fly.invoke(bird);
        System.out.println("调用一下公有方法-带参: ");
        for (Method declaredMethod : declaredMethods) 
            if (declaredMethod.getName().equals("sleep")) 
                declaredMethod.invoke(bird, 1111);
            
        
    

输出:

################# 2. 获取成员方法 #################
getMethod: public void classTest.Bird.sing()
getDeclaredMethod: private void classTest.Bird.fly()
getMethods: public void classTest.Bird.sing()
getMethods: public java.lang.String classTest.Bird.toString()
getMethods: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
getMethods: public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
getMethods: public final void java.lang.Object.wait() throws java.lang.InterruptedException
getMethods: public boolean java.lang.Object.equals(java.lang.Object)
getMethods: public native int java.lang.Object.hashCode()
getMethods: public final native java.lang.Class java.lang.Object.getClass()
getMethods: public final native void java.lang.Object.notify()
getMethods: public final native void java.lang.Object.notifyAll()
getDeclaredMethods: public void classTest.Bird.sing()
getDeclaredMethods: private void classTest.Bird.fly()
getDeclaredMethods: public java.lang.String classTest.Bird.toString()
getDeclaredMethods: protected void classTest.Bird.sleep(int)
调用一下私有方法-需要暴力反射: 
I can fly...
调用一下公有方法-带参: 
I am sleep 1111 s
  • 操作构造函数
    @Test
    public void test3Constructor() throws Exception 
        System.out.println("################# 3. 获取构造函数 #################");
        Constructor<?>[] constructors = birdClass.getConstructors();    // 获取公共构造函数
        Constructor<?>[] declaredConstructors = birdClass.getDeclaredConstructors();
        System.out.println("getConstructors 公共构造函数");
        for (Constructor<?> constructor : constructors) 
            System.out.println("getConstructors: " + constructor.toString());
        
        System.out.println("getDeclaredConstructors  所有构造函数");
        for (Constructor<?> declaredConstructor : declaredConstructors) 
            System.out.println("getDeclaredConstructors: " + declaredConstructor.toString());
            System.out.println("构造函数参数个数:" + declaredConstructor.getParameterCount());
        

        // 利用反射创建对象
        System.out.println("直接new:" + new Bird());
        // newInstance默认调用的是无参public构造函数,如果构造为私有,会报错异常
        System.out.println("newInstance(默认调用空构造函数,且为public):" + Bird.class.newInstance());
        // 获取构造函数,测试:获取私有的、int入参的构造函数
        Constructor<Bird> declaredConstructor = birdClass.getDeclaredConstructor(int.class);
        declaredConstructor.setAccessible(true);  // 需要暴力反射
        Bird birdRef = declaredConstructor.newInstance(100);
        System.out.println("反射获取构造函数: " + birdRef);
    

输出:

################# 3. 获取构造函数 #################
getConstructors 公共构造函数
getConstructors: public classTest.Bird(java.lang.String,int)
getConstructors: public classTest.Bird()
getDeclaredConstructors  所有构造函数
getDeclaredConstructors: public classTest.Bird(java.lang.String,int)
构造函数参数个数:2
getDeclaredConstructors: private classTest.Bird(int)
构造函数参数个数:1
getDeclaredConstructors: public classTest.Bird()
构造函数参数个数:0
直接new:Birdname='null', age=0
newInstance(默认调用空构造函数,且为public):Birdname='null', age=0
反射获取构造函数: Birdname='null', age=100
  • 操作注解:
    /**
     * 测试获取注解
     */
    @Test
    public void test4Annotation() 
        System.out.println("################# 4. 获取所有注解 #################");
        System.out.println("---------获取类上注解:");
        // 注意自定义注解的范围
        Annotation[] annotations = birdClass.getDeclaredAnnotations();
        for (Annotation annotation : annotations) 
            System.out.println(annotation);
        
        System.out.println("---------获取指定注解:");
        MyAnnotation declaredAnnotation = birdClass.getDeclaredAnnotation(MyAnnotation.class);
        System.out.println("指定注解value值:" + declaredAnnotation.value());
        System.out.println("指定注解user值:" + declaredAnnotation.user());

        System.out.println("---------获取方法上的注解: ");
        Method[] declaredMethods = birdClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) 
            Annotation[] annotations1 = declaredMethod.getDeclaredAnnotations();
            if (annotations1 != null && annotations.length != 0) 
                System.out.println(declaredMethod.getName() + "上的注解为:" + Arrays.toString(annotations1));
            
        
    

输出:

################# 4. 获取所有注解 #################
---------获取类上注解:
@classTest.MyAnnotation(user=lanyyyy, value=我的注解)
---------获取指定注解:
指定注解value值:我的注解
指定注解user值:lanyyyy
---------获取方法上的注解: 
sing上的注解为:[]
fly上的注解为:[]
toString上的注解为:[@classTest.MyAnnotation(user=lanyyyy, value=)]
sleep上的注解为:[@classTest.MyAnnotation(user=lanyyyy, value=)]
  • 操作接口:
    /**
     * 测试父接口类
     */
    @Test
    public void test5Interfaces() 
        System.out.println("################# 5. 测试父接口类 #################");
        Class<?>[] interfaces = birdClass.getInterfaces();
        System.out.println("父接口为:" + Arrays.toString(interfaces));
    

输出:

################# 5. 测试父接口类 #################
父接口为:[interface classTest.Anamal]
  • 操作直接父类
    /**
     * 获取直接父类
     */
    @Test
    public void test6SuperClass() 
        System.out.println("################# 6. 获取直接父类 #################");
        Class<? super Bird> superclass = birdClass.getSuperclass();
        System.out.println("直接父类为:" + superclass);
    

输出:

```################# 6. 获取直接父类 #################
直接父类为:class classTest.Fly
  • 操作包
    /**
     * 测试包
     */
    @Test
    public void test7Package() 
        System.out.println("################# 7. 测试包名 #################");
        Package aPackage = birdClass.getPackage();
        System.以上是关于java学习-反射机制的主要内容,如果未能解决你的问题,请参考以下文章

JAVA反射机制

Java反射机制

Java高级-反射机制

Java基础:Java的反射机制

Java反射机制详解一

Java - 反射