面试官:Java 反射是什么?我回答不上来!

Java如何基于反射机制获取不同的类 主要介绍了Java如何基于反射机制获取不同的类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 立即下载

来源:cnblogs.com/hxsyl

  • 一.概念

  • 二.常用方法  

  • 三.典型例题

  • 四.Method类

  • 五.数组的反射

  • 六.结束语

一.概念

反射就是把Java的各种成分映射成相应的Java类。

Class类的构造方法是private,由JVM创建。

反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。(来自Sun)

JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。

反射是从1.2就有的,后面的三大框架都会用到反射机制,涉及到类"Class",无法直接new CLass(),其对象是内存里的一份字节码.

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

基本的 Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。Class 没有公共构造方法。

Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

Person p1 = new Person();
//下面的这三种方式都可以得到字节码
CLass c1 = Date.class();
p1.getClass();
//若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来
Class.forName("java.lang.String");

Class.forName()字节码已经加载到java虚拟机中,去得到字节码;java虚拟机中还没有生成字节码 用类加载器进行加载,加载的字节码缓冲到虚拟机中。

考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

import java.lang.reflect.*;

public class DumpMethods {
   public static void main(String args[]) {
      try {
           Class c = Class.forName("java.util.Stack");

           Method m[] = c.getDeclaredMethods();

           for (int i = 0; i < m.length; i++)
               System.out.println(m[i].toString());
      }
      catch (Throwable e){
            System.err.println(e);
      }
   }
}

public synchronized java.lang.Object java.util.Stack.pop()
public java.lang.Object java.util.Stack.push(java.lang.Object)
public boolean java.util.Stack.empty()
public synchronized java.lang.Object java.util.Stack.peek()
public synchronized int java.util.Stack.search(java.lang.Object)

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

以下示例使用 Class 对象来显示对象的类名:

void printClassName(Object obj) {
       System.out.println("The class of " + obj +
                     " is " + obj.getClass().getName());
}

还可以使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象。例如:

System.out.println("The name of class Foo is: "+Foo.class.getName());

在没有对象实例的时候,主要有两种办法。

//获得类类型的两种方式
Class cls1 = Role.class;
Class cls2 = Class.forName("yui.Role");

注意第二种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。现在得到cls1就可以创建一个Role类的实例了,利用Class的newInstance方法相当于调用类的默认的构造器。

Object o = cls1.newInstance();
//创建一个实例
//Object o1 = new Role();   //与上面的方法等价

二.常用方法

1.isPrimitive(判断是否是基本类型的字节码)

public class TestReflect {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str = "abc";
        Class cls1 = str.getClass();
        Class cls2 = String.class;
        Class cls3 = null;//必须要加上null
        try {
            cls3 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(cls1==cls2);
        System.out.println(cls1==cls3);

        System.out.println(cls1.isPrimitive());
        System.out.println(int.class.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型。
        System.out.println(int.class == Integer.class);
        System.out.println(int.class == Integer.TYPE);
        System.out.println(int[].class.isPrimitive());
        System.out.println(int[].class.isArray());
    }
}

结果:

true
true
false
true
false
true
false
true

2.getConstructor和getConstructors()

java中构造方法没有先后顺序,通过类型和参数个数区分。

public class TestReflect {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException {
        // TODO Auto-generated method stub
        String str = "abc";

        System.out.println(String.class.getConstructor(StringBuffer.class));
    }
}

3.Filed类代表某一类中的一个成员变量。

import java.lang.reflect.Field;
public class TestReflect {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
        ReflectPointer rp1 = new ReflectPointer(3,4);
        Field fieldx = rp1.getClass().getField("x");//必须是x或者y
        System.out.println(fieldx.get(rp1));

        /*
         * private的成员变量必须使用getDeclaredField,并setAccessible(true),否则看得到拿不到
         */
        Field fieldy = rp1.getClass().getDeclaredField("y");
        fieldy.setAccessible(true);//暴力反射
        System.out.println(fieldy.get(rp1));

    }
}

class ReflectPointer {

    public int x = 0;
    private int y = 0;

    public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source
        super();
        // TODO Auto-generated constructor stub
        this.x = x;
        this.y = y;
    }
}

三.典型例题

1.将所有String类型的成员变量里的b改成a。

import java.lang.reflect.Field;
public class TestReflect {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
        ReflectPointer rp1 = new ReflectPointer(3,4);
        changeBtoA(rp1);
        System.out.println(rp1);

    }

    private static void changeBtoA(Object obj) throws RuntimeException, Exception {
        Field[] fields = obj.getClass().getFields();

        for(Field field : fields) {
            //if(field.getType().equals(String.class))
            //由于字节码只有一份,用equals语义不准确
            if(field.getType()==String.class) {
                String oldValue = (String)field.get(obj);
                String newValue = oldValue.replace('b', 'a');
                field.set(obj,newValue);
            }
        }
    }
}

class ReflectPointer {

    private int x = 0;
    public int y = 0;
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "itcat";

