为什么在Java实例化期间将类命名为两次?

时间:2009-12-24 03:59:25

标签: java syntax types

实例化对象时,为什么要指定两次类?

OddEven number = new OddEven();

为什么你不能说number = new OddEven();?当我声明一个字符串时,我只说String一次:

String str = "abc";

实际上,我的问题不是“为什么你这样做” - 显然,你这样做是因为你必须 - 但是,为什么创作者选择让Java语法像这样工作呢?

我的想法是:

  1. Java在低级别运行的方式有一些基础,需要输入两次名称,或者
  2. 创作者可以自由选择这样做以保持语法的某些方面一致 - 首先声明类型?或者它更像是它的前辈?

12 个答案:

答案 0 :(得分:43)

因为你可以这样做:

Superclass x = new Subclass();

引用的类型可以是要声明的实际对象的超类,因此您需要同时指定它们。例如,你可以这样做:

List<String> stringList = new ArrayList<String>();

您的程序与实现List的对象交互,而您不关心实现。

答案 1 :(得分:5)

看似冗余的类型名称的原因是您正在执行两个单独的操作,每个操作都要求您指定一个类型。

在左侧,您要声明具有特定类型的变量(存储位置)。在右侧,您将创建具有特定类型的新对象。中间的'='会引用您创建的新对象,并将其放置在您创建的存储位置中。

每侧的类型不必相同。例如,这是合法代码:

Object number = new OddEven();

关键字String仅在第二个示例中显示一次的原因是String类型隐含在右侧,因为“xxx”是String常量。它只是简写:

String string = new String("xxx");

答案 2 :(得分:4)

当你写:

OddEven number = new OddEven();

您实际上做了两件事:1)您声明了number 类型的变量OddEven 2)您为类{{1}的新实例分配了引用}}。但是因为变量可以包含类型的任何子类型,所以编写OddEven对于编译器来说不足以知道number = new OddEven();变量的实际类型。所以,你必须声明它。 Java是一种强类型语言,这意味着每个变量和每个表达式都具有在编译时已知的类型。您可能希望阅读Java语言规范(JLS)的全部Chapter 4. Types, Values, and Variables以了解更多信息。

现在,当你写:

number

事情有点不同。用双引号括起来的字符String str = "abc"; 在这里被称为字符串文字,它已经是对"abc"实例的引用,并且总是引用类{{{}}的同一个实例。 1}}。引用JLS的3.10.5 String Literals部分:

  

每个字符串文字都是一个参考   (§4.3)到一个实例   上课的§4.3.1§12.5)   String (§4.3.3)String   对象具有常量值。串   文字 - 或者更一般地说,字符串   这是常数的值   表达式(§15.28) - 是   “实习”以便分享独特   实例,使用该方法   String

因此,String肯定不会转换为String.intern,这绝对不等同于我在一些评论和答案中所读到的。运行以下类:

String str = "abc";

生成以下输出:

String str = new String("abc");

并证明public class Test { public static void main(String[] args) { String one = "abc"; String two = "abc"; String abc = new String("abc"); System.out.println(one == two); System.out.println(one == abc); } } true false 是对同一个实例的引用,但one是对另一个实例的引用(即额外的不必要对象具有已创建)。

实际上,使用two是构造新字符串的低效方法,并且只应用于强制子字符串复制到新的基础字符数组,如

abc

答案 3 :(得分:0)

第一个OddEven是类型,第二个是实例。它不一定是OddEven,它可以是OddEven的任何子类。这并不意味着你输入了两次。任何IDE都有代码模板,您只需键入一次名称。

答案 4 :(得分:0)

第一个声明是你想在你拥有的作用域中使用的变量类型,在这种情况下它是OddEven,第二个声明是用于实例化(在这种情况下初始化)引用的构造函数。 p>

你可以说INumberInstance = new OddEven(),其中INumberInstance是OddEven可以被强制转换的类(例如,像OddEven的超级)。

答案 5 :(得分:0)

在java中创建新对象的方法是:

Class_name reference_variable = new Class_name(param_if_any);

字符串类是一个例外

您可以创建一个新的字符串对象

String s = "abc";

String s = new String("abc");

答案 6 :(得分:0)

除了Jim所说的,Java是一种静态类型的语言。这意味着每个varable都有一个在编译时就知道的类型。

例如:

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

public class B
{
    public void foo() { }
}

public class Main
{
    public static void main(final String[] argv)
    {
        A a = new A();
        B b = new B();

        a.foo();
        b.foo();
    }
}

编译器查看“a.foo()”和“b.foo()”并检查a是否为A类,A有一个名为“foo”的方法,该方法不带参数。编译器对“b.foo()”执行相同的操作。

如果你能写这样的主要内容:

public class Main
{
    public static void main(final String[] argv)
    {
        a = new A(); // in Java you would really do Object a = new A();
        b = new B(); // in Java you would really do Object b = new B();

        a.foo();
        b.foo();
    }
}

然后编译器无法进行验证,而且必须在运行时进行。

答案 7 :(得分:0)

将'OddEven number'视为定义Object和'new OddEven();'填充对象。

我不打算详细介绍超类和子类,因为其他人已经解释过了。

答案 8 :(得分:0)

Java的设计者没有拥有来使语法冗余。 Scala是另一种使用JVM的语言,它也是静态类型的。 Scala使用类型推理来减少冗长。例如,这是一个名为MyPair的MyPair类型变量的声明。 MyPair将两个变量相互关联。它是一个泛型类,因此您可以指定第一个变量的类型为Int,第二个变量的类型为String:

var x: MyPair[Int, String] = new MyPair[Int, String](1, "scala")

Scala类型推理允许您删除冗余类型声明:

var x = new MyPair[Int, String](1, "scala")

Scala甚至根据构造函数参数推断类型,因此您可以这样写:

var x = new MyPair(1, "scala")

答案 9 :(得分:0)

当您说String name = "foo"时,内部Java编译器会创建一个值为“foo”的String对象,并将其引用分配给name变量。因此,这里不是创建一个新的String对象,而是分配对另一个String对象的引用。

顺便说一下,编译器总是为我们创建“foo”。它首先在字符串池中查找,如果它不存在,则只创建“foo”。否则,Compiler从String池返回一个引用。这是Java编译器在内部执行的一些优化。

String name = "foo"OddEvenNumber oddEven = anotherOddEvenObject;

相似

答案 10 :(得分:0)

考虑以下示例,

我们可以按如下方式指定对象类型,

List<String> abc;

在method1()中,如果你想使用最适合它的数组列表,那么我们可以像下面一样实例化,

abc = new ArrayList<String>();

在method2()中,如果你想使用最适合它的链接数组列表,那么我们可以像下面那样实例化,

abc = new LinkedList<String>();

因此,我们的想法是,我们可以指定“SuperClass”的类型,并在适当的操作中动态地使用适合不同要求的子类(如“LinkedList”和“ArrayList”)进行实例化。

答案 11 :(得分:0)

数组示例:

声明和初始化——当你知道数组的长度时:

int[] numberArray = new int[10];

声明然后初始化 - 当您还不知道数组的长度并且可能从方法或用户输入中获取时

int[] numberArray;
int length = 10; // let’s say we got this from the user
numberArray = new int[length];

仅初始化 - 当您不需要重用时:

return new int[10];