tags:

views:

208

answers:

9

This may sound really basic. But I'm brand new to Java. With the few initial hours of learning I've put in so far, I'm continuously perplexed by the redundancy in the syntax of a new object declaration:

TypeName a = new TypeName();

In particular,

String s = new String("abc");
Character c = new Character("A");

Why in the world would someone want to type the keyword TypeName (eg. String, Character, etc...) twice? I understand there are short-hands of:

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

But these are exceptions rather than rules. So can any one enlighten me please? Thx.

+5  A: 

With this syntax you can easily create an object of type X and assign it to a variable of type Y:

List<String> myList = new ArrayList<String>();
tangens
+16  A: 

Because sometimes you want to do something like:

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

or

// Cast a child class to its parent
MyParentClass mpc = new IneritedClassFromParent();

or

// Store and access a concrete implementation using its interface
ISomeInterface isi = new ConcreteInterfaceImplementation();

In other words, just because you declare a type to store doesn't always mean you want it initialized with a new instance of that class.

You may want to use a new instance of a child class when using inheritance or an Interface Implementation when using Interfaces.

Or sometimes you may want to explicitly force something to be null initially and fill it later.

Justin Niessner
However, this doesn't explain why you need to mention the type twice in the examples the OP gave. Type inference has been around for almost 100 years, i.e. longer than programming languages have and *certainly* longer than Java has, so I think the question why Java is missing a feature that has been basically standard since the 80s is still open.
Jörg W Mittag
I agree w/ Jorg W Mittag. In particular, I have a follow up question to the examples you showed here. Why can't someone just have `InheritedClassFromParent mpc = new InheritedClassFromParent()`? What is the benefit of declaring the variable in the parent class?
Zhang18
@Zhang18 - It's for the same reason you would use an interface. If the parent defines the members you need, it's better to use the more generic type. You're then free to change the underlying type without breaking dependent code. For example, you could change `MyParentClass mpc = new InheritedClassFromParent();` to `MyParentClass mpc = SomeOtherChild();` without breaking code that uses mpc whereas using concrete types...you could cause breaking changes.
Justin Niessner
That makes sense. thanks a lot!
Zhang18
A: 

That's because there is no implicit way to assign the value of a complex object.

When you do int a = 3; or double b = 2.5;, you can implicitly state the type on the right-hand side.

In OOP, you have to use a constructor which is why you have to do new TypeName(). This also gives you the ability to pass in parameters to set up the object.

Another reason is when you use interfaces. So you can do:

MyInterface blah = new InterfaceImplementation();
MyInterface bar = new AnotherInterfaceImplementation();

and even:

ParentClass foo = new DerivedClass();

This is because when working with interfaces you typically don't want to set the variable type to be the interface-implementation, but the interface itself. Otherwise there would be no way to specify which implementation to use.

Another useful thing is generics:

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

Java 7 will simplify this to

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

so that you don't have to type <SomeType> twice (this especially gets painful in Maps).

Vivin Paliath
A: 

When you will get to the class generics (extensions):

class a extends b

You will see that you can do something like this:

b=new a();

oneat
A: 

Well, a variable needs to have a type. And when you are creating instance of an object, you need to tell which type it should be. And of course these don't have to be the same. You can set a String to an Object variable, for instance. Of course you could have something like this to make things a bit easier:

var s = new TypeName();

That's how it has been done in C#. But I suppose in Java they have not seen a need for that.
I agree that Java is quite verbose by modern standards, but it also quite easy to read and there's not much syntactic sugar to confuse you.

Carlos
+1  A: 

Many good answers here as to why it's necessary. You're correct in that it often seems redundant. java has often been (not unfairly) criticized as a bit, er... verbose. There are a few shortcuts. e.g. for strings String s="Abc"(not actually a shortcut, it's a bit different, and better, in that you're not explicitly creating a new object). There will also be some reduction of the duplication in declarations in java 7 for generics.

Steve B.
A: 

There are strongly typed languages that support "type inference" (like Scala, for example). Java simply isn't one of them (although there will be some type inference of generic arguments in Java 7). In these languages, although the variable type isn't declared, the compiler can unambiguously infer it, and still detect type errors. For example (non-Java):

val str = "This is not a number!";
val x = str.intValue(); // Compiler error, because str is implicitly a String.

In Java, there will be many cases where you will assign a specific concrete type on the right to a more general type on the left. For example:

Set students = new TreeSet();

This is a good style, because your code will not depend on a specific implementation. If you need to switch implementations (for example, you need faster lookups from a hash-based Set), only the right-hand side of the initializer changes.

For this reason, it's especially important to declare public APIs using the correct abstractions, rather than concrete types.

erickson
+4  A: 

Why in the world would someone want to type the keyword TypeName (eg. String, Character, etc...) twice?

Because you're doing two things:

  • Declaring a variable of a certain type
  • Creating an object of a certain type

The two types are not necessarily the same, e.g.

Map m = new HashMap();

You are probably used to "dynamically typed" languages like PHP where variables do not have a type. The advantage you get with Java's static type declarations is that a lot of programming errors are caught by the compiler (even, in a modern IDE, while you are typing). For example, if you make a simple mistake:

m.siez();

The compiler will immediately alert you to the fact that there is something wrong with your program - and it can do that only because it knows that the declared type Map does not have a method siez().

Some modern statically typed languages like C# and Scala use type inference to give you a "best of both worlds" where you can omit the type declaration and the compiler will assume that it's the same as the type of the object you are assigning to it. However, such languages always allow explicit type declarations because type inference is not always possible or desirables (such as in the example above where the variable is supposed to use the interface rather than the concrete class).

Michael Borgwardt
+2  A: 

This is not at all redundant. There are two steps to utilize a variable :

  1. declaration : this step tells the VM what will be the static footprint of the variable. For instance : Object a; will have only the footprint declared in the class Object visible, while Integer b; will have all footprint declared in the Integer class and all inherited parent classes, up to Object visible. This is for the static part.

  2. instanciation : this step tells the VM what will be the dynamic footprint of the variable. For instance : List<String> c = new LinkedList<String>();, then c.put("foo"); will use the LinkedList's implementation of the put() method, even if what is visible is List::put(). Sometimes, you will require that kind of declaration/instanciation, but will need to override to access a very specific method not visible with the static footprint. For example, let's consider a method declared as public void method1(Object obj) and you know that the obj instance is actually an Integer, thus you will specifically use the dynamic footprint by casting the object into it: int value = ((Integer) obj).intValue();

Now, as for the String a = "A"; part. Java has made shorthand writing of the "primitive" classes available for simplicity. More specifically, since Java 1.5, you can do :

Integer n1 = 1;
Integer n2 = new Integer(1);  // same thing
int n3 = n2;

And all works. But what's the difference? Consider this piece of code :

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));

will output

a:65 = b:65 == false
b:65 = c:65 == false
c:65 = d:65 == true

Why? Because the JVM is trying to reuse memory as much as possible, and since a and b are creating new instances of a String, they are not sharing the same memory space. However, c and d are using constant string values (this is a compiler optimization) and therefore are pointing to the exact same String object.

Yanick Rochon