    public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source
        super();
        // TODO Auto-generated constructor stub
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "ReflectPointer [str1=" + str1 + ", str2=" + str2 + ", str3="
                + str3 + "]";
    }
}

2.写一个程序根据用户提供的类名,调用该类的里的main方法。

为什么要用反射的方式呢?

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

public class TestReflect {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
        String str = args[0];
        /*
         * 这样会数组角标越界,因为压根没有这个字符数组
         * 需要右键在run as-configurations-arguments里输入b.Inter(完整类名)
         *
         */
        Method m = Class.forName(str).getMethod("main",String[].class);
        //下面这两种方式都可以,main方法需要一个参数

        m.invoke(null, new Object[]{new String[]{"111","222","333"}});
        m.invoke(null, (Object)new String[]{"111","222","333"});//这个可以说明,数组也是Object
        /*
         * m.invoke(null, new String[]{"111","222","333"})
         * 上面的不可以,因为java会自动拆包
         */
    }
}

class Inter {
    public static void main(String[] args) {
        for(Object obj : args) {
            System.out.println(obj);
        }
    }
}

3.模拟 instanceof 操作符

class S {
}

public class IsInstance {
   public static void main(String args[]) {
      try {
           Class cls = Class.forName("S");
           boolean b1 = cls.isInstance(new Integer(37));
           System.out.println(b1);
           boolean b2 = cls.isInstance(new S());
           System.out.println(b2);
      }
      catch (Throwable e) {
           System.err.println(e);
      }
   }
}

在这个例子中创建了一个S 类的 Class 对象,然后检查一些对象是否是S的实例。Integer(37) 不是,但 new S()是。

四.Method类

代表类(不是对象)中的某一方法。

import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*
 * 人在黑板上画圆,涉及三个对象,画圆需要圆心和半径,但是是私有的,画圆的方法
 * 分配给人不合适。
 *
 * 司机踩刹车,司机只是给列车发出指令,刹车的动作还需要列车去完成。
 *
 * 面试经常考面向对象的设计,比如人关门,人只是去推门。
 *
 * 这就是专家模式:谁拥有数据,谁就是专家,方法就分配给谁
 */
public class TestReflect {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
        String str = "shfsfs";
        //包开头是com表示是sun内部用的,java打头的才是用户的
        Method mtCharAt = String.class.getMethod("charAt", int.class);
        Object ch = mtCharAt.invoke(str,1);//若第一个参数是null,则肯定是静态方法
        System.out.println(ch);

        System.out.println(mtCharAt.invoke(str, new Object[]{2}));//1.4语法

    }

}

五.数组的反射

Array工具类用于完成数组的反射操作。

同类型同纬度有相同的字节码。

int.class和Integer.class不是同一份字节码,Integer.TYPE,TYPE代表包装类对应的基本类的字节码 int.class==Integer.TYPE。

import java.util.Arrays;

/*
 * 从这个例子看出即便字节码相同但是对象也不一定相同,根本不是一回事
 *
 */
public class TestReflect {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
        int[] a = new int[3];
        int[] b = new int[]{4,5,5};//直接赋值后不可以指定长度,否则CE
        int[][] c = new int[3][2];
        String[] d = new String[]{"jjj","kkkk"};
        System.out.println(a==b);//false
        System.out.println(a.getClass()==b.getClass());//true
        //System.out.println(a.getClass()==d.getClass());    //比较字节码a和cd也没法比
        System.out.println(a.getClass());//输出class [I
        System.out.println(a.getClass().getName());//输出[I,中括号表示数组,I表示整数

        System.out.println(a.getClass().getSuperclass());//输出class java.lang.Object
        System.out.println(d.getClass().getSuperclass());//输出class java.lang.Object

        //由于父类都是Object,下面都是可以的
        Object obj1 = a;//不可是Object[]
        Object obj2 = b;
        Object[] obj3 = c;//基本类型的一位数组只可以当做Object,非得还可以当做Object[]
        Object obj4 = d;

        //注意asList处理int[]和String[]的区别
        System.out.println(Arrays.asList(b));//1.4没有可变参数,使用的是数组,[[I@1bc4459]
        System.out.println(Arrays.asList(d));//[jjj, kkkk]

    }
}

六.结束语

以上就是反射机制的简单的使用,显然学过spring的朋友一定明白了,为什么可以通过配置文件就可以让我们获得指定的方法和变量,在我们创建对象的时候都是通过传进string实现的,就好像你需要什么,我们去为你生产,还有我们一直在用Object,这就说明java语言的动态特性,依赖性大大的降低了。

开源DIY | 打造会“听”会“走”的智能移动垃圾桶 本文详细介绍了如何利用Arduino和超声波传感器打造一款会“听”会“走”的智能移动垃圾桶。通过开源硬件和简单编程,实现声控移动和自动避障功能,适合创客爱好者和家庭DIY。项目成本控制在200元内,涵盖硬件搭建、电路连接和核心功能实现,是入门级机器人制作的理想选择。 阅读详情

