栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

动态构建匿名类混乱

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

动态构建匿名类混乱

这是一个非常简单的问题,答案很复杂。在我尝试解释时,请多多包涵。

查看引发异常的源代码

Class
(我不确定为什么您的堆栈跟踪未在中给出行号
Class
):

try{  Class[] empty = {};  final Constructor<T> c = getConstructor0(empty, Member.DECLARED);  // removed some pre that was not relevant}catch (NoSuchMethodException e){  throw new InstantiationException(getName());}

你看到那

NoSuchMethodException
被换成
InstantiationException
。这意味着对于的类类型,没有no-
arg构造函数
object2

首先,什么是类型

object2
?用代码

System.out.println("object2 class: " + object2.getClass());

我们看到了

object2类:junk.NewMain $ 1类

这是正确的(我在类NewMain的垃圾包中运行示例代码)。

那是什么

junk.NewMain$1
呢?

Class obj2Class = object2.getClass();try{  Constructor[] ctors = obj2Class.getDeclaredConstructors();  for (Constructor cc : ctors)  {    System.out.println("my ctor is " + cc.toString());  }}catch (Exception ex){  ex.printStackTrace();}

这给了我们

我的ctor是垃圾.NewMain $ 1(java.util.Calendar)

因此,您的匿名类正在寻找

Calendar
要传递的a。然后,它将为您工作:

Object newObj = ctors[0].newInstance(Calendar.getInstance());

如果您有这样的事情:

final String finalString = "I'm final :)";final Integer finalInteger = new Integer(30);final Calendar calendar = Calendar.getInstance();Object object2 = new Object(){  {    System.out.println("Instance initializing block");    System.out.println(finalString);    System.out.println("My integer is " + finalInteger);    System.out.println(calendar.getTime().toString());  }  private void hiddenMethod()  {    System.out.println("Use reflection to find me :)");  }};

那么我的呼叫

newInstance
将无法工作,因为ctor中没有足够的参数,因为现在它需要:

我的ctor是垃圾邮件.NewMain $ 1(java.lang.Integer,java.util.Calendar)

如果我然后实例化

Object newObj = ctors[0].newInstance(new Integer(25), Calendar.getInstance());

使用调试器进行的内部窥视显示

finalInteger
为25,而不是最终值30。

事情有些复杂,因为您是在静态环境中执行上述所有操作。如果您将上面的所有代码都移到这样的非静态方法中(请记住,我的类是junk.NewMain):

public static void main(String[] args){  NewMain nm = new NewMain();  nm.doIt();}public void doIt(){  final String finalString = "I'm final :)";  // etc etc}

您会发现内部类的ctor现在(删除我添加的Integer引用):

我的ctor是垃圾.NewMain $ 1(junk.NewMain,java.util.Calendar)

在Java语言规范,部分15.9.3这样解释道:

如果C是一个匿名类,而C的直接超类S是一个内部类,则:

  • 如果S是局部类,并且S在静态上下文中出现,则参数列表中的参数(如果有)是构造函数的参数(按它们在表达式中出现的顺序)。
  • 否则,与S紧密相关的i实例是构造函数的第一个参数,其后是类实例创建表达式的参数列表中的参数(如果有的话),它们按照在表达式中出现的顺序排列。

为什么匿名构造函数完全接受参数?

由于您无法为匿名内部类创建构造函数,因此实例初始值设定项块可达到此目的(请记住,您只有该匿名内部类的一个实例)。VM不了解内部类,因为编译器将所有内容分离为单个类(例如junk.NewMain
$ 1)。该类的ctor包含实例初始化程序的内容。

JLS
15.9.5.1匿名构造函数对此进行了说明:

…匿名构造函数对声明C的类实例创建表达式的每个实际参数都有一个形式参数。

您的实例初始化程序具有对

Calendar
对象的引用。除了通过构造函数之外,编译器还如何将运行时值获取到您的内部类(作为VM的类创建)中?

最后(是),最后一个问题的答案。为什么构造函数不需要

String
?JLS
3.10.5的最后一点说明:

由常量表达式计算的字符串在编译时进行计算,然后将其视为文字。

换句话说,您的

String
值在编译时是已知的,因为它是文字,因此它不必成为匿名构造函数的一部分。为了证明是这种情况,我们将测试JLS
3.10.5中的下一条语句:

在运行时通过串联计算的字符串是新创建的,因此是不同的。

从而更改您的代码:

String str1 = "I'm";String str2 = " final!";final String finalString = str1 + str2

并且您会发现您的ctor现在(在非静态上下文中):

我的ctor是垃圾.NewMain $ 1(junk.NewMain,java.lang.String,java.util.Calendar)

ew 我希望这是有道理的,对您有所帮助。我学到了很多,这是肯定的!



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/438282.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号