为什么MyClass.class存在于java和MyField.field中不存在?

时间:2010-12-19 23:58:07

标签: java syntax

让我说我有:

class A {
    Integer b;
    void c() {}
}

为什么Java具有以下语法:A.class,并且没有这样的语法:b.fieldc.method

对于类文字有什么用处吗?

4 个答案:

答案 0 :(得分:6)

A.class语法看起来像字段访问,但实际上它是在上下文中的特殊语法规则的结果,其中不允许正常的字段访问;即A是一个类名。

以下是JLS中的语法:

Primary:
  ParExpression
        NonWildcardTypeArguments (
            ExplicitGenericInvocationSuffix | this Arguments)
  this [Arguments]
  super SuperSuffix
  Literal
  new Creator
  Identifier { . Identifier }[ IdentifierSuffix]
  BasicType {[]} .class
  void.class

请注意,fieldmethod没有等效语法。

(旁白:语法允许b.field,但JLS声明b.field表示名为“field”的字段的内容......如果不存在此类字段,则为编译错误。 {I}同样适用c.method,并且必须存在字段 c。因此,这些结构都不代表您希望它们的意思......)

为什么存在此限制?好吧,我想因为Java语言设计者没有看到需要混淆语言语法/语义来支持方便地访问Field和Method对象。 (有关更改Java的一些问题,请参阅下面的 * 。)

Java反射的设计并不容易使用。在Java中,最好在可能的情况下使用静态类型。它更有效,更不易碎。将反射的使用限制在静态类型不起作用的少数情况下。

如果你习惯于编程到一切都是动态的语言,这可能会让你感到烦恼。但是最好不要与它作斗争。

  

对于类文字有什么用处吗?

我想,他们支持这个课程的主要原因是它避免了每次你需要反复做某事时调用Class.forName("some horrible string")的程序。你可以称之为妥协/小小的让步,以便于反思。

我想另一个原因是<type>.class语法没有破坏任何内容,因为class已经是关键字。 (IIRC,Java 1.1中添加了语法。)


*如果语言设计师试图改进对此类事物的支持,那就会出现各种各样的问题:

  • 这些变化会给语言带来歧义,使编译和其他依赖于解析器的任务变得更加困难。
  • 无论methodfield是否已转换为关键字,这些更改无疑会破坏现有代码。
  • 您不能将b.field视为隐式对象属性,因为它不适用于对象。相反,b.field需要应用于字段/属性标识符。但除非我们将field保留为保留字,否则我们会遇到异常情况,您可以创建一个名为field的字段,但不能在Java源代码中引用它。
  • 对于c.method,存在可能存在多个名为c的可见方法的问题。第二个问题是,如果有一个名为c的字段和一个名为c的方法,那么c.method 可能是对字段的引用method字段引用的对象上调用c

答案 1 :(得分:1)

我认为您希望此信息用于记录等。最不幸的是,虽然编译器可以完全访问这些信息,但是这些信息不可用。

具有一点创造力的人可以使用反射获取信息。我不能提供任何例子,因为没有什么要求可以遵循,我不想完全浪费我的时间:)

答案 2 :(得分:-1)

我不确定我是否完全理解你的问题。您不清楚A.class语法的含义。您可以使用Reflections API通过以下方式从给定对象获取类:

A a = new A()
Class c = a.getClass()

Class c = A.class;

然后使用c做一些事情。

反射API主要用于调试工具,因为Java支持多态,你总是可以在运行时知道对象的实际类,所以开发了反射API以帮助调试问题(给定的子类,当预期超级行为等)。

没有b.field或c.method的原因是因为它们在Java中没有任何意义和功能目的。您无法创建对方法的引用,并且字段在运行时无法更改其类型,这些内容在编译时设置。 Java是一种非常严格的语言,没有太多的运行时灵活性(除非你使用动态类加载,但即使这样你需要有关加载对象的一些信息)。如果您来自Ruby或Javascript之类的灵活语言,那么您可能会发现Java对您的品味有一点控制。

但是,让编译器帮助您解决代码中的潜在问题非常有用。

答案 3 :(得分:-2)

在java中,并非所有东西都是对象。

你可以拥有

A a = new A()
Class cls = a.getClass()

或直接来自班级

A.class

通过这个,您可以获得该课程的对象。

通过反射,您可以获得方法和字段,但这变得复杂。因为不是一切都是对象。这不是像Scala或Ruby这样的语言,其中一切都是对象。 反思教程:http://download.oracle.com/javase/tutorial/reflect/index.html

BTW:你没有指定public / private / protected,所以默认情况下你的东西被声明为package private。这是包级别保护访问http://download.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html