Java静态方法问题,也许无解,求高人看看有没有思路

guolin 2013-01-06 03:58:48
比如说现在两个类有继承关系, People类中有一个静态方法getClassName(),可以获取到当前的类名。Teacher类继承自People类。现在在Test方法里,调用Teacher.getClassName(),得到的类名却是People的类名,当然这也很好理解为什么,我就是想问问有没有什么办法可以使Teacher.getClassName()得到的是Teacher的类名。只能在People的getClassName()里面改代码,不可以动Teacher这个类。

以下附上简单代码。


package com.test;

public class People {

public static String getClassName() {
return new Object() {
private String getName() {
String className = getClass().getName();
return className.substring(0, className.indexOf("$"));
}
}.getName();
}

}


package com.test;

public class Teacher extends People{
}


import com.test.Teacher;

public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Teacher.getClassName());
}
}
...全文
1129 点赞 收藏 42
写回复
42 条回复
spiderzw 2015年07月21日
引用 25 楼 whz137458 的回复:
[quote=引用 23 楼 xodbc 的回复:] 引用 22 楼 whz137458 的回复: Peple.this可以返回子类对象!! 这回答真是无语抡笔... 回正题,从堆栈找静态方法的实际调用类在jre7下测试似乎无效,测试代码如下: Java code ? 123456789101112 try { new SecurityManager(){ ……
你说话太伤人了,你看看我24楼写的吧[/quote] 层主,你的图像好漂亮,能告诉美女芳名吗,虽然不知道有没有,但还是向问下,我喜欢美女
回复 点赞
lvzhongyi 2014年12月01日
我是专门来顶郭哥的,我是小吕
回复 点赞
为啥呢 2013年01月09日
引用 34 楼 crusher395 的回复:
我提供一个思路,就是比较绕: new Throwable().printStackTrace(); 的结果可得: java.lang.Throwable at com.test.People.getClassName(People.java:xxx1) at com.test.Test.main(Test.java:xxx2) 硬要找printSta……
这意味着源码必须在生产环境出现....而且涉及IO操作....几乎不可能实际应用
回复 点赞
clariones 2013年01月09日
这个就是“静态方法继承”的问题么? 那个问题貌似有很多帖子,说清楚了的。 lz的需求是什么么? 我猜测,是有一大堆代码,其中有个 getClassName()方法一开始写成静态的了,结果后来发现实际运行中是需要根据不同的实例来给出结果,但是又一大堆代码已经完成,实在不想改了,是么? 我有个建议供参考:把方法改成不是静态的。 既然可能是运行时动态的,那我想代码里不会出现 Teacher.getClassName()这样的调用吧? 如果已经知道是Teacher类了,那就没必要调用了,所以很大可能代码里是 Teacher x; ... x.getClassName()这样的调用吧? 如果是这样的话,把getClassName改成非静态方法应该不会太影响已有的代码,用编译器跑一下就可以把需要修改的地方都找出来了; 实际上,把代码写出来,假设有3个类,People,Teacher,Test, 在Test中用Javap命令看字节码,你会看到类似
Compiled from "TestMain.java"
public class pkgname.staticinherit2.TestMain extends java.lang.Object
。。。。。。
const #16 = Method      #17.#19;        //  pkgname/staticinherit2/Teacher.getClassName:()Ljava/lang/String;
const #17 = class       #18;    //  pkgname/staticinherit2/Teacher
const #18 = Asciz       pkgname/staticinherit2/Teacher;
const #19 = NameAndType #20:#21;//  getClassName:()Ljava/lang/String;
const #20 = Asciz       getClassName;
const #21 = Asciz       ()Ljava/lang/String;;
。。。。。。
public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   invokestatic    #16; //Method pkgname/staticinherit2/Teacher.getClassName:()Ljava/lang/String;
   3:   astore_1
   4:   getstatic       #22; //Field java/lang/System.out:Ljava/io/PrintStream;
   7:   aload_1
   8:   invokevirtual   #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   11:  return
在Teacher,class里你会看到类似
Compiled from "TestMain.java"
public class pkgname.staticinherit2.TestMain extends java.lang.Object
  SourceFile: "TestMain.java"
  minor version: 0
  major version: 46
  Constant pool:
const #1 = class        #2;     //  pkgname/staticinherit2/TestMain
const #2 = Asciz        pkgname/staticinherit2/TestMain;
const #3 = class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = Asciz        <init>;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;
const #8 = Method       #3.#9;  //  java/lang/Object."<init>":()V
const #9 = NameAndType  #5:#6;//  "<init>":()V
const #10 = Asciz       LineNumberTable;
const #11 = Asciz       LocalVariableTable;
const #12 = Asciz       this;
const #13 = Asciz       Lpkgname/staticinherit2/TestMain;;
const #14 = Asciz       main;
const #15 = Asciz       ([Ljava/lang/String;)V;
const #16 = Method      #17.#19;        //  pkgname/staticinherit2/Teacher.getClassName:()Ljava/lang/String;
const #17 = class       #18;    //  pkgname/staticinherit2/Teacher
const #18 = Asciz       pkgname/staticinherit2/Teacher;
const #19 = NameAndType #20:#21;//  getClassName:()Ljava/lang/String;
const #20 = Asciz       getClassName;
const #21 = Asciz       ()Ljava/lang/String;;
const #22 = Field       #23.#25;        //  java/lang/System.out:Ljava/io/PrintStream;
const #23 = class       #24;    //  java/lang/System
const #24 = Asciz       java/lang/System;
const #25 = NameAndType #26:#27;//  out:Ljava/io/PrintStream;
const #26 = Asciz       out;
const #27 = Asciz       Ljava/io/PrintStream;;
const #28 = Method      #29.#31;        //  java/io/PrintStream.println:(Ljava/lang/String;)V
const #29 = class       #30;    //  java/io/PrintStream
const #30 = Asciz       java/io/PrintStream;
const #31 = NameAndType #32:#33;//  println:(Ljava/lang/String;)V
const #32 = Asciz       println;
const #33 = Asciz       (Ljava/lang/String;)V;
const #34 = Asciz       args;
const #35 = Asciz       [Ljava/lang/String;;
const #36 = Asciz       result;
const #37 = Asciz       Ljava/lang/String;;
const #38 = Asciz       SourceFile;
const #39 = Asciz       TestMain.java;

{
public pkgname.staticinherit2.TestMain();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 4: 0

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      5      0    this       Lpkgname/staticinherit2/TestMain;


public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   invokestatic    #16; //Method pkgname/staticinherit2/Teacher.getClassName:()Ljava/lang/String;
   3:   astore_1
   4:   getstatic       #22; //Field java/lang/System.out:Ljava/io/PrintStream;
   7:   aload_1
   8:   invokevirtual   #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   11:  return
  LineNumberTable:
   line 13: 0
   line 14: 4
   line 15: 11

  LocalVariableTable:
   Start  Length  Slot  Name   Signature
   0      12      0    args       [Ljava/lang/String;
   4      8      1    result       Ljava/lang/String;


}


D:\work\eclipse\ACP\WydLab\bin>javap -c -verbose pkgname.staticinherit2.Teacher
Compiled from "Teacher.java"
public class pkgname.staticinherit2.Teacher extends pkgname.staticinherit.People
  SourceFile: "Teacher.java"
  minor version: 0
  major version: 46
  Constant pool:
const #1 = class        #2;     //  pkgname/staticinherit2/Teacher
const #2 = Asciz        pkgname/staticinherit2/Teacher;
const #3 = class        #4;     //  pkgname/staticinherit/People
const #4 = Asciz        pkgname/staticinherit/People;
const #5 = Asciz        <init>;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;
const #8 = Method       #3.#9;  //  pkgname/staticinherit/People."<init>":()V
const #9 = NameAndType  #5:#6;//  "<init>":()V
......
{
public pkgname.staticinherit2.Teacher();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #8; //Method pkgname/staticinherit/People."<init>":()V
   4:   return
.....
也就是说,调用的地方“Test.class"里是有"Teacher"这个类的信息的,而Teacher这个类里(如果不覆盖父类的静态方法的话)是根本没有getClassName这个方法的,从Test.class的字节码中找到Teacher类,然后发现没有getClassName方法,然后向上找到父类的静态方法的整个过程,是JVM的字节码引擎处理的,纯java code是无法知道“getClassName"其实是从Teacher类开始找的,除非你的JVM引擎告诉你这些信息。
回复 点赞
crusher395 2013年01月09日
引用 38 楼 xodbc 的回复:
引用 34 楼 crusher395 的回复: 我提供一个思路,就是比较绕: new Throwable().printStackTrace(); 的结果可得: java.lang.Throwable at com.test.People.getClassName(People.java:xxx1) at com.test.Test.main(Test.java:xxx2) ……
我是被逼的。。。
回复 点赞
为啥呢 2013年01月08日
引用 32 楼 whz137458 的回复:
引用 31 楼 crusher395 的回复:我觉得不可能做到,证明: Teacher.getClassName()访问的是静态代码段People.getClassName(),类名Teacher还是People是运行期特征,要动态获得只能通过this.getClass().getName() ,显然静态代码不能用this 至于new Throwable().……
这个....需求是不能随便推翻的
引用 8 楼 brightyq 的回复:
实在要取,从堆栈中取吧.比如 : Java code?1234567public static void getClassName() { StackTraceElement[] stacks = new Throwable().getStackTrace(); for(StackTraceElement s : sta……
打印结果: com.test.People Test 堆栈里也没有Teacher
回复 点赞
安特矮油 2013年01月08日
引用 8 楼 brightyq 的回复:
实在要取,从堆栈中取吧.比如 : Java code?1234567public static void getClassName() { StackTraceElement[] stacks = new Throwable().getStackTrace(); for(StackTraceElement s : sta……
getClassName com.study.test.People main com.study.test.T 测试结果,因为直接是调用的People的static方法,所以Teacher根本就不可能会有的
回复 点赞
安特矮油 2013年01月08日
static方法中是没办法的,因为static方法的执行的时候可能只加载了class,但是对象并未产生,那么父类如何能知道他的儿子呢?就像儿子都还没怀上没出声,父亲怎么知道儿子是什么样呢?所以不要再纠结于此。
回复 点赞
crusher395 2013年01月08日
34楼的这个思路理论上是可行的!
回复 点赞
crusher395 2013年01月08日
我提供一个思路,就是比较绕: new Throwable().printStackTrace(); 的结果可得: java.lang.Throwable at com.test.People.getClassName(People.java:xxx1) at com.test.Test.main(Test.java:xxx2) 硬要找printStackTrace的运行期特征,其实是可以的,就是读文件在Test.java:xxx2行通过正则表达式解析出那个Teacher
回复 点赞
小灰狼 2013年01月07日
单从JAVA的语法上来看,此题无解 如果从分析楼主的需求角度看,应该还是有办法可想的。楼主这样做想达到什么目的,不妨说出来讨论一下
回复 点赞
rome_wu 2013年01月07日
引用 31 楼 crusher395 的回复:
我觉得不可能做到,证明: Teacher.getClassName()访问的是静态代码段People.getClassName(),类名Teacher还是People是运行期特征,要动态获得只能通过this.getClass().getName() ,显然静态代码不能用this 至于new Throwable().getStackTrace()[0].getClassName() 之类……
其实我很纠结,为啥一定要用静态的?难道只为了好调用?24L的做法有何不可?而且无须传参!
回复 点赞
crusher395 2013年01月07日
我觉得不可能做到,证明: Teacher.getClassName()访问的是静态代码段People.getClassName(),类名Teacher还是People是运行期特征,要动态获得只能通过this.getClass().getName() ,显然静态代码不能用this 至于new Throwable().getStackTrace()[0].getClassName() 之类本质获得的还是编译期特征,如
package script;

public class Father {

	public void getClassNameDyn() {
		new Throwable().printStackTrace();
		System.out.println(this.getClass().getName());
	}

}

public class Child extends Father{}

public class Test { 
    public static void main(String[] args) throws Exception { 
        new Child().getClassNameDyn(); 
    } 
}
的返回结果是: java.lang.Throwable at script.Father.getClassNameDyn(Father.java:32) at script.Test.main(Script.java:197) script.Child 这里Father是编译期特征 如果楼主只想实现单纯的这个需求,我看Teacher.class.getName()就行,你试着把class.getName()想象成一个不变的方法,否则只能传参数了
回复 点赞
rome_wu 2013年01月07日
如果真的可行,希望楼主发个信息给我让我看看如何实现!
回复 点赞
rome_wu 2013年01月07日
我个人觉得静态方法是无法实现你说的功能的,你还是尝试用我的代码试试看吧!
回复 点赞
rome_wu 2013年01月07日
为啥一定要静态方法?
回复 点赞
为啥呢 2013年01月07日
引用 25 楼 whz137458 的回复:
引用 23 楼 xodbc 的回复:引用 22 楼 whz137458 的回复: Peple.this可以返回子类对象!! 这回答真是无语抡笔... 回正题,从堆栈找静态方法的实际调用类在jre7下测试似乎无效,测试代码如下: Java code ? 123456789101112 try { new Se……
我并没有人身攻击的意思,可是请你在回帖的时候至少看清LZ的问题,标题上可是清清楚楚地写着“静态方法”4个大字....
回复 点赞
rome_wu 2013年01月07日
引用 24 楼 whz137458 的回复:
public class Peple { public void getObject(){ // TODO Auto-generated method stub System.out.println(Peple.this); } } class Teacher extends Peple{ public static void main(String[] args) ……
Teacher的主方法可以放在Test类里
回复 点赞
rome_wu 2013年01月07日
引用 23 楼 xodbc 的回复:
引用 22 楼 whz137458 的回复: Peple.this可以返回子类对象!! 这回答真是无语抡笔... 回正题,从堆栈找静态方法的实际调用类在jre7下测试似乎无效,测试代码如下: Java code ? 123456789101112 try { new SecurityManager(){ ……
你说话太伤人了,你看看我24楼写的吧
回复 点赞
rome_wu 2013年01月07日
public class Peple { public void getObject(){ // TODO Auto-generated method stub System.out.println(Peple.this); } } class Teacher extends Peple{ public static void main(String[] args) { new Teacher().getObject(); } } 改成这样试试把
回复 点赞
发动态
发帖子
Java SE
创建于2007-09-28

3.4w+

社区成员

30.7w+

社区内容

Java 2 Standard Edition
社区公告
暂无公告