`
idealab
  • 浏览: 197738 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

区别类方法、实例方法和字段的调用

    博客分类:
  • Java
阅读更多
     本例根据一个实例来说明类方法和实例方法调用的区别,以及不同修饰符下的属性调用的区别,并对这种区别作出解释。
     父类定义:
public class Parent{
	public static String name = "父类的名字,静态常量";
	public final int age = 40;
	public String birth = "父类生日,变量";
	public static void sayHello(){
		System.out.println("父类的类方法,Hello Parent~");
	}
	public void sayBye(){
		System.out.println("父类的实例方法,Bye Parent~");
	}
}

     子类定义:
public class Son extends Parent{
	public static String name = "子类名字,静态变量";
	public final int age = 20;
	public String birth = "子类生日,变量";

	public static void sayHello(){
		System.out.println("子类的类方法,Hello Child!");
	}
	public void sayBye(){
		System.out.println("子类的实例方法,Bye Child!");
	}
	public static void main(String[] args){
		//1
		Parent obj1 = new Son();
		System.out.println(obj1.name);
		System.out.println(obj1.age);
		System.out.println(obj1.birth);
		obj1.sayHello();
		obj1.sayBye();
	}
}

输出结果:
  
引用

父类的名字,静态常量
40
父类生日,变量
父类的类方法,Hello Parent~
子类的实例方法,Bye Child

    
      主函数中声明了对Parent的引用obj1,这个引用指向Son的对象,即实际对象是利用new Son()所创建的实例。
      上例中,obj1对调用了Parent类的静态方法sayHello(),而调用了Son类的实例方法sayHello()。对类方法和实例方法调用的区别,《深入Java虚拟机》中有这样一段话可以解释:
引用
当JVM调用一个类方法时,它会基于对象引用的类型(通常在编译时可知)来选择所调用的方法。相反,当JVM调用一个实例方法是,它会基于实际对象的类(只能在运行时得知)来选择所调用的方法。

对象引用obj1的类型Parent自加载进入JVM之后便在内存的方法区维护了静态方法,而Son类的实例方法sayBye()是在被实际对象调用的时候才动态连接的。
      基于上面分析可以推测,因为类在方法区中还维护了字段信息、类(静态)变量、常量池,JVM调用一个字段时,它将基于对象引用的类型来选择所调用的字段,故obj1调用的字段皆来自于父类Parent。

注:常量池:常量池就是该类型所用常量的一个有序集合,包括直接常量(string、integer和floating point常量)和对其他类型、字段和方法的符号引用。池中的数据项就像数组一样是通过索引访问的,因为常量池存储了相应类型所用到的所有类型、字段和方法的符号引用,所以他在java程序的动态连接性中起到核心作用。
分享到:
评论
11 楼 C_J 2009-04-28  
xiasheng 写道
是不是一般方法,当类被加载的时候已经被编译,但并未连结,页静态方法则是在类加载时就已经被连结了???/



我的理解:是的

所有方法都被编译

静态在加载就连接

一般在new操作时进行连接
10 楼 xiasheng 2009-04-28  
是不是一般方法,当类被加载的时候已经被编译,但并未连结,页静态方法则是在类加载时就已经被连结了???/
9 楼 C_J 2009-04-22  
哈哈  首先感谢你的祝福

引用
这个问题不在于Test是可变类还是不可变的

不同意
你可以试试传个
String 对象进去

引用
这就意味着call()方法里的t“复制”了obj,和obj指向Test的同一个实例(也就是实际对象)。

同意
这里的复制,不管在C++也好,JAVA也好都是“参数拷贝”。这句话咱达成了共识。

引用
无论是obj.setName("abc");还是t.setName("abc");其实都调用了实际对象的那个实例方法


同意
因为都指向了同一个地址


8 楼 idealab 2009-04-22  
首先希望共患难的兄弟能够尽早振作起来,找工作十有八九不如意,心态要好才能越来越坚强,祝早日找到满意的工作!

这个问题不在于Test是可变类还是不可变的,而是关于以类实例为参数的方法倒底传入了什么!在java中,传入的实际是引用的拷贝,类似于你以前说的“副本”,这就意味着call()方法里的t“复制”了obj,和obj指向Test的同一个实例(也就是实际对象)。但同时,我在贴子最开始有个引用:
引用
当JVM调用一个类方法时,它会基于对象引用的类型(通常在编译时可知)来选择所调用的方法。相反,当JVM调用一个实例方法是,它会基于实际对象的类(只能在运行时得知)来选择所调用的方法。

这样看,无论是obj.setName("abc");还是t.setName("abc");其实都调用了实际对象的那个实例方法。但是t=t2;这句便只是让t具有了指向t2的指针。
7 楼 C_J 2009-04-22  
我觉得我们沟通还是没那么充分

引用
public void call(Test t) {
           Test t2 = new Test();
           t2.setName("cba');
           t.setName("abc");
           t = t2 ;
        }

        public static void main(String[] arg) {
       Test obj = new Test();
           call (obj) ;
           System.out.println("obj"+obj.getName());
        }


这位大哥的Test没有告诉我是不可变类和可变类(暂认为是可变类)
    所以操作的是指针,传递的也可以认为是指针
    竟然是可变类,所以 t.setName("abc"); 是行得通的,因为他们指向的是同一个地址
    但还是用C++的方式来理解的话

    t和obj都是“指针”(目前产生了2个指针),目前指向了同一个地址

    然后 t=t2,这里只改变了 t 这个“指针”,并没有改变“指针内容”,所以作者说 并没有影响“obj”,所以打出的是abc 

 
其实final就有点“引用”的味道了。用C++的指针概念来理解JAVA对象也不错嘛
哎,其实是经历了一次惨痛的面试!!
6 楼 idealab 2009-04-20  
Java中开发人员不可以操作指针这是大学课程中就讲过的。引用在JVM中直接就是指向对象的指针,而不是你所理解的C++中对象的副本。正因为此,通过引用是可以找到对象并其做更改。

关于参数传递:如果对象作为参数传递给方法,则传递的是引用的“拷贝”,但是利用该拷贝调用方法时,却调用了所指向的实际对象的方法,因此可以更改对象,详细信息请参考:http://www.iteye.com/topic/4189#

个人感觉C_J总是根据C++经验去理解Java,Java中很多事情是没那么复杂的。比如
对JAVA中的可变类,我理解的是直接操作指针的,如参数传递进去的可变类对象,是可以直接被更改的。
   对于不可变类,上述更改就无效了,因为不可变类操作的是指针的副本,也就是“引用”了。
java中可变类和不可变类通过访问控制修饰符final来实现的,参考这里
5 楼 C_J 2009-04-20  
引用
Java中开发人员可操作的只有引用


这句话有什么根据么? 我所知道C++说引用的特性是,他是对象地址(当然还包括基本数据类型)的副本,而这个副本,我的理解是竟然是副本,就没有去更改的理由,因为你改的不是“原件”。

   对JAVA中的可变类,我理解的是直接操作指针的,如参数传递进去的可变类对象,是可以直接被更改的。
   对于不可变类,上述更改就无效了,因为不可变类操作的是指针的副本,也就是“引用”了。

当然,大家共勉,共同进步!
4 楼 idealab 2009-04-19  
1、Java中开发人员可操作的只有引用,不能直接操作指针,但是在底层实现引用的却是指针:JVM会将指向已加载类的引用由“符号引用(该类的全限名称)”替换为指针。类似的,底层对方法的调用也用到指针。
2、Java对多态的实现是依靠跟C++中“虚表”类似的方法表。同样的,方法表中数组元素是指向超类、接口的方法的指针,也通过偏移量来,但是由于Java编译期间的方法只是用符号代替的,故只有运行时方法被第一次调用之后,方法表中的元素才能够获得所指向的方法地址,进而指向它。
3、类方法与实例方法的存储是否有区别我也还不太明了,需要进一步研究。望与楼上共同进步~
3 楼 C_J 2009-04-19  
我说的虚拟方法是指

virtual(C++)   abstract(JAVA)

不过 ,你说到“引用”,我一直归纳为“指针”,但指针这个词总有点变扭,我暂称“句柄”


涉及到“多态”,我想势必就会涉及到虚拟方法,我不知道JAVA有没有像C++那种“虚表”的 机制。

另外static方法与一般方法存储的类栈区域肯定是有区别的,你不能笼统的归纳到
引用
“类的方法表”
中。
2 楼 idealab 2009-04-19  
C_J 写道


 Parent obj1 = new Son(); //一个本指向一个子类对象的句柄强行转换为Parent
 obj1.sayHello(); //static被定义在类栈的静态区域(它是在加载JVM时候已经编译了),所以指向父类栈中
 obj1.sayBye();   //而一般方法不会预编译,但他跟类定义跑,在new Son()的时候的动态连接Son类栈中的sayBye()方法。


同意,不过只是连接,应该并非编译了方法栈地址,而这个操作应该是在类定义的时候编译的。

恩,根据引用所指对象的类型信息来动态调用方法,这应该就是所谓连接吧。

我的理解是,当Parent类被加载进入JVM的时候,静态方法的地址绑定到类的方法表中,静态字段name作为类变量、常量age和birth作为编译时常量存入方法区,编译之后他们的地址和值不再改变,故曰静态绑定。
而引用是以指向对象的指针存在的,在执行期间,父类的引用有可能指向不同子类的实例方法(也就是多态),这种在执行期间才确定具体方法的机制叫动态绑定。

不过,不知楼上所讲虚拟方法指的是什么呢?
1 楼 C_J 2009-04-19  
我的理解大致分为2大机制:

1,静态绑定:这种一般只跟类走
   static方法,一般方法

2,动态绑定:这个得看指针指向了(C++可能复杂点)
   虚拟方法

引用

关于“静态绑定”和“动态绑定”
    virtual就产生了“动态绑定”的机制。
    普通方法是跟类走的(静态绑定,NEW 对象的时候并不临时生成指针,而在类定义的时候就已经编译好了函数地址),而虚拟方法是“动态绑定”,这种机制就需要动态指定函数地址,通过什么?就通过上面说的“虚表”和指向“虚表的指针”。



再看看你的代码

 Parent obj1 = new Son(); //一个本指向一个子类对象的句柄强行转换为Parent
 obj1.sayHello(); //static被定义在类栈的静态区域(它是在加载JVM时候已经编译了),所以指向父类栈中
 obj1.sayBye();   //而一般方法不会预编译,但他跟类定义跑,在new Son()的时候的动态连接Son类栈中的sayBye()方法。

引用

Son类的实例方法sayBye()是在被实际对象调用的时候才动态连接的。


同意,不过只是连接,应该并非编译了方法栈地址,而这个操作应该是在类定义的时候编译的。


上面是自己写的总结,我不知道我的理解是否到位

相关推荐

    java 反射入门-属性方法调用实例

    这篇博文将带你入门Java反射,并通过属性和方法的调用来实践这一概念。 首先,理解反射的基础概念。在Java中,`Class`类代表了运行时的类信息。通过`Class`对象,我们可以获取到类的名称、构造器、方法和字段。例如...

    反射,动态加载指定类调用类中的方法

    4. 调用方法:对获取到的`Method`对象,调用`invoke()`方法,传入对象实例和方法参数。 下面是一个简单的示例,演示了如何动态加载一个类并调用其方法: ```java public class Tafcm01 { public static void main...

    Java实例化一个抽象类对象的方法教程

    当子类实例化时,会调用抽象类中的构造方法进行初始化。 在Java中,实例化抽象类的一种常见方式是通过子类继承并实现抽象方法。假设有一个抽象类`AbstractBase`: ```java public abstract class AbstractBase { ...

    静态建对象调用成员对象的成员字段.rar

    6. **静态方法调用实例成员**:静态方法可以直接调用类的静态字段,但不能直接访问实例字段,因为它们没有对象上下文。如果需要访问实例字段,通常需要通过传递对象实例作为参数。 7. **多态(Polymorphism)**:...

    通过反射获得实体类的字段和值

    - 性能开销:反射涉及类型信息的查找和解析,比直接调用成员方法或访问字段慢得多。 - 安全性和性能问题:过度使用反射可能会引入安全漏洞,并影响应用程序的性能。 #### 5. 实践中的注意事项 - **性能考量**:在...

    Java反射调用方法

    这个特性使得Java具有了更高的灵活性,能够处理一些在编译时无法确定的对象和方法调用。 在给定的代码中,`TestRef` 类展示了如何使用Java反射调用方法。首先,我们创建了一个 `Foo` 类,它有一个私有字符串成员...

    C#中类、属性、字段、方法举例

    在C#编程语言中,类(Class)是面向对象编程的核心概念,它是创建对象...了解并熟练掌握类、属性、字段和方法对于编写高效且易于维护的C#代码至关重要。通过实践这些基本概念,开发者能够构建出复杂且功能丰富的应用。

    Java动态调用实例

    反射是Java提供的一种机制,它允许程序在运行时检查类、接口、字段和方法的信息,甚至可以创建和操作对象。`java.lang.reflect`包提供了多种类和接口来支持反射,如`Class`、`Constructor`、`Method`和`Field`。例如...

    java 通过反射获取枚举类,及枚举类的值,枚举类枚举实例名

    在Java编程语言中,反射(Reflection)是一种强大的工具,它允许程序在运行时检查和操作类、接口、字段和方法等对象。枚举(Enumeration)是Java中的一个特殊类类型,用于定义一组常量。本项目"test-enum-demo-...

    java动态调用方法

    总的来说,Java动态调用方法通过反射机制实现了运行时对类和方法的动态操作,这在许多场合都有用武之地,如插件系统、自动化测试、元编程等。然而,由于反射的特性,也需要注意其可能带来的安全问题和性能影响。在...

    c#类成员(字段、属性、方法、事件)

    总结来说,C#中的字段、属性、方法和事件构成了类的主要成员,它们共同作用于对象的描述、状态管理、行为实现和外部通信,是构建复杂应用程序的基础。理解和熟练运用这些概念对于成为一名高效的C#开发者至关重要。

    泛微接口说明与调用实例

    泛微接口说明与调用实例主要涵盖了泛微协同办公系统中的接口规范,这些接口主要用于不同模块的数据交互和服务集成。在企业信息化建设中,接口的合理使用可以实现各个系统的无缝对接,提高工作效率。以下是对各文件...

    WPF继承_子类继承父类,实现跨类调用方法

    在Windows Presentation Foundation (WPF) 中,继承是面向对象编程的一个关键特性,它允许子类继承父类的属性、字段和方法,以便扩展或重写它们。标题“WPF继承_子类继承父类,实现跨类调用方法”表明我们将讨论如何...

    Java方法反射调用demo

    Java反射是Java编程语言中的一个强大特性,它允许在运行时检查类、接口、字段和方法的信息,并且能够在运行时动态地创建对象和调用方法。这个特性使得Java具有了高度的灵活性,常用于框架开发、插件系统、元编程等...

    静态成员间的调用实例(基础)

    例如,我们可以创建一个包含静态字段和方法的类: ```csharp public class MyClass { public static int StaticField = 0; // 静态字段 public static void StaticMethod() { // 静态方法 Console.WriteLine("这...

    C#调用C++DLL实例代码

    本篇文章将详细探讨如何在C#中调用C++的DLL,并通过一个实例代码进行演示。 首先,我们需要了解C#调用C++DLL的基本原理。.NET框架提供了一种称为P/Invoke(Platform Invoke)的技术,允许C#代码调用非托管代码,如...

    java 反射 调用私有方法(有参数私有方法)获取私有属性值

    Java反射是Java语言提供的一种强大的动态类型特性,它允许程序在运行时检查类、接口、字段和方法的信息,并且能够动态地创建对象和调用方法。这个能力使得开发者可以突破静态类型的束缚,实现一些在编译时期无法完成...

    公司java笔试题汇总.doc

    abstract修饰符可修饰字段、方法和类 B. 抽象方法的body部分必须用一对大括号{ }包住 C. 声明抽象方法,大括号可有可无 D. 声明抽象方法不可写出大括号 2. 如下代码 public class Test { public int aMethod() {...

    c# 类的静态字段操作

    在这个例子中,`SharedValue` 是一个静态字段,可以被 `IncrementShared` 和 `DecrementShared` 方法所访问和修改,无论创建多少个 `MyClass` 的实例,`SharedValue` 的值都是共享的。 静态字段常用于计数器、全局...

Global site tag (gtag.js) - Google Analytics