总结
这个月马上就又要过去了,还在找工作的小伙伴要做好准备了,小编整理了大厂java程序员面试涉及到的绝大部分面试题及答案,希望能帮助到大家
/**
- 通过反射获取类的所有方法
*/
private static void printMethods(){
//1.获取并输出类的名称
Class mClass = SonClass.class;
System.out.println(“类的名称:” + mClass.getName());
//2.1 获取所有 public 访问权限的方法
//包括自己声明和从父类继承的
Method[] mMethods = mClass.getMethods();
//2.2 获取所有本类的的方法(不问访问权限)
//Method[] mMethods = mClass.getDeclaredMethods();
//3.遍历所有方法
for (Method method :
mMethods) {
//获取并输出方法的访问权限(Modifiers:修饰符)
int modifiers = method.getModifiers();
System.out.print(Modifier.toString(modifiers) + " ");
//获取并输出方法的返回值类型
Class returnType = method.getReturnType();
System.out.print(returnType.getName() + " "
- method.getName() + "( ");
//获取并输出方法的所有参数
Parameter[] parameters = method.getParameters();
for (Parameter parameter:
parameters) {
System.out.print(parameter.getType().getName()
- " " + parameter.getName() + “,”);
}
//获取并输出方法抛出的异常
Class[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes.length == 0){
System.out.println(" )");
}
else {
for (Class c : exceptionTypes) {
System.out.println(" ) throws "
- c.getName());
}
}
}
}
同获取变量信息一样,需要注意注释中 2.1 与 2.2 的区别,下面看一下打印输出:
- 调用
getMethods()
方法
获取 SonClass
类所有 public
访问权限的方法,包括从父类继承的。打印信息中,printSonMsg()
方法来自 SonClass
类, printFatherMsg()
来自 FatherClass
类,其余方法来自 Object 类。
类的名称:obj.SonClass
public void printSonMsg( )
public void printFatherMsg( )
public final void wait( ) throws java.lang.InterruptedException
public final void wait( long arg0,int arg1, ) throws java.lang.InterruptedException
public final native void wait( long arg0, ) throws java.lang.InterruptedException
public boolean equals( java.lang.Object arg0, )
public java.lang.String toString( )
public native int hashCode( )
public final native java.lang.Class getClass( )
public final native void notify( )
public final native void notifyAll( )
- 调用
getDeclaredMethods()
方法
打印信息中,输出的都是 SonClass
类的方法,不问访问权限。
类的名称:obj.SonClass
private int getSonAge( )
private void setSonAge( int arg0, )
public void printSonMsg( )
private void setSonName( java.lang.String arg0, )
private java.lang.String getSonName( )
三、访问或操作类的私有变量和方法
================
在上面,我们成功获取了类的变量和方法信息,验证了在运行时 动态的获取信息 的观点。那么,仅仅是获取信息吗?我们接着往后看。
都知道,对象是无法访问或操作类的私有变量和方法的,但是,通过反射,我们就可以做到。没错,反射可以做到!下面,让我们一起探讨如何利用反射访问 类对象的私有方法 以及修改 私有变量或常量。
老规矩,先上测试类。
注:
-
请注意看测试类中变量和方法的修饰符(访问权限);
-
测试类仅供测试,不提倡实际开发时这么写 : )
TestClass.java
3.1 访问私有方法
以访问 TestClass
类中的私有方法 privateMethod(...)
为例,方法加参数是为了考虑最全的情况,很贴心有木有?先贴代码,看注释,最后我会重点解释部分代码。
/**
-
访问对象的私有方法
-
为简洁代码,在方法上抛出总的异常,实际开发别这样
*/
private static void getPrivateMethod() throws Exception{
//1. 获取 Class 类实例
TestClass testClass = new TestClass();
Class mClass = testClass.getClass();
//2. 获取私有方法
//第一个参数为要获取的私有方法的名称
//第二个为要获取方法的参数的类型,参数为 Class…,没有参数就是null
//方法参数也可这么写 :new Class[]{String.class , int.class}
Method privateMethod =
mClass.getDeclaredMethod(“privateMethod”, String.class, int.class);
//3. 开始操作方法
if (privateMethod != null) {
//获取私有方法的访问权
//只是获取访问权,并不是修改实际权限
privateMethod.setAccessible(true);
//使用 invoke 反射调用私有方法
//privateMethod 是获取到的私有方法
//testClass 要操作的对象
//后面两个参数传实参
privateMethod.invoke(testClass, "Java Reflect ", 666);
}
}
需要注意的是,第3步中的 setAccessible(true)
方法,是获取私有方法的访问权限,如果不加会报异常 IllegalAccessException,因为当前方法访问权限是“private”的,如下:
java.lang.IllegalAccessException: Class MainClass can not access a member of class obj.TestClass with modifiers “private”
正常运行后,打印如下,调用私有方法成功:
Java Reflect 666
3.2 修改私有变量
以修改 TestClass
类中的私有变量 MSG
为例,其初始值为 “Original” ,我们要修改为 “Modified”。老规矩,先上代码看注释。
/**
-
修改对象私有变量的值
-
为简洁代码,在方法上抛出总的异常
*/
private static void modifyPrivateFiled() throws Exception {
//1. 获取 Class 类实例
TestClass testClass = new TestClass();
Class mClass = testClass.getClass();
//2. 获取私有变量
Field privateField = mClass.getDeclaredField(“MSG”);
//3. 操作私有变量
if (privateField != null) {
//获取私有变量的访问权
privateField.setAccessible(true);
//修改私有变量,并输出以测试
System.out.println("Before Modify:MSG = " + testClass.getMsg());
//调用 set(object , value) 修改变量的值
//privateField 是获取到的私有变量
//testClass 要操作的对象
//“Modified” 为要修改成的值
privateField.set(testClass, “Modified”);
System.out.println("After Modify:MSG = " + testClass.getMsg());
}
}
此处代码和访问私有方法的逻辑差不多,就不再赘述,从输出信息看出 修改私有变量 成功:
Before Modify:MSG = Original
After Modify:MSG = Modified
3.3 修改私有常量
在 3.2 中,我们介绍了如何修改私有 变量,现在来说说如何修改私有 常量,
01. 真的能修改吗?
常量是指使用 final
修饰符修饰的成员属性,与变量的区别就在于有无 final
关键字修饰。在说之前,先补充一个知识点。
Java 虚拟机(JVM)在编译 .java
文件得到 .class
文件时,会优化我们的代码以提升效率。其中一个优化就是:JVM 在编译阶段会把引用常量的代码替换成具体的常量值,如下所示(部分代码)。
编译前的 .java
文件:
//注意是 String 类型的值
private final String FINAL_VALUE = “hello”;
if(FINAL_VALUE.equals(“world”)){
//do something
}
编译后得到的 .class
文件(当然,编译后是没有注释的):
private final String FINAL_VALUE = “hello”;
//替换为"hello"
if(“hello”.equals(“world”)){
//do something
}
但是,并不是所有常量都会优化。经测试对于 int
、long
、boolean
以及 String
这些基本类型 JVM 会优化,而对于 Integer
、Long
、Boolean
这种包装类型,或者其他诸如 Date
、Object
类型则不会被优化。
总结来说:对于基本类型的静态常量,JVM 在编译阶段会把引用此常量的代码替换成具体的常量值。
这么说来,在实际开发中,如果我们想修改某个类的常量值,恰好那个常量是基本类型的,岂不是无能为力了?反正我个人认为除非修改源码,否则真没办法!
这里所谓的无能为力是指:我们在程序运行时刻依然可以使用反射修改常量的值(后面会代码验证),但是 JVM 在编译阶段得到的 .class 文件已经将常量优化为具体的值,在运行阶段就直接使用具体的值了,所以即使修改了常量的值也已经毫无意义了。
下面我们验证这一点,在测试类 TestClass
类中添加如下代码:
接下来,是修改常量的值,先上代码,请仔细看注释:
/**
-
修改对象私有常量的值
-
为简洁代码,在方法上抛出总的异常,实际开发别这样
*/
private static void modifyFinalFiled() throws Exception {
//1. 获取 Class 类实例
TestClass testClass = new TestClass();
Class mClass = testClass.getClass();
//2. 获取私有常量
Field finalField = mClass.getDeclaredField(“FINAL_VALUE”);
//3. 修改常量的值
if (finalField != null) {
//获取私有常量的访问权
finalField.setAccessible(true);
//调用 finalField 的 getter 方法
//输出 FINAL_VALUE 修改前的值
System.out.println("Before Modify:FINAL_VALUE = "
- finalField.get(testClass));
//修改私有常量
finalField.set(testClass, “Modified”);
//调用 finalField 的 getter 方法
//输出 FINAL_VALUE 修改后的值
System.out.println("After Modify:FINAL_VALUE = "
- finalField.get(testClass));
//使用对象调用类的 getter 方法
//获取值并输出
System.out.println("Actually :FINAL_VALUE = "
- testClass.getFinalValue());
}
}
上面的代码不解释了,注释巨详细有木有!特别注意一下第3步的注释,然后来看看输出,已经迫不及待了,擦亮双眼:
Before Modify:FINAL_VALUE = FINAL
After Modify:FINAL_VALUE = Modified
Actually :FINAL_VALUE = FINAL
结果出来了:
总结
面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。
我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。
面试题及解析总结
大厂面试场景
知识点总结
VALUE = Modified
Actually :FINAL_VALUE = FINAL
结果出来了:
总结
面试前的“练手”还是很重要的,所以开始面试之前一定要准备好啊,不然也是耽搁面试官和自己的时间。
我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。
面试题及解析总结
[外链图片转存中…(img-ozsWy7eN-1715566744341)]
大厂面试场景
[外链图片转存中…(img-sPI7mxAz-1715566744341)]
知识点总结
[外链图片转存中…(img-8tLwVJrd-1715566744342)]