先看代码:
public class Test {
public static void testStatic(){
System.out.println("testStatic()");
}
public void testNonStatic(){
System.out.println("testNonStatic()");
}
public static void main(String[] args) {
Test.testStatic();
Test test = null;
test.testStatic();
test = new Test();
test.testStatic();
test.testNonStatic();
}
}
结果:
testStatic()
testStatic()
testStatic()
testNonStatic()
原因其实很简单,调用静态方法或者访问静态数据时根本不需要实例,如例子中test.testStatic(); ,这里的test是否为空根本无所谓,因为它存在的目的就是向编译器传达一个信号,"我要调用的是Test类的testStatic()方法,别给我搞错了啊!"。虽然java是面向对象的语言,但到底层执行依然是过程式的,这是计算机的本质决定的。因此,实例方法的调用不过是换了个形式而已,就是把对象引用本身作为第一个参数,比如test.testNonStatic();其实可以看作Test::testNonStatic(test);这里传入的参数test就是非静态方法中可以拿来用的this了。
换个形式可能更容易理解:
public void Test::testNonStatic(final Test this){……}
非静态方法里就可以使用this这个形参来访问数据了。调用非静态方法的时候会检查该实例是否为null。
最后,看一下main方法反编译代码:
public static void main(java.lang.String[]);
Code:
0: invokestatic #6; //Method testStatic:()V
3: aconst_null
4: astore_1
5: aload_1
6: pop
7: invokestatic #6; //Method testStatic:()V
10: new #7; //class Test
13: dup
14: invokespecial #8; //Method "":()V
17: astore_1
18: aload_1
19: pop
20: invokestatic #6; //Method testStatic:()V
23: aload_1
24: invokevirtual #9; //Method testNonStatic:()V
27: return
这里可以发现一个问题,当用类直接调用方法时,只需要1条指令:
invokestatic #6; //Method testStatic:()V
而用对象引用来调用却需要3条指令,而且前两条完全是无用功:
5: aload_1
6: pop //干嘛,耍我呢?
7: invokestatic #6; //Method testStatic:()V
刚把引用test放到栈顶就立马弹出去了,瞎折腾了一下。剩下的才是真正起作用的调用指令。很明显,test是否为null根本不用理会了。
这里发现一个问题,使用类直接调用静态方法不但是一个好的编码习惯,还可能有性能上的优势,毕竟使用对象引用来调用时白白浪费了两条指令。之所以说是"可能",因为jvm编译器完全有可能把这种无用指令优化掉。
还是非静态方法的调用规矩啊,
23: aload_1
24: invokevirtual #9; //Method testNonStatic:()V
将test作为唯一的参数,调用testNonStatic方法。invokevirtual会检查该参数,为null时抛异常。
分享到:
相关推荐
反射机制使得我们能够在运行时动态地获取类的信息,并且能够创建对象、调用方法、访问字段,甚至改变类的行为。在Java中,`java.lang.reflect`包提供了对反射的支持。 在“反射,动态加载指定类调用类中的方法”这...
3. **定义本地方法**:由于C#不支持直接传递方法作为参数,我们需要定义一个本地方法,该方法接受结构体参数并调用Delphi的存储过程: ```csharp private static void CallDelphiProcedure([In] TMyRecord record) ...
它可以用于调用父类的构造函数(`super()`),或者访问父类的字段和方法(`super.field`或`super.method()`)。在子类中,如果重写了父类的方法,可以通过`super`调用父类的原版方法。在示例中没有使用`super`,但它...
在上述示例中,静态方法`StaticMethod`调用了实例方法`InstanceMethod`是不可能的,因为静态方法不依赖于实例,无法直接访问实例的成员。如果需要在静态方法中使用实例成员,必须先创建实例。 总结来说,C#中的静态...
本文介绍了如何使用Java反射机制来创建get和set方法,并通过反射调用这些方法来访问对象的属性。这种方式虽然灵活,但在实际开发中应当谨慎使用,因为它可能会降低代码的性能和可维护性。了解反射机制的基本原理对于...
JNI为Java应用程序提供了一个接口,可以调用本地方法(即非Java代码),同时也允许本地方法调用Java代码。在Android环境中,JNI通常用于提高性能、利用硬件特性或者调用已有的C/C++库。 在Java层定义一个静态变量:...
例如,可以使用`MethodInfo`类的`Invoke`方法来调用方法。 ### 四、总结 通过上述分析,我们可以看出反射在C#中的强大功能。它可以让我们在运行时动态地获取并操作类的成员,这对于构建高度灵活和可扩展的应用程序...
1. **访问父类字段**:如果子类和父类有同名字段,`super.field` 可以访问父类的字段。 2. **调用父类方法**:`super.method()` 用来调用父类的非覆盖方法,特别是覆盖了父类方法的情况下。 3. **构造器链**:子类...
3. **启动BarTender并执行打印**:创建完`ProcessStartInfo`后,我们可以使用`Process`类的`Start`方法来启动BarTender并执行指定的操作: ```csharp Process barTenderProcess = new Process(); barTenderProcess....
描述:调用的方法中不会抛出异常,但是调用方法的时候尝试使用try catch 捕获异常; 处理方式:确认此方法的调用会不会导致异常的发生,如果不会抛出异常请去 掉try catch,确认方法调用会不会抛出异常关键是对方法...
例如,`super.someMethod()`调用父类的`someMethod`方法,`super.someField`访问父类的`someField`字段。 4. final关键字与继承 `final`关键字可以应用于类、方法和变量,表示不可改变或不可继承。如果一个类被...
- 另外,还可以尝试在Matlab端编写一个包装函数,该函数接收结构体作为输入,并将其转换为`sim`函数可以接受的形式。 #### 示例代码 假设C#端有如下代码片段: ```csharp using MathWorks.MATLAB.NET.Arrays; ...
这使得开发者可以在运行时动态地创建对象、调用方法或访问字段。RTTI主要通过两种方式实现: 1. **传统RTTI**:假设在编译阶段已经知道了所有类型信息,如通过`instanceof`关键字判断对象类型。 2. **反射机制**:...
在C#代码中,你需要在引用`System.Runtime.InteropServices`命名空间后,使用`DllImport`特性来声明一个静态的extern方法。例如,调用`CreateFile`函数: ```csharp [DllImport("coredll.dll", EntryPoint = ...
在JNI中,可以通过`FindClass`, `GetStaticFieldID`和`GetStatic*Field`(或`SetStatic*Field`)方法来获取和修改Java类的静态字段。 6. **线程安全**:在Android 5.0中,JNI函数默认运行在主线程之外,开发者需要...
这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法以及访问未导出的类等方面显得尤为有用。以下是对"JAVA反射机制的入门代码"的详细解释。 首先,我们要理解反射的基本概念...
此外,为了提高性能,实际应用中可以考虑使用序列化或克隆方法,或者针对特定类实现专门的拷贝构造函数或`copy()`方法。 总结来说,Java反射机制为我们提供了动态访问和操作类的能力,可以用来实现对象的深拷贝。...
有了父类的`Class`对象后,我们可以通过`getFields()`方法获取所有的public字段,或者使用`getDeclaredFields()`获取包括私有在内的所有字段: ```java Field[] fields = superClass.getDeclaredFields(); for ...
本文将详细介绍如何在C#中使用P/Invoke调用C/C++ DLL中的函数,并处理输入、输出字符串参数和结构类型参数。 首先,我们需要理解P/Invoke的概念。P/Invoke是.NET框架提供的一种机制,用于使托管代码能够访问非托管...
这部分信息可以帮助JVM执行方法调用、垃圾回收等操作。 2. **实例数据**:这是对象真正存储字段值的地方,包括类中的基本类型和引用类型。基本类型如int、char等占用固定大小的内存,而引用类型则指向其他对象的...