`
Qieqie
  • 浏览: 340000 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

是谁调用了它的静态方法?

阅读更多
我该如何知道是哪个子类调用了它的静态方法?有必要吗?

//ActiveRecord.java
public abstract class ActiveRecord {

    public static int count() {
        //我应该如何知道,Xxx.count()中的Xxx实际是什么类?
        //假如java在此可以使用关键字class,用以表示实际调用该静态方法的类:
        Class targetClass = class;
        String hql = "select count(*) from " + targetClass.getSimpleName() 
              + " where " + propertyName + "=?";
        List list = theStaticHibernateTemplate.find(hql, value);
        return (Integer) list.get(0);
    }

}


//Entity.java

@MappedSuperclass
public abstract class Entity extends ActiveRecord {
...
}

//User.java
@Entity
public User extends Entity {...}

//Topic.java
@Entity
public Topic extends Entity {...}



//XxxAction.java
public void someMethod(){
    //ActiveRecord.count中的targetClass 将是User.class
    int userCount = User.count(); 

    //ActiveRecord.count中的targetClass 将是Topic.class
    int topicCount = Topic.count(); 
}


我如何完成如上的做法?
分享到:
评论
21 楼 fantaxy025025 2012-07-13  
世隔近5年,我才看到了这么精彩的讨论。
所谓,思想和眼光,相辅相承。

如果我没有接触RoR的话,估计我很难猜测出qieqie兄到底想做什么。
另外,还有java的泛型。
20 楼 leadyu 2007-12-17  
收到Qieqie的站内短信,OK,我也收回我的'晕',口头谈了,坏习惯,不过确实是我没看清楚题目,浏览的时候无意看到这个帖,没怎么想就回了。

这个帖讨论怎么实现,估计很难讨论出什么结果,本身就可以不设计成static。不如引申为‘static内部机制的讨论’来解释之前的方法为什么不可行
19 楼 leadyu 2007-12-17  
抱歉,是我没看到static。找了找资料,纯当初学,总结一下。

如果是static那就不可能在方法内部知道调用者的信息的,根本没有所谓的调用者。

方法定义在类级别,方法本身不会实例化,在虚拟机内部调用也不会引用到一个Runtime对象。
也就是说User.count和ActiveRecord.count是一样的。可以看看VM Spec.的说明:

规范给出了2个例子说明这个问题:
int addTwo(int i, int j) {
    return i + j;
}

static int addTwoStatic(int i, int j) {
    return i + j;
}

分别编译出来的指令如下:
   0     aload_0			 // Push local variable 0 (this)
   1 	bipush 12			// Push int constant 12
   3 	bipush 13			// Push int constant 13
   5 	invokevirtual #4		// Method Example.addtwo(II)I
   8	ireturn	

   0 	bipush 12
   2 	bipush 13
   4 	invokestatic #3 		// Method Example.addTwoStatic(II)I
   7 	ireturn
		 

可以看出,虚拟机内部是通过2种指令来执行实例化方法和静态方法的。
对于invokevirtual #4指令,可以看出,必须先调用aload_0对this进行压栈,参数查找从局部变量栈中的第一位开始。至于#4,代表的是一个常量符号,编译时由编译器临时生成存放在class文件内,在对象实例化时动态付值为方法的地址偏移量。(这是由于编译器无法在编译期知道方法内存的分配地址)

对于invokestatic #3指令可以看出,他的参数寻找是从局部变量的第0位开始,并不存在什么调用者,也不存在实例化方法。


这就可以解释为什么静态方法里面不存在this,以及为什么User.count显示的线程调用栈还是ActiveRecord.count,这是由于调用根本不是由User实例或者对象发起。

只是完全不明白这里为什么要设计成静态方法。


至于LZ之前说的,class文件内部仍然保持着User.count的语义,何以见得?除非你找到常量池里面定义的#3,指向,也许这个常量根本就不再编译期指向。

18 楼 惊鸿逝水 2007-12-17  
楼上兄弟,没弄清楚楼主的需求!static
17 楼 leadyu 2007-12-17  
呵呵,你说的没错,在javaeye上我确实是一个刚出来混的。看看,兄台都已经5颗星拉,难怪看不起俺们刚出来混的。

还有,兄弟不要轻易质疑俺们这种刚出来混得,积分高低实在不说明什么问题呀,在我搞自己的Jwebap项目之前,确实很少来Javaeye,是我的错。你可以执行执行下面这段,看看:


public abstract class AA {
	public void count(){
		
		System.out.println(this.getClass());
		
	}
}

public class BB extends AA{

	public static void main(String[] a){
		BB b=new BB();
		
		b.count();
	}
}



多的就不说了,就算你抓住了别人的小辫子,也不用出言不逊巴。
16 楼 Qieqie 2007-12-16  
leadyu 写道
晕,谁说无解,答案简单的很啊。你在ActiveRecord里面用

this.getClass()不就完了?


User调用count的话,虽然方法定义在父类,但是this指向的就是User

public abstract class ActiveRecord {   
  
    public static int count() {   
        //我应该如何知道,Xxx.count()中的Xxx实际是什么类?   
        //假如java在此可以使用关键字class,用以表示实际调用该静态方法的类:   
        Class targetClass = this.getClass();   
        String hql = "select count(*) from " + targetClass.getSimpleName()    
              + " where " + propertyName + "=?";   
        List list = theStaticHibernateTemplate.find(hql, value);   
        return (Integer) list.get(0);   
    }   
  
}   


你传染我,让我晕了
15 楼 leadyu 2007-12-16  
晕,谁说无解,答案简单的很啊。你在ActiveRecord里面用

this.getClass()不就完了?


User调用count的话,虽然方法定义在父类,但是this指向的就是User

public abstract class ActiveRecord {   
  
    public static int count() {   
        //我应该如何知道,Xxx.count()中的Xxx实际是什么类?   
        //假如java在此可以使用关键字class,用以表示实际调用该静态方法的类:   
        Class targetClass = this.getClass();   
        String hql = "select count(*) from " + targetClass.getSimpleName()    
              + " where " + propertyName + "=?";   
        List list = theStaticHibernateTemplate.find(hql, value);   
        return (Integer) list.get(0);   
    }   
  
}   
14 楼 yujiang 2007-12-14  
Qieqie 写道
velna_007 写道
我昨天也触及了一个有点类似的问题,比如一个模板类
class ABC<E>{
public void someMethod(){
}
}

我想在someMethod里知道E到底是什么类,想了很久,好像也是无解

这个有解

给你参考:http://www.hibernate.org/328.html


public abstract class GenericHibernateDAO<T, ID extends Serializable>
        implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private Session session;

    public GenericHibernateDAO() {
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                                .getGenericSuperclass()).getActualTypeArguments()[0];
     }
}


这个要继承.不继承的话还真的没有办法.

同主题相关的一点东西
具体的可以看  JLS 第三版   15.12.3 15.12.4
public class M {

	static void test() {
		System.out.println("---");
	}
	
	public static void main(String[] args) {
		((M) null).test();
	}
}
13 楼 Qieqie 2007-12-14  
[讨论]Java中的ActiveRecord实现

讨论得已经够深了,无解。此帖就此打住吧
12 楼 neuzhujf 2007-12-14  
子类overwrite父类的静态方法。
public class User extends ActiveRecord {
	public static int count() {   
    	RuntimeException e = new RuntimeException();
    	System.out.println(e.getStackTrace()[0].getClassName());
        return ActiveRecord.count();   
    }   
}
11 楼 Qieqie 2007-12-14  
velna_007 写道

不知道你有没有试过,这个行不通。。。


如果我的类是
class ABC<String>{
public void someMethod(){
}
}
那么是可以的


我已经给你那个提示了,如果你觉得不可行,你通过站内信息给我,不要在这个帖子后跟贴
因为,你最后的跟贴和主贴主题不相关,而且还跟两个贴。

煞风景
10 楼 velna_007 2007-12-14  
如果我的类是
class ABC<String>{
public void someMethod(){
}
}
那么是可以的
9 楼 velna_007 2007-12-14  
不知道你有没有试过,这个行不通。。。
8 楼 Qieqie 2007-12-14  
velna_007 写道
我昨天也触及了一个有点类似的问题,比如一个模板类
class ABC<E>{
public void someMethod(){
}
}

我想在someMethod里知道E到底是什么类,想了很久,好像也是无解

这个有解

给你参考:http://www.hibernate.org/328.html


public abstract class GenericHibernateDAO<T, ID extends Serializable>
        implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private Session session;

    public GenericHibernateDAO() {
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                                .getGenericSuperclass()).getActualTypeArguments()[0];
     }
}
7 楼 velna_007 2007-12-14  
我昨天也触及了一个有点类似的问题,比如一个模板类
class ABC<E>{
public void someMethod(){
}
}

我想在someMethod里知道E到底是什么类,想了很久,好像也是无解
6 楼 Qieqie 2007-12-14  
如果要放,则是放在栈上

简单地,可认为java的每个method是栈上的一个元素,jvm完全可以把当前谁"."的这个method放入栈的这个元素中。

在instance方法中,这个"谁"由 this 扮演,现在缺少的是用某个关键字来扮演static method的这个"谁"

我触及了这个问题,真是很不幸
5 楼 velna_007 2007-12-14  
应该是编译期的信息无法在运行期使用
User.count()前加User只是为了编译的目的,真正到了运行期这个信息就被丢弃了,再说,如果不丢弃,这个信息可以放在哪里呢?放在count方法上?还是放在User类声明上?好像都不可以。
4 楼 sswh 2007-12-14  
啊。。我看错了。

方法栈的确不包含子类的信息。
3 楼 Qieqie 2007-12-14  
LS的方法无法做到,试验如下:

//ActiveRecord.java
package net.paoding.ar.test;

import sun.reflect.Reflection;

public abstract class ActiveRecord {
    public static int count() {
        System.out.println("Reflection.getCallerClass(1)=" + Reflection.getCallerClass(1));
        System.out.println("Reflection.getCallerClass(2)=" + Reflection.getCallerClass(2));
        System.out.println("Reflection.getCallerClass(3)=" + Reflection.getCallerClass(3));
        System.out.println("Reflection.getCallerClass(4)=" + Reflection.getCallerClass(4));
        return 3;
    }
}


//User.java
public class User extends ActiveRecord {

}



//UserAction.java
public class UserAction {
    public static void main(String[] args) {
        User.count();
    }
}


打印结果:
Reflection.getCallerClass(0)=class sun.reflect.Reflection
Reflection.getCallerClass(1)=class net.paoding.ar.test.ActiveRecord
Reflection.getCallerClass(2)=class net.paoding.ar.test.UserAction
Reflection.getCallerClass(3)=null
Reflection.getCallerClass(4)=null


==〉通过Reflection.getCallerClass无法嘚知程序使用的是User.count()而非ActiveRecord.count()



我反编译了UserAction.class,确定.class文件中仍然保持User.count()的叙述,
这意味着,虚拟机完全可以提供API来让编程者获得。

到底是否有这样的API? 这个特性如果无法从语言本身得到满足,将是很难过。
2 楼 sswh 2007-12-14  
好像javaeye以前贴过:

//参数0:返回sun.reflect.Reflection
//参数1:返回本类
//参数2以上,依次返回方法调用栈上的类
Class targetClass = Reflection.getCallerClass(2); 

还有另外一种方法也是一样:
String caller = new Throwable().getStackTrace()[2].getClassName();

相关推荐

    通过反射调用静态方法

    本文将详细讲解如何通过反射调用静态方法,并探讨在特定场景下,如MyBatis中的应用。 首先,理解反射的概念是至关重要的。在Java中,反射API(java.lang.reflect)允许我们获取类的信息,包括类名、构造函数、方法...

    Springboot Thymeleaf模板文件调用Java类静态方法

    方法名(参数)}”这种格式来调用Java类的静态方法。 开发环境:IntelliJ IDEA 2019.2.2 Spring Boot版本:2.1.8 新建一个名称为demo的Spring Boot项目。 1、pom.xml 加入Thymeleaf依赖 &lt;groupId&gt;org.spring...

    静态方法,静态成员变量的调用

    在Java编程语言中,静态方法和实例方法是两种不同类型的成员,它们在使用和功能上有所区别。静态方法是属于类级别的,而实例方法是属于对象级别的。理解这两种方法的特性对于编写高效的代码至关重要。 首先,调用...

    jni调用java静态方法

    本示例将详细介绍如何在JNI中调用Java的静态方法。 首先,我们需要了解JNI的基本结构。一个JNI程序通常包括Java类(包含JNI函数声明)和本地源代码(C/C++实现)。在Java类中,我们会定义`native`关键字修饰的静态...

    MFC DLL动态调用及静态调用

    在Windows编程环境中,MFC(Microsoft Foundation Classes)是一种C++库,它提供了对Windows API的封装,便于开发者创建用户界面和应用程序。DLL(Dynamic Link Library)是Windows操作系统中的一种共享库机制,允许...

    webservice的动态调用和静态调用

    它要求在编译时就已经知道服务的WSDL(Web Service Description Language)信息,对于经常变动的服务地址或者需要动态发现服务的情况,静态调用就显得不太灵活。 相反,动态调用通常是在运行时通过反射或者其他方式...

    C#静态方法与非静态方法的比较

    这意味着在调用静态方法时,不需要先创建类的对象。静态方法通常用于执行与类相关的操作,但不涉及特定对象的状态。 **2. 实例方法** 实例方法也称为非静态方法,它依赖于类的一个特定实例。实例方法能够访问类中...

    DynamicCustomVI_动态调用_labview_静态调用_

    - **性能**:静态调用在大多数情况下具有更好的性能,因为它在编译时就已经确定了路径,而动态调用在运行时还需要查找和加载VI。 - **适应性**:动态调用更适用于需要根据条件或输入动态选择不同功能的场合,而...

    Qt下使用C++调用静态库及动态库示例程序

    使用简单的程序展示了C++调用动态库和静态库的方法。 文件结构: exe:笔者部署可运行文件,因开发环境版本不同,可能存在无法直接使用的情况,两个部署文件(copy_ldd.sh及...useLib1:调用静态库和动态库的工程文件。

    PHP静态调用非静态方法的应用分析

    在PHP编程语言中,静态调用非静态方法是一种特殊情况,虽然在Java或C#等静态类型语言中会被编译器捕获并报错,但在PHP这样的动态语言中却是可行的,尽管并不推荐。PHP允许这样的调用主要是为了保持向后兼容,尤其是...

    面向Python的函数调用路径静态提取方法研究.pdf

    总结来说,面向Python的函数调用路径静态提取方法的研究是软件工程领域中的一个重要方向,它涉及到了软件分析与测试的多个核心知识点。通过深入掌握这些技术,能够显著提高软件开发和维护的效率与质量。

    客户端脚本调用服务端静态方法----PageMethods.doc

    ### 客户端脚本调用服务端静态方法——PageMethods 的实现原理及应用 #### 一、背景介绍 在Web开发中,客户端与服务端的交互是非常常见且重要的环节。传统的做法是通过表单提交或者Ajax请求来完成数据交换。然而,...

    html静态页面调用php文件的方法

    在开发Web应用时,经常会有在HTML静态...通过上述方法,可以在HTML静态页面中实现对PHP文件的动态调用,并通过PHP处理后返回的数据动态更新页面内容。这种方法在Web应用程序开发中非常实用,能够大幅提高用户交互体验。

    Java的静态方法调用.pdf

    静态方法调用是指在不创建对象的情况下直接通过类名来调用的方法,它与类相关联,而不是类的实例。这种方式在处理与类相关的属性或不需要访问实例变量的操作时特别有用。 静态方法调用的优势在于: 1. **效率**:...

    静态方法和非静态方法的调用.pdf

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main(string[] args) ...

    静态库_动态库生成过程及其调用方法详解

    调用静态库和动态库的方法有所不同。对于静态库,直接在源代码中#include库的头文件,并在链接阶段指定对应的.lib文件即可。而动态库的调用则分为两种:延迟加载(Delay Load)和即时加载(Immediate Load)。即时...

    Python 调用 C# 静态方法,非静态方法,传参

    - 通过加载的 DLL 实例调用静态方法并传递参数。 2. **Python 调用 C# 非静态方法** - 非静态方法需要先创建 C# 类的实例,然后通过实例调用方法。在 Python 中,这通常意味着需要使用 `ctypes` 创建结构体来表示...

    FORTRAN静态库的生成、维护与调用

    为了在主程序中调用静态库中的子程序,需要在编译主程序时指定静态库的位置。具体步骤如下: 1. **设置编译器路径**:确保编译器能够找到静态库所在位置。这通常可以通过设置环境变量或在编译命令中指定路径来实现...

    LabVIEW静态和动态调用子VI经典示例

    本教程主要探讨的是如何在LabVIEW中静态和动态地调用子VI,以及这两种方法的不同特性。 一、静态调用子VI 静态调用子VI是在编译时确定的,即在设计阶段就固定了将要调用的子VI。这种方式的优点在于能够进行早期...

Global site tag (gtag.js) - Google Analytics