java面试笔试题及答案,Java反射的常见用法

本文详细介绍了Java中的反射机制,包括如何通过Class.forName和newInstance加载类,以及如何通过反射调用类的构造函数和方法,展示了实例代码和Class类在实际项目中的应用,强调了工厂模式中newInstance的类加载原理。
摘要由CSDN通过智能技术生成

在第3行定义的MyFuncClass这个类里,我们定义了2个构造函数和3个方法。

10 public class ReflectionReadFunc {

11 public static void main(String[] args) {

12 Class clazz = MyFuncClass.class;

13 Method[] methods = clazz.getDeclaredMethods();

14 for (Method method : methods)

15 { System.out.println(method); }

16 //得到所有的构造函数

17 Constructor[] c1 = clazz.getDeclaredConstructors();

18 //输出所有的构造函数

19 for(Constructor ct : c1)

20 { System.out.println(ct); }

21 }

22 }

在main函数的第12行,我们同样是通过了类名.class的方式(也就是MyFuncClass.class的方式)得到了Class类型的clazz对象。

在第13行里,是通过了getDeclaredMethods方法得到了MyFuncClass类的所有方法,并在第14行的for循环里输出了各方法。在第17行里,是通过了getDeclaredConstructors方法得到了所有的构造函数,并通过第19行的循环输出。

本代码的输出结果如下所示,其中第1到第3行输出的是类的方法,第4和第5行输出的是类的构造函数。

1 private void MyFuncClass.f1()

2 protected int MyFuncClass.f2(int)

3 public java.lang.String MyFuncClass.f2(java.lang.String)

4 public MyFuncClass()

5 public MyFuncClass(int)

不过在实际的项目里,我们一般不会仅仅“查看”类的属性和方法,在更多的情况里,我们是通过反射装载和调用类里的方法。

3 通过forName和newInstance方法加载类

在前文JDBC操作数据库的代码里,我们看到在创建数据库连接对象(Connection)之前,需要通过Class.forName(“com.mysql.jdbc.Driver”);的代码来装载数据库(这里是MySQL)的驱动。

可以说,Class类的forName方法最常见的用法就是装载数据库的驱动,以至于不少人会错误地认为这个方法的作用是“装载类”。

其实forName方法的作用仅仅是返回一个Class类型的对象,它一般会和newInstance方法配套使用,而newInstance方法的作用才是加载类。

通过下面的ForClassDemo.java这段代码,我们来看下综合使用forName和newInstance这两个方法加载对象的方式。

1 class MyClass{

2 public void print()

3 { System.out.println(“Java”); }

4 }

5 public class ForClassDemo {

6 public static void main(String[] args) {

7 //通过new创建类和使用类的方式

8 MyClass myClassObj = new MyClass();

9 myClassObj.print();//输出是Java

10 //通过forName和newInstance加载类的方式

11 try {

12 Class<?> clazz = Class.forName(“MyClass”);

13 MyClass myClass = (MyClass)clazz.newInstance();

14 myClass.print();//输出是Java

15 } catch (ClassNotFoundException e) {

16 e.printStackTrace();

17 } catch (InstantiationException e) {

18 e.printStackTrace();

19 } catch (IllegalAccessException e) {

20 e.printStackTrace();

21 }

22 }

23 }

在第1行定义的MyClass这个类里,我们在其中的第2行定义了一个print方法。

Main函数的第8和第9行里,我们演示了通过常规new的方式创建和使用类的方式,通过第9行,我们能输出“Java”这个字符串。

在第12行,我们通过Class.forName(“MyClass”)方法返回了一个Class类型的对象,请注意,forName方法的作用不是“加载MyClass类”,而是返回一个包含MyClass信息的Class类型的对象。这里我们是通过第13行的newInstance方法,加载了一个MyClass类型的对象,并在第14行调用了其中的print方法。

既然forName方法的作用仅仅是“返回Class类型的对象”,那么在JDBC部分的代码里,为什么我们能通过Class.forName(“com.mysql.jdbc.Driver”);代码来装载MySQL的驱动呢?在MySQL的com.mysql.jdbc.Driver驱动类中有如下的一段静态初始化代码。

