有两个让我不太明白的调用:
1.http://smiky.iteye.com/admin/blogs/996590
2.
package org.gerry;
public class Son extends Parent
{
public void test()
{
super.test();
System.out.println( this );
this.duo();
}
public void duo()
{
System.out.println("Son duo");
}
}
package org.gerry;
public class Parent
{
public void test()
{
System.out.println("Parent test...");
System.out.println( this );
this.duo();
}
public void duo()
{
System.out.println("Parent duo");
}
}
package org.gerry;
public class client
{
public static void main(String[] args)
{
new Son().test();
}
}
第二个的结果相信会有人跟我一样弄错,父类的test()方法内会调用那个方法?子类or父类的?
字节码先上:
parent的test方法
public void test();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #21 // String Parent test...
5: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_0
12: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
15: aload_0
16: invokevirtual #32 // Method duo:()V
19: return
LineNumberTable:
line 7: 0
line 8: 8
line 9: 15
line 10: 19
LocalVariableTable:
Start Length Slot Name Signature
0 20 0 this Lorg/gerry/Parent;
可以看出偏移量为16的指令为invokevirtual,说明这个方法是个多态调用,但是看下面的变量表,很显示这个this是Parent类型的,根据方法解析规则:(下面是常量表中的类方法表
#32 = Methodref #1.#33 // org/gerry/Parent.duo:()V)
方法的符号引用在指令调用之前替换成直接引用,先找到#1对应的Parent(不用说Parent早就换成了Parent.class对应的直接引用),即然有了Class对象,接着就是在该类中查找#33对应的NameAndType类型常量池的索引,说白了就是在类中找duo方法,找得到的话就换成方法的直接引用
照上面的分析,结果应该是调用父类的duo()才对,可为什么调用的是子类的duo呢?可能有人说,invokevirtual表示调用多态方法啊,但是我父类中有duo方法啊,就算多态也应该找我自己的啊,轮不到子类啊
出现这种情况,只能在这种情况才可能,就是Parent的本地变量表中的this的直接引用就是指向 main方法中new的那个Son,在这种情况下多态才能体现出来(只有 invokevirtual对应的操作数this是Son,它才会动态分派到Son的duo方法)
从下面的打印结果能看出这点:Son中的this与Parent中的this指向的是同一个地址
Parent test...
org.gerry.Son@2f995c9a
Son duo
org.gerry.Son@2f995c9a
Son duo
还有一点顺带提一下,不知道对不对,
super根本就屁用没有,只不过指定编译器执行父类的方法,下面是Son的test()的字节码:
public void test();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #15 // Method org/gerry/Parent.test:()V
4: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_0
8: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
11: aload_0
12: invokevirtual #29 // Method duo:()V
15: return
LineNumberTable:
line 7: 0
line 8: 4
line 9: 11
line 10: 15
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lorg/gerry/Son;
从偏移为1的指令看出,它就是调用父类的test方法,而方法在执行的时候会传一个隐藏的this作为参数(从实际方法的本地方法表中可以看出),是不是这里是将Son的对象传到了Parent的test方法作为隐藏的this?估计也只有这个可能,
那么有什么方式可以获取到父类的对象呢?子类初始化时会初始化父类,那么生成的父类对象去那啦?可以调用到吗?如果调用不到的话在这种情况下算生成了几个对象?
对于上面第一个是不是也可以这样理解,对于属性只管其静态类型(本地变量表中的类型)?父类中的this的类型是父类本身,所以改奕的是父类的值,对子类无影响?
看来我是JS写多了,以为this是谁改变的就是谁的字段的值,走火入魔了
看来我的猜测是对的,将父类中的this强制改成子类,那么父类方法中操作的就是子类的属性了,看来对属性的操作只看静态类型
class A extends E{
int x;
int y;
public void setValue(int i,int j){
this.x = i;
this.y = j;
// B b = (B)this;
// b.x = i;
// b.y = j;
}
public int compute(){
return this.x * this.y;
}
}
分享到:
相关推荐
线程可以共享系统分派给这个进程的内存空间。 2、 定义线程的方法 定义线程的方法有两种:继承 Thread 类和实现 Runnable 接口。两种方法的本质上是一种方法,即都是通过 Thread 类建立线程,并运行 run() 方法。 ...
### Java并发编程笔记 #### 一、线程与进程 - **进程**: 是操作系统资源分配的基本单位,每个进程都有自己的独立内存空间。例如,当我们打开QQ或者音乐播放器时,实际上是在启动`qq.exe`或`Music.exe`这样的程序,...
深入理解 Java 虚拟机笔记 Java 虚拟机(JVM)是 Java 语言的运行环境,它负责解释和执行 Java 字节码。下面是 Java 虚拟机相关的知识点: 虚拟机内存结构 Java 虚拟机的内存结构主要包括以下几个部分: * 方法...
Spring框架是Java开发中的核心组件,它为应用程序提供...这些笔记将涵盖这些主题的基本概念、使用方法和示例,帮助初学者快速理解和掌握Spring生态系统。通过深入学习和实践,开发者能够构建出高效、可扩展的Java应用。
在处理请求时,Servlet容器会调用service()方法,根据请求类型分派到doGet()或doPost()等方法。最后,当Servlet不再需要时,服务器会调用destroy()方法,释放资源。 三、Servlet部署 Servlet通常通过在Web应用的web...
4. **服务阶段**: 用户请求到达,调用service()方法,根据HTTP方法分派到doGet()或doPost()。 5. **销毁阶段**: 当服务器关闭或Servlet不再需要时,调用destroy()方法进行清理。 **五、Servlet生命周期** 1. **加载...
3. 服务:每次有请求到达,Servlet容器都会调用`service()`方法,该方法会根据请求类型分派到`doGet()`或`doPost()`等具体处理方法。 4. 销毁:当Servlet不再使用或Web应用停止时,会调用`destroy()`方法释放资源。 ...
3. **重定向与请求分派**:重定向改变浏览器地址,分派则在服务器内部转发请求。 【Web应用属性与监听器】 1. **属性与参数**:属性是动态存储在特定范围(请求、会话、上下文)的数据,参数通常是配置项。 2. **...
- **请求分派(Forward)**:通过`RequestDispatcher`的`forward()`方法,服务器内部转发请求,用户在浏览器中看不到URL变化。 6. **HTTP请求和响应对象**: - **HttpServletRequest**:提供请求信息,如参数、头...
在服务阶段,每次请求都会调用`service()`方法,该方法会根据HTTP请求类型分派到`doGet()`或`doPost()`等具体处理方法。最后,当Servlet不再使用或者服务器关闭时,会调用`destroy()`方法释放资源,结束生命周期。 ...
4. final的作用:final关键字在Java中用于声明类、方法和变量。当final用来修饰一个类时,表示这个类不能被继承;当用来修饰方法时,表示方法不能被重写;当用来修饰变量时,表示变量一旦赋值之后,其值就不能被修改...
### 经典的Java Web培训教材知识点概览 #### 一、前言和体系结构 在本章节中,教材详细介绍了Java Web应用的基础概念和技术框架,重点覆盖了以下几个方面: 1. **HTTP协议基础** - HTTP(HyperText Transfer ...
声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其...
Spring MVC是一个基于Java的实现MVC设计模式的请求驱动类型的轻量级Web框架,通过分离控制器、模型对象、分派器以及处理程序对象来提供Web层的模型设计。Spring MVC是Spring框架的一部分,它通过一套注解,让POJO...
4. 服务:每当有新的请求到达,Servlet容器会调用Servlet的`service()`方法,该方法会根据请求类型分派到`doGet()`或`doPost()`等具体方法。 5. 销毁:当服务器关闭或Servlet不再需要时,容器会调用Servlet的`...
- **DispatcherServlet**:作为整个框架的入口点,负责接收请求并分派到相应的处理器。 - **Controller**:控制器处理用户请求,通常由开发者自定义,实现特定业务逻辑。 - **Model**:模型对象,包含了应用程序...
2. **GenericServlet**:这是一个抽象Servlet类,实现了Servlet和ServletConfig接口,提供了基本的`service()`方法,可以根据请求类型分派到`doGet()`, `doPost()`等方法。 3. **HttpServlet**:进一步抽象了...
1. **DispatcherServlet**:所有请求由DispatcherServlet接收,它负责分派请求给合适的Controller。 2. **HandlerMapping**:找到处理请求的Controller。 3. **Controller处理**:Controller执行业务逻辑,返回...
Struts2是一个强大的Java web开发框架,用于构建和维护可扩展、优雅的MVC应用程序。这个学习笔记和测试源代码的资源着重于Struts2中的视图类型与全局视图的概念,以及结果类型转换和全局结果的配置。 首先,我们要...