当前位置: 首页 > 知识库问答 >
问题:

班getDeclaredMethods()反映特殊行为

伏砚
2023-03-14

我有一个抽象类a,类B是扩展a的具体类。

给B班打电话。getDeclaredMethods()除了返回类B的方法签名外,还返回类A的方法签名,但是JAVA文档在getDeclaredMethods()上说了一些不同的东西。

这包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法

因此,从上面的文档中,我希望从抽象父类继承的方法foo()不应该从getDeclaredMethods()调用返回,但我得到的方法foo()是从抽象父类继承的,它是从getDeclaredMethods()调用返回的。

import java.lang.reflect.*;

public class B extends A {
    public static void main(String[] args) throws Exception {
        Method[] methods = B.class.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i]);
        }
    }
}


abstract class A {
    public void foo() {
    }
}

谁能给我解释一下这种行为吗。

共有3个答案

冷夜洛
2023-03-14

奇怪之处不在getDeclaredMethods()——它在B的类文件中,其主体只调用super。foo()

我不完全理解它,但它似乎与foo()是在包私有超类中声明的公共方法有关。

一些测试用例:

  • Apackage private,foopublic(根据问题):方法在B
  • Apackage private,foopackage private:方法未在B
  • Apublicfoopublic:方法未在B
  • Apublic,foopackage private:在B

我怀疑这个想法是不同包中的第三个类不能“看到”A,但A. foo()仍然是public,所以它应该(?)可以通过B访问。为了使其可访问,B需要“重新声明”它。

我不清楚这是否真的是正确的——这个(?)在上面JLS 6.6.1规定(重点):

引用类型的成员(类、接口、字段或方法)或类类型的构造函数,只有在该类型可访问且声明该成员或构造函数允许访问时才可访问

但该代码可以在不同的包中使用:

B b = new B();
b.foo();
卞云瀚
2023-03-14

出于其他答案列出的原因,有时编译器必须向类文件中添加一些棘手的代码;这可以是字段、构造函数或方法的形式。但是,它总是将这些字段标记为synthetic。这是它添加的实际修改器,您可以检查该方法是否与该方法合成:

method.isSynthetic()

因此,无论何时获得所有方法,都要使用此方法筛选列表,以仅选择在源代码中实际声明的方法;)

合成代码的其他示例包括:自动添加的默认构造函数,如果您有一个非静态内部类,则对字段中的外部类的引用。

乐正光誉
2023-03-14

之所以会出现这种情况,是因为超类具有包级别的访问权限。如果将classA的访问修饰符更改为public(需要将其放入自己的文件中),则B.class中的额外方法。getDeclaredMethods()将消失。

(还要注意,在类A上修改的abstract是一种转移注意力的方法:当类A不是抽象时,也会发生同样的事情。)

这是Java编译器中针对反射错误的一个变通方法:尽管foo是一个公共方法,但它是在包范围的类a定义的。您可以对类B进行反思,找到方法,尝试使用反射调用它,结果得到一个IllegalAccessException

编译器将在类B中生成一个桥接方法,这样您就可以正确地反射调用方法foo

如果在AAfinal方法中使用foo方法,这是最好的证明,这使得无法修复此反射错误(无法覆盖该方法)

AB在包abc中,类C在包def中。类C尝试在类B上反射调用方法foo,该方法是公共的,但失败了,因为它是在非公共类A中定义的。

线程“main”java中出现异常。lang.IllegalAccessException:Class def。C无法访问abc类的成员。A带有修饰语“公开决赛”

package abc;

public class B extends A {
}

class A {
    public final void foo() {
    }

}
package def;

import java.lang.reflect.Method;

import abc.B;

public class C {
    public static void main(String[] args) throws Exception {
        Method m = B.class.getMethod("foo");
        m.invoke(new B());
    }
}

只需从方法foo中删除final关键字即可解决问题,因为编译器随后会在类B中插入合成桥方法。

本错误报告对此进行了解释:

http://bugs.java.com/view_bug.do?bug_id=6342411

以下程序在运行时失败并出现此错误:

Exception in thread "main" java.lang.IllegalAccessException: Class refl.ClientTest can not access a member of class refl.a.Base with
modifiers "public"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.reflect.Method.invoke(Method.java:578)
        at refl.ClientTest.main(ClientTest.java:9)
========== test/refl/a/Base.java ========== 
     1  package refl.a; 
     2   
     3  class Base { 
     4      public void f() { 
     5          System.out.println("Hello, world!"); 
     6      } 
     7  } 
========== test/refl/a/Pub.java ========== 
     1  package refl.a; 
     2   
     3  public class Pub extends Base {} 
========== test/refl/ClientTest.java ========== 
     1  package refl; 
     2  import refl.a.*; 
     3  import java.lang.reflect.*; 
     4   
     5  public class ClientTest { 
     6      public static void main(String[] args) throws Exception { 
     7          Pub p = new Pub(); 
     8          Method m = Pub.class.getMethod("f"); 
     9          m.invoke(p); 
    10      } 
    11  }

该提议是在这些非常罕见的情况下添加桥接方法,以修复反射中的问题,而无需其他预见的修复或解决方法。具体来说,当公共方法从非公共类继承到公共类时,我们将生成一个桥接方法。

 类似资料:
  • 问题内容: 有人可以详细说明一下,并解释两种方法之间的区别,以及何时/为什么要在另一种方法上使用 问题答案: 包括 由类本身 声明 的 所有方法,而仅返回公共方法,还返回从基类(此处是from )继承的方法。 在和中的Javadocs中阅读有关它的更多信息。

  • 在Solidity的类型系统里面有一些类型有一些在其它语言中没有的语法。其中之一就是函数类型。但依然,使用var时,可以把函数类型作为本地变量。 contract FunctionSelector { function select(bool useB, uint x) returns (uint z) { var f = a; if (useB) f = b; ret

  • 这是正确的吗? 我可以找到一个相关的问题,但它是有参数的,我不能在没有params的情况下转换它。

  • 特殊包中可用的功能是通用功能,它遵循广播和自动数组循环。 下面来看看一些最常用的特殊函数功能 - 立方根函数 指数函数 相对误差指数函数 对数和指数函数 兰伯特函数 排列和组合函数 伽马函数 下面来简单地了解这些函数。 立方根函数 这个立方根函数的语法是 - 。 这将获取的基于元素的立方体根。 参考下面的一个例子 - 执行上面示例代码,得到以下结果 - 指数函数 指数函数的语法是 - 。 这将计算

  • 关于字符集和替代字形 除键盘上可看到的字符之外,字体中还包括许多字符。根据字体的不同,这些字符可能包括连字、分数字、花饰字、装饰字、序数字、标题和文体替代字、上标和下标字符、变高数字和全高数字。字形是特殊形式的字符。例如,在某些字体中,大写字母 A 有几种形式可用,如花饰字或小型大写字母。 插入替代字形的方式有两种: 可以使用 “字形 ”面板来查看和插入任何字体中的字形。 可以使用 “OpenTy

  • 一些字符在 XML 中有特殊的含义,只能够通过其实体名称输入 字符 写法 缩写涵义 < &lt; less than > &gt; greater than & &amp; ampersand " &quot; quote ' &apos; apostrophe 空格 &nbsp; none-break space 通常需要使用实体输入的字符包括<、&、空格   XML 会将任意数量的空格解析为一