2007-12-14
是谁调用了它的静态方法?
关键字: JAVA
我该如何知道是哪个子类调用了它的静态方法?有必要吗?
//ActiveRecord.java
//XxxAction.java
我如何完成如上的做法?
//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();
}
我如何完成如上的做法?
评论
leadyu
2007-12-17
收到Qieqie的站内短信,OK,我也收回我的'晕',口头谈了,坏习惯,不过确实是我没看清楚题目,浏览的时候无意看到这个帖,没怎么想就回了。
这个帖讨论怎么实现,估计很难讨论出什么结果,本身就可以不设计成static。不如引申为‘static内部机制的讨论’来解释之前的方法为什么不可行
这个帖讨论怎么实现,估计很难讨论出什么结果,本身就可以不设计成static。不如引申为‘static内部机制的讨论’来解释之前的方法为什么不可行
leadyu
2007-12-17
抱歉,是我没看到static。找了找资料,纯当初学,总结一下。
如果是static那就不可能在方法内部知道调用者的信息的,根本没有所谓的调用者。
方法定义在类级别,方法本身不会实例化,在虚拟机内部调用也不会引用到一个Runtime对象。
也就是说User.count和ActiveRecord.count是一样的。可以看看VM Spec.的说明:
规范给出了2个例子说明这个问题:
分别编译出来的指令如下:
可以看出,虚拟机内部是通过2种指令来执行实例化方法和静态方法的。
对于invokevirtual #4指令,可以看出,必须先调用aload_0对this进行压栈,参数查找从局部变量栈中的第一位开始。至于#4,代表的是一个常量符号,编译时由编译器临时生成存放在class文件内,在对象实例化时动态付值为方法的地址偏移量。(这是由于编译器无法在编译期知道方法内存的分配地址)
对于invokestatic #3指令可以看出,他的参数寻找是从局部变量的第0位开始,并不存在什么调用者,也不存在实例化方法。
这就可以解释为什么静态方法里面不存在this,以及为什么User.count显示的线程调用栈还是ActiveRecord.count,这是由于调用根本不是由User实例或者对象发起。
只是完全不明白这里为什么要设计成静态方法。
至于LZ之前说的,class文件内部仍然保持着User.count的语义,何以见得?除非你找到常量池里面定义的#3,指向,也许这个常量根本就不再编译期指向。
如果是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,指向,也许这个常量根本就不再编译期指向。
惊鸿逝水
2007-12-17
楼上兄弟,没弄清楚楼主的需求!static
leadyu
2007-12-17
呵呵,你说的没错,在javaeye上我确实是一个刚出来混的。看看,兄台都已经5颗星拉,难怪看不起俺们刚出来混的。
还有,兄弟不要轻易质疑俺们这种刚出来混得,积分高低实在不说明什么问题呀,在我搞自己的Jwebap项目之前,确实很少来Javaeye,是我的错。你可以执行执行下面这段,看看:
多的就不说了,就算你抓住了别人的小辫子,也不用出言不逊巴。
还有,兄弟不要轻易质疑俺们这种刚出来混得,积分高低实在不说明什么问题呀,在我搞自己的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();
}
}
多的就不说了,就算你抓住了别人的小辫子,也不用出言不逊巴。
Qieqie
2007-12-16
leadyu 写道
晕,谁说无解,答案简单的很啊。你在ActiveRecord里面用
this.getClass()不就完了?
User调用count的话,虽然方法定义在父类,但是this指向的就是User
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);
}
}
你传染我,让我晕了
leadyu
2007-12-16
晕,谁说无解,答案简单的很啊。你在ActiveRecord里面用
this.getClass()不就完了?
User调用count的话,虽然方法定义在父类,但是this指向的就是User
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);
}
}
yujiang
2007-12-14
Qieqie 写道
velna_007 写道
我昨天也触及了一个有点类似的问题,比如一个模板类
class ABC<E>{
public void someMethod(){
}
}
我想在someMethod里知道E到底是什么类,想了很久,好像也是无解
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();
}
}
Qieqie
2007-12-14
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();
}
}
Qieqie
2007-12-14
velna_007 写道
不知道你有没有试过,这个行不通。。。
如果我的类是
class ABC<String>{
public void someMethod(){
}
}
那么是可以的
我已经给你那个提示了,如果你觉得不可行,你通过站内信息给我,不要在这个帖子后跟贴
因为,你最后的跟贴和主贴主题不相关,而且还跟两个贴。
煞风景
velna_007
2007-12-14
如果我的类是
class ABC<String>{
public void someMethod(){
}
}
那么是可以的
class ABC<String>{
public void someMethod(){
}
}
那么是可以的
velna_007
2007-12-14
不知道你有没有试过,这个行不通。。。
Qieqie
2007-12-14
velna_007 写道
我昨天也触及了一个有点类似的问题,比如一个模板类
class ABC<E>{
public void someMethod(){
}
}
我想在someMethod里知道E到底是什么类,想了很久,好像也是无解
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];
}
}
velna_007
2007-12-14
我昨天也触及了一个有点类似的问题,比如一个模板类
class ABC<E>{
public void someMethod(){
}
}
我想在someMethod里知道E到底是什么类,想了很久,好像也是无解
class ABC<E>{
public void someMethod(){
}
}
我想在someMethod里知道E到底是什么类,想了很久,好像也是无解
Qieqie
2007-12-14
如果要放,则是放在栈上
简单地,可认为java的每个method是栈上的一个元素,jvm完全可以把当前谁"."的这个method放入栈的这个元素中。
在instance方法中,这个"谁"由 this 扮演,现在缺少的是用某个关键字来扮演static method的这个"谁"
我触及了这个问题,真是很不幸
简单地,可认为java的每个method是栈上的一个元素,jvm完全可以把当前谁"."的这个method放入栈的这个元素中。
在instance方法中,这个"谁"由 this 扮演,现在缺少的是用某个关键字来扮演static method的这个"谁"
我触及了这个问题,真是很不幸
velna_007
2007-12-14
应该是编译期的信息无法在运行期使用
User.count()前加User只是为了编译的目的,真正到了运行期这个信息就被丢弃了,再说,如果不丢弃,这个信息可以放在哪里呢?放在count方法上?还是放在User类声明上?好像都不可以。
User.count()前加User只是为了编译的目的,真正到了运行期这个信息就被丢弃了,再说,如果不丢弃,这个信息可以放在哪里呢?放在count方法上?还是放在User类声明上?好像都不可以。
sswh
2007-12-14
啊。。我看错了。
方法栈的确不包含子类的信息。
方法栈的确不包含子类的信息。
Qieqie
2007-12-14
LS的方法无法做到,试验如下:
//ActiveRecord.java
//User.java
//UserAction.java
打印结果:
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? 这个特性如果无法从语言本身得到满足,将是很难过。
//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? 这个特性如果无法从语言本身得到满足,将是很难过。
sswh
2007-12-14
好像javaeye以前贴过:
//参数0:返回sun.reflect.Reflection
//参数1:返回本类
//参数2以上,依次返回方法调用栈上的类
Class targetClass = Reflection.getCallerClass(2);
还有另外一种方法也是一样:
String caller = new Throwable().getStackTrace()[2].getClassName();
//参数0:返回sun.reflect.Reflection
//参数1:返回本类
//参数2以上,依次返回方法调用栈上的类
Class targetClass = Reflection.getCallerClass(2);
还有另外一种方法也是一样:
String caller = new Throwable().getStackTrace()[2].getClassName();
youyu
2007-12-14
为什么不设计成:
public void someMethod(){
int userCount = ActiveRecord .count(User.class);
int topicCount = ActiveRecord .count(Topic.class);
}
public class ActiveRecord
{
public static int count(Class clazz)
{
....
}
}
或者 SPING里面 HibernateSupport类 和HibernateTemplate...(大概是这个名字)那样设计?
对你的代码:在static method 里面得到执行这个方法的引用,好象不可以:
首先应该明确一点: static method是被称为类方法,它的意义是这个类所有对象共同的方法,这个方法被调用,就相当于:这个类所有的对象一起调用这个方法一次,既然是一起调用,你又怎么知道到底是谁调用了这个方法呢。
所以根据语法,static不能用 this,super关键字,这就是你无法在ActiveRecord中得到targetClass对象的原因。
个人见解,敬请指正。
public void someMethod(){
int userCount = ActiveRecord .count(User.class);
int topicCount = ActiveRecord .count(Topic.class);
}
public class ActiveRecord
{
public static int count(Class clazz)
{
....
}
}
或者 SPING里面 HibernateSupport类 和HibernateTemplate...(大概是这个名字)那样设计?
对你的代码:在static method 里面得到执行这个方法的引用,好象不可以:
首先应该明确一点: static method是被称为类方法,它的意义是这个类所有对象共同的方法,这个方法被调用,就相当于:这个类所有的对象一起调用这个方法一次,既然是一起调用,你又怎么知道到底是谁调用了这个方法呢。
所以根据语法,static不能用 this,super关键字,这就是你无法在ActiveRecord中得到targetClass对象的原因。
个人见解,敬请指正。
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 188261 次
- 性别:

- 来自: 北京

- 详细资料
搜索本博客
最近加入圈子
最新评论
-
使用 庖丁分词(2.0.4-alp ...
请问,啥时候出新版本的paoding分词? 谢谢,等急死了
-- by shguan@toptimetech.com -
使用 庖丁分词(2.0.4-alp ...
支持,测试过庖丁分词比IKAnalyzer感觉要好些
-- by keller -
设计的一个考虑点:区分数 ...
把不变的信息放到缓存里那要多大得内存才够啊,分布式缓存。。 确实成本比较高,那你 ...
-- by bloodrate -
设计的一个考虑点:区分数 ...
taobao是用什么东西去映射这些在不同的服务器上面的数据的呢?
-- by laiseeme -
设计的一个考虑点:区分数 ...
不错的设计,耦合度明显比将两者设计在一起要来得低
-- by jbon






评论排行榜