相关推荐

S7-200 Smart 控制运动轴(脉冲电机/伺服)教程

S7-200 Smart 控制运动轴(脉冲电机/伺服) 结合本人刚接触触摸屏时候的踩坑经验,编写S7-200 Smart 控制运动轴(脉冲电机/伺服)的详细流程,给刚接触PLC的朋友提供一些经验指导。 本文详细介绍了S7-200 Smart 控制脉冲步进/伺服电机流程,包含接线方法及梯形图。希望对初学者有所帮助

xjbsw0的博客 5万+

Java反射

一.概念 反射就是把Java的各种成分映射成相应的Java类。 Class类的构造方法是private,由JVM创建。 反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,P...

weixin_45493969的博客 269

地图可视化类型大全

地图可视化类型大全: 散点地图 网格地图 聚合地图 气泡地图 热力图 Choropleth地图/分级设色地图/分级区域地图/着色地图/分级统计地图(百度百科这样翻译)/等值域地图/分段设色地图 Cartogram地图/变形地图/示意地图 规则形状地图 /RecMap/Demers Cartogram/瓷砖网格地图/DorlingMap 流型图(Flow Map)\流线图\流向图\轨迹地图 复合地图

codeuniverse的博客 3532

java反射面试_总结Java反射面试题(附答案)

反射机制是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。今天总结了java反射面试题10道,各位java程序员可以根据这篇java反射面试题,来回顾一下java反射的相关知识。1、java反射的作用是什么?答:反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法。在java中,只...

weixin_35763448的博客 8708

Fluent验证案例03:管道中湍流流动压降计算——采用kw-sst模型计算压降更为准确。

阅读(4053) 评论(0)本案例利用Fluent计算管道中湍流流动压降。

qq_15963745的博客 877

行业变革下的功能安全落地痛点3:高阶智驾安全责任转移 —— 从 “人为中心” 到 “机器主责” 的产业阵痛

文章围绕高阶智驾(L3 级)落地挑战,探讨安全责任从 “人控” 向 “机控” 转移的本质、技术短板导致的责任模糊、全球法规实践及技术 - 法规 - 保险的破局路径。

my9111526 126

Java面试题——Java反射

从网上搜集以及自己整理的常见Java面试题,找工作必备,拿走不谢

sunmenglove的博客 892

vscode中运行gcc -v命令失败了,提示:gcc不是内部或外部命令...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 976

java反射技术详解

为什么需要了解反射? 什么是反射? 反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,他允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性。程序中对象的类型一般都是在编译期就确定下来的,而当我们的程序在运行时,可能需要动态的加载一些类,这些类因为之前用不到,所以没有加载到jvm,这时,使用Java反射机制可以在运行期动态的创建对象并调用其

yangwu007的博客 907

Open3D 进阶(32)渐进三角网(PTD)地面滤波

渐进三角网地面滤波算法(Progressive TIN Densification, PTD)是一种广泛应用于机载LiDAR点云数据处理的滤波方法,旨在从复杂场景中精确分离地面点,以生成数字高程模型(DEM)。

点云侠的博客 1541

基于Simulink的无线充电系统LCC补偿网络建模与控制

本文详细介绍了基于Simulink的无线充电系统LCC补偿网络建模与控制方法。首先分析了无线充电系统面临的核心挑战,提出LCC补偿网络解决方案,阐述了其恒流输出和输入阻抗解耦原理。通过Simulink分步演示了系统建模过程,包括松耦合变压器、LCC+LC补偿网络、功率变换级搭建以及频率跟踪控制实现。仿真结果表明,LCC补偿系统在气隙变化和负载跳变下能保持输出电压稳定(波动±3%),效率达89%。文章还总结了工程实现要点,并探讨了动态充电、多负载系统等扩展应用。该教程为开发高效智能的无线充电系统提供了实用指导

amy_mhd的博客 63

Java反射是什么?看这篇绝对会了!

Java技术栈www.javastack.cn打开网站看更多优质文章作者:火星十一郎https://www.cnblogs.com/hxsyl一.概念反射就是把Java的各种成分映射成相...

Java技术栈,分享最主流的Java技术 585

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

面试官:Java反射是什么?别说你回答不上来!

你知道的越多,不知道的就越多,业余的像一棵小草!你来,我们一起精进!你不来,我和你的竞争对手一起精进!编辑:业余草来源:www.cnblogs.com/hxsyl推荐:https://w...

xmt1139057136的专栏 584

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

面试官:Java反射是什么?我回答不上来!

点击“开发者技术前线”,选择“星标????”在看|星标|留言, 真爱作者:火星十一郎https://www.cnblogs.com/hxsyl一.概念反射就是把Java的各种成分映射成...

开发者技术前线-DevolperFront 551

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

上一篇: 跟狗屎一样的代码,到底该如何重构?
下一篇: 重磅!阿里首推内部“SpringCloudAlibaba项目文档”这细节讲解,神了!
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值