随趣科技有限公司
随趣科技有限公司虚拟人技术传播者

公司成立于2021年,是全球范围内少数同时拥有全栈3D AIGC技术和自然语言生成式大模型技术的前沿人工智能公司。

󦌑136 2108 0965

󦘑136 2108 0965

󦗑1039900924

󦌡1039900924@qq.com

虚拟人类学方法,虚拟人技术可用于

2022-08-19344

1、Java中的虚拟方法virtual method是什么含义

   Java方法调用的虚分派

JUN | COMMENTS

本文通过介绍 Java 方法调用的虚分派,来加深对 Java 多态实现的理解。需要预先理解 Java 字节码和 JM 的基本框架。

虚分配(irtual Dispatch)

首先从字节码中对方法的调用说起。Java 的 bytecode 中方法的调用实现分为四种指令:

为最常见的情况,包含 virtual dispatch 机制;

是作为对 private 和构造方法的调用,绕过了 virtual dispatch;

的实现跟 invokevirtual 类似。

是对静态方法的调用。

其中最复杂的要属 invokevirtual 指令,它涉及到了多态的特性,使用 virtual dispatch 做方法调用。

virtual dispatch 机制会首先从 receiver(被调用方法的对象)的类的实现中查找对应的方法,如果没找到,则去父类查找,直到找到函数并实现调用,而不是依赖于引用的类型。

下面是一段有趣的代码。反映了 virtual dispatch 机制 和 一般的 field 访问的不同。

public class Greeting {

String intro = "Hello";

String target(){

return "world";

}

}

public class FrenchGreeting extends Greeting {

String intro = "Bonjour";

String target(){

return "le monde";

}

public static void main(String[] args){

Greeting english = new Greeting();

Greeting french = new FrenchGreeting();

( "," ());

( "," ());

(((FrenchGreeting)french).intro "," ((FrenchGreeting)french).target());

}

}

运行的结果为

Hello,world

Hello,le monde

Bonjour,le monde

前两行输出中,对于 intro 这个属性的访问,直接指向了父类中的变量,因为引用类型为父类。

第二行对于 target()的方法调用,则是指向了子类中的方法,虽然引用类型也为父类,但这是虚分派的结果,虚分派不管引用类型的,只查被调用对象的类型。

既然虚分派机制是从被调用对象本身的类开始查找,那么对于一个覆盖了父类中某方法的子类的对象,是无法调用父类中那个被覆盖的方法的吗?

在虚分派机制中这确实是不可以的。但却可以通过 invokespecial 实现。如下代码

public class FrenchGreeting extends Greeting {

String intro = "Bonjour";

String target(){

return "le monde";

}

public String func(){

return ();

}

public static void main(String[] args){

Greeting english = new Greeting();

FrenchGreeting french = new FrenchGreeting();

(());

}

}

func()就成功的调用了父类的方法 target(),虽然 target()已经被子类重写了。具体的调用细节,从字节码中可以看到:

ALOAD 0: this

INOKESPECIAL () : String

ARETURN

其中使用了 invokespecial 指令,而不是施行虚分派策略的 invokevirtual 指令。

方法表(Method Table)

介绍了虚分派,接下来介绍是它的一种实现方式 – 方法表。类似于 C的虚函数表 vtbl。

在有的 JM 实现中,使用了方法表机制实现虚分派,而有时候,为了节省内存可能不采用方法表的实现。

不要被方法表这个名字迷惑,它并不是记录所有方法的表。它是为虚分派,不会记录用 invokestatic 调用的静态方法和用 invokespecial 调用的构造函数和有方法。

JM 会在链接类的过程中,给类分配相应的方法表内存空间。每个类对应一个方法表。这些都是存在于 method area 区中的。这里与 C略有不同,C中每个对象的第一个指针就是指向了相应的虚函数表。而 Java 中每个对象索引到对应的类,在对应的类数据中对应一个方法表。(关于链接的更多信息,参见博文《Java 类的装载、链接和初始化》)

一种方法表的实现如下:

父类的方法比子类的方法先得到解析,即父类的方法相比子类的方法位于表的前列。

表中每项对应于一个方法,索引到实际方法的实现代码上。如果子类重写了父类中某个方法的代码,则该方法第一次出现的位置的索引更换到子类的实现代码上,而不会在方法表中出现新的项。

JM 运行时,当代码索引到一个方法时,是根据它在方法表中的偏移量来实现访问的。(第一次执行到调用指令时,会执行解析,将符索引替换为对应的直接索引)。

由于 invokevirtual 调用的方法在对应的类的方法表中都有固定的位置,直接索引的值可以用偏移量来表示。(符索引解析的最终目的是完成直接索引:对象方法和对象变量的调用都是用偏移量来表示直接索引的)