1 static {

2 try {

3 java.sql.DriverManager.registerDriver(new Driver());

4 } catch (SQLException e) {

5 throw new RuntimeException(“Can’t register driver!”);

6 }

7 }

也就是说,当我们调用Class.forName方法后,会通过执行这段代码会新建一个Driver的对象,并调用第3行的DriverManager.registerDriver把刚创建的Driver对象注册到DriverManager里。

在上述的代码里,我们看到了除了new之外,我们还能通过newInstance来创建对象。

其实这里说“创建”并不准确,虽然说通过new和newInstance我们都能得到一个可用的对象,但newInstance的作用其实是通过Java虚拟机的类加载机制把指定的类加载到内存里。

我们在工厂模式中,经常会通过newInstance方法来加载类,但这个方法只能是通过调用类的无参构造函数来加载类,如果我们在创建对象时需要传入参数,那么就得使用new来调用对应的带参的构造函数了。

4 通过反射机制调用类的方法

如果我们通过反射机制来调用类的方式,那么就得解决三个问题,第一,通过什么方式来调?第二,如何传入参数,第三,如何得到返回结果?

通过下面的CallFuncDemo.java代码,我们将通过反射来调用类里的方法,在其中我们能看下上述三个问题的解决方法。

1 import java.lang.reflect.Constructor;

2 import java.lang.reflect.InvocationTargetException;

3 import java.lang.reflect.Method;

4 class Person {

5 private String name;

6 public Person(String name)

7 {this.name = name;}

8 public void saySkill(String skill) {

9 System.out.println(“Name is:”+name+“,skill is:” + skill);

10 }

11 public int addSalary(int current)

12 { return current + 100;}

13 }

在第4行里,我们定义了一个Person类,在其中的第6行里,我们定义了一个带参的构造函数,在第8行里,我们定义了一个带参但无返回值得saySkill方法,在第11行里,我们定义了一个带参而且返回int类型的addSalary方法。

14 public class CallFuncDemo {

15 public static void main(String[] args) {

16 Class c1azz = null;

17 Constructor c = null;

18 try {

19 c1azz = Class.forName(“Person”);

20 c = c1azz.getDeclaredConstructor(String.class);

21 Person p = (Person)c.newInstance(“Peter”);

22 //output: Name is:Peter, skill is:java

23 p.saySkill(“Java”);

24 // 调用方法,必须传递对象实例,同时传递参数值

25 Method method1 = c1azz.getMethod(“saySkill”, String.class);

26 //因为没返回值,所以能直接调

27 //输出结果是Name is:Peter, skill is:C#

28 method1.invoke(p, “C#”);

29 Method method2 = c1azz.getMethod(“addSalary”, int.class);

30 Object invoke = method2.invoke(p, 100);

31 //输出200

32 System.out.println(invoke);

33 } catch (ClassNotFoundException e) {

34 e.printStackTrace();

35 } catch (NoSuchMethodException e1) {

36 e1.printStackTrace();

37 } catch (InstantiationException e) {

38 e.printStackTrace();

39 } catch (IllegalAccessException e) {

40 e.printStackTrace();

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

在这里,由于面试中MySQL问的比较多,因此也就在此以MySQL为例为大家总结分享。但是你要学习的往往不止这一点,还有一些主流框架的使用,Spring源码的学习,Mybatis源码的学习等等都是需要掌握的,我也把这些知识点都整理起来了

面试真题

Spring源码笔记

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

在这里,由于面试中MySQL问的比较多,因此也就在此以MySQL为例为大家总结分享。但是你要学习的往往不止这一点,还有一些主流框架的使用,Spring源码的学习,Mybatis源码的学习等等都是需要掌握的,我也把这些知识点都整理起来了

[外链图片转存中…(img-aKw6ikm1-1713315379994)]

[外链图片转存中…(img-BaqT2TL3-1713315379994)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值