Java对象创建语法效率?

Java对象创建语法效率?,java,syntax,Java,Syntax,这听起来很基本。但我对Java是全新的。到目前为止,我只花了几个小时的时间学习,我一直对新对象声明语法中的冗余感到困惑: TypeName a = new TypeName(); 特别是, String s = new String("abc"); Character c = new Character("A"); 究竟为什么有人要键入关键字TypeName(例如String,Character,等等)两次?据我所知,有以下几种情况: String s = "abc"; char c = "

这听起来很基本。但我对Java是全新的。到目前为止,我只花了几个小时的时间学习,我一直对新对象声明语法中的冗余感到困惑:

TypeName a = new TypeName();
特别是,

String s = new String("abc");
Character c = new Character("A");
究竟为什么有人要键入关键字
TypeName
(例如
String
Character
,等等)两次?据我所知,有以下几种情况:

String s = "abc";
char c = "A";

但这些都是例外,而不是规则。有谁能给我点化一下吗?Thx.

使用此语法,您可以轻松创建
X
类型的对象,并将其分配给
Y
类型的变量:

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

因为有时候你想做以下事情:

// Explicitly force my object to be null
String s = null;

换句话说,仅仅因为声明要存储的类型并不总是意味着您希望使用该类的新实例对其进行初始化

您可能希望在使用继承时使用子类的新实例,或者在使用接口时使用接口实现


或者,有时您可能希望先显式地强制某个对象为null,然后再填充它。

这是因为没有隐式方法来指定复杂对象的值

当你做
inta=3
双b=2.5,您可以在右侧隐式声明类型

在OOP中,必须使用构造函数,这就是为什么必须执行
newtypename()
。这还使您能够传入参数以设置对象

另一个原因是当您使用接口时。因此,您可以:

MyInterface blah = new InterfaceImplementation();
MyInterface bar = new AnotherInterfaceImplementation();
甚至:

ParentClass foo = new DerivedClass();
这是因为在处理接口时,您通常不希望将变量类型设置为接口实现,而希望将接口本身设置为变量类型。否则,将无法指定要使用哪个实现

另一个有用的东西是泛型:

List<SomeType> myList = new ArrayList<SomeType>();
List myList=new ArrayList();
Java7将把这简化为

List<SomeType> myList = new ArrayList<>();
List myList=new ArrayList();

这样您就不必输入两次
(这在映射中尤其令人痛苦)。

当您进入类泛型(扩展)时:

您将看到您可以执行以下操作:

b=new a();

一个变量需要有一个类型。当您创建一个对象的实例时,您需要告诉它应该是哪种类型。当然,这些不必是相同的。例如,可以将字符串设置为对象变量。当然,你可以用这样的方法让事情变得更简单:

var s = new TypeName();
在C#中就是这样做的。但我想在Java中,他们没有看到这样做的必要性。

我同意,按照现代标准,Java非常冗长,但它也非常容易阅读,而且没有太多的语法糖分让您感到困惑。

这里有很多关于为什么需要它的好答案。你说得对,它常常显得多余。java经常被(并非不公平地)批评为有点,呃。。。冗长的。有一些捷径。e、 g.对于字符串
String s=“Abc”
(实际上不是一个快捷方式,它有点不同,而且更好,因为您没有显式地创建新对象)。java 7中泛型声明的重复也会有所减少。

有支持“类型推断”的强类型语言(例如Scala)。Java并不是其中之一(尽管在Java7中会有一些泛型参数的类型推断)。在这些语言中,虽然没有声明变量类型,但编译器可以毫不含糊地推断它,并且仍然可以检测类型错误。例如(非Java):

在Java中,在许多情况下,您会将右侧的特定具体类型分配给左侧的更一般类型。例如:

Set students = new TreeSet();
这是一种很好的样式,因为您的代码不依赖于特定的实现。如果需要切换实现(例如,需要从基于散列的
集合
更快地查找),则只有初始值设定项的右侧会发生更改

因此,使用正确的抽象而不是具体类型来声明公共API尤为重要

到底为什么会有人想要 键入关键字TypeName(例如字符串、, 人物等等)两次

因为你在做两件事:

  • 声明某一类型的变量
  • 创建特定类型的对象
这两种类型不一定相同,例如

Map m = new HashMap();
您可能已经习惯了像PHP这样的“动态类型”语言,其中变量没有类型。Java的静态类型声明的优点是,编译器会捕获许多编程错误(即使在现代IDE中,当您键入时)。例如,如果您犯了一个简单的错误:

m.siez();
编译器会立即提醒您程序有问题,这只是因为它知道声明的类型
Map
没有方法
siez()


一些现代的静态类型语言,如C#和Scala,会给你一个“两全其美”的结果,你可以省略类型声明,编译器会假设它与你分配给它的对象的类型相同。但是,这种语言总是允许显式类型声明,因为类型推断并不总是可能的或可取的(例如在上面的示例中,变量应该使用接口而不是具体的类)。

这一点都不是多余的。使用变量有两个步骤:

  • 声明:此步骤告诉VM变量的静态足迹。例如:
    对象a
    将只有在类
    对象中声明的封装外形可见,而
    整数b
    将在
    Integer
    类和所有继承的父类(u)中声明所有封装外形
    val str = "This is not a number!";
    val x = str.intValue(); // Compiler error, because str is implicitly a String.
    
    Set students = new TreeSet();
    
    Map m = new HashMap();
    
    m.siez();
    
    Integer n1 = 1;
    Integer n2 = new Integer(1);  // same thing
    int n3 = n2;
    
    String a = new String("A");
    String b = new String("A");
    String c = "A";
    String d = "A";
    
    System.out.println("a:" + a.hashCode() + " = b:" + b.hashCode() + " == " + (a == b));
    System.out.println("b:" + b.hashCode() + " = c:" + c.hashCode() + " == " + (b == c));
    System.out.println("c:" + c.hashCode() + " = d:" + d.hashCode() + " == " + (c == d));
    
    a:65 = b:65 == false
    b:65 = c:65 == false
    c:65 = d:65 == true