invokeinterface 与 invokevirtual 的比较

当使用 invokeinterface 来调用方法时,由于不同的类可以实现同一 interface,我们无法确定在某个类中的 inteface 中的方法处在哪个位置。于是,也就无法解析 CONSTANT_intefaceMethodrefinfo 为直接索引,而必须每次都执行一次在 methodtable 中的搜索了。 所以,在这种实现中,通过 invokeinterface 访问方法比通过 invokevirtual 访问明显慢很多。

参考:

irtual Dispatch

首先从字节码中对方法的调用说起。

java的bytecode中对方法的调用实现分为四种情况:

为最常见的情况,包含virtual dispatch机制;

,绕过了virtual dispatch;

其中最复杂的要属 invokevirtual .

virtual dispatch机制会首先从 receiver(调用该方法的对象)的类的实现中查找对应的方法,如果没找到,则去父类查找,直到找到函数并实现调用,而不是依赖于引用类型。

下面是一段有趣的代码。反映了virtual dispatch机制 和 一般的field访问的不同。

public class Greeting {

String intro = "Hello";

String target(){

return "world";

}

}

public class FrenchGreeting extends Greeting {

String intro = "Bonjour";

String target(){

return "le monde";

}

public static void main(String[] args){

Greeting english = new Greeting();

Greeting french = new FrenchGreeting();

( "," ());

( "," ());

(((FrenchGreeting)french).intro "," ((FrenchGreeting)french).target());

}

}

运行的结果为

Hello,world

Hello,le monde

Bonjour,le monde

其中的第二行是亮点。

对于intro这个filed的访问,直接指向了父类中的变量,因为引用 类型为父类。

而对于target的方法调用,则是指向了子类中的方法,虽然引用类型也为父类,但这是virtual dispatch的结果,virtual dispatch不管引用类型的,只查receiver的类型。

既然 虚分派 机制是从receiver对象的子类开始查找,由此看来,对于一个覆盖了父类中某方法的子类的对象,是无法调用父类中那个被覆盖的方法的吗?

在虚分派机制中这确实是不可以的。但却可以通过invokespecial实现。如下代码

public class FrenchGreeting extends Greeting {

String intro = "Bonjour";

String target(){

return "le monde";

}

public String func(){

return ();

}

public static void main(String[] args){

Greeting english = new Greeting();

FrenchGreeting french = new FrenchGreeting();

(());

}

}

func()就成功的调用了父类的方法target,虽然target已经被子类重写了。怎么实现的?让我们看一看func方法中生成的字节码:

ALOAD 0: this

INOKESPECIAL () : String

ARETURN

原来如此,它是通过invokespecial 指令来调用的。

如果删除jump那一段 程序可以正常运行,请问jump那段有什么问题??

C里才叫虚类。

Java里应该称为抽象类,类名前加abstract,不能够实例化。与接口不同的是:

1、一个子类只能继承一个抽象类,但能实现多个接口;

2、一个抽象类可以有构造方法,接口没有构造方法;

3、一个抽象类中的方法不一定是抽象方法,即其中的方法可以有实现(有方法体),接口中的方法都是抽象方法,不能有方法体,只有声明;

4、一个抽象类可以是public、private、protected、default,

接口只有public;

5、一个抽象类中的方法可以是public、private、protected、default,

接口中的方法只能是public和default。

虚拟人类学方法,虚拟人技术可用于  第1张

2、人类学最根本的研究方法是问卷法吗

   文化人类学的主要研究方法有:

田野调查法也称为田野工作,是一种对一个社会及其生活方式亲身从事的长期性的调查和体会工作。

这是文化人类学最有特色的研究法。文化人类学家特别注重通过直接的观察,收集每一手证据。

采用这种方法,人们在选择研究一种人类行为时,必须全面考察与之相关联的问题。

比较法在文化人类学的研究中无时无刻不在使用。

概念分析法即构建一个或若干个概念以分析各种社会文化现象。它首先从个别文化的经验材料中归纳出一般原则,然后把它作为分析文化的工具,以分析其他文化现象。

你的文献综述具体准备往哪个方向写,题目老师同意了没,具体有要要,需要多少字呢? 你可以告诉我具体的排版格式要,文献综述想写好,先要在图书馆找好相关资料,确定好题目与写作方向。老师同意后在下笔,还有什么不了解的可以直接问我,...

人类学是社会科学,因此需要开展调查研究,可以参考如下资料: 人类学研究的基本方法是田野民族志,也就是深入实地进行调查。

虚拟人类学方法,虚拟人技术可用于  